2 * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
3 * This code handles requests generated by operations on /dev/uds
5 * The entry points into this file are...
7 * uds_open: handles the open(2) syscall on /dev/uds
8 * uds_close: handles the close(2) syscall on /dev/uds
9 * uds_select: handles the select(2) syscall on /dev/uds
10 * uds_read: handles the read(2) syscall on /dev/uds
11 * uds_write: handles the write(2) syscall on /dev/uds
12 * uds_ioctl: handles the ioctl(2) syscall on /dev/uds
13 * uds_status: handles status requests.
14 * uds_cancel: handles cancelled syscalls.
18 * table.c, uds.c, uds.h
22 * The interface to unix domain sockets is similar to the
23 * the interface to network sockets. There is a character
24 * device (/dev/uds) that uses STYLE_CLONE and this server
25 * is a 'driver' for that device.
35 static int uds_perform_read(int minor
, endpoint_t m_source
, size_t
37 static int uds_perform_write(int minor
, endpoint_t m_source
, size_t
40 int uds_open(message
*dev_m_in
, message
*dev_m_out
)
42 message fs_m_in
, fs_m_out
;
48 static int call_count
= 0;
49 printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in
),
51 printf("Endpoint: 0x%x\n", dev_m_in
->USER_ENDPT
);
55 * Find a slot in the descriptor table for the new descriptor.
56 * The index of the descriptor in the table will be returned.
57 * Subsequent calls to read/write/close/ioctl/etc will use this
58 * minor number. The minor number must be different from the
59 * the /dev/uds device's minor number (currently 0).
62 minor
= -1; /* to trap error */
64 for (i
= 1; i
< NR_FDS
; i
++) {
65 if (uds_fd_table
[i
].state
== UDS_FREE
) {
73 /* descriptor table full */
74 uds_set_reply(dev_m_out
, DEV_OPEN_REPL
, dev_m_in
->USER_ENDPT
,
75 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, ENFILE
);
80 * We found a slot in uds_fd_table, now initialize the descriptor
83 /* mark this one as 'in use' so that it doesn't get assigned to
86 uds_fd_table
[minor
].state
= UDS_INUSE
;
88 /* track the system call we are performing in case it gets cancelled */
89 uds_fd_table
[minor
].call_nr
= dev_m_in
->m_type
;
90 uds_fd_table
[minor
].ioctl
= 0;
91 uds_fd_table
[minor
].syscall_done
= 0;
93 /* set the socket owner */
94 uds_fd_table
[minor
].owner
= dev_m_in
->USER_ENDPT
;
95 uds_fd_table
[minor
].endpoint
= dev_m_in
->USER_ENDPT
;
97 /* setup select(2) framework */
98 uds_fd_table
[minor
].selecting
= 0;
99 uds_fd_table
[minor
].select_proc
= 0;
100 uds_fd_table
[minor
].sel_ops_in
= 0;
101 uds_fd_table
[minor
].sel_ops_out
= 0;
102 uds_fd_table
[minor
].status_updated
= 0;
104 /* initialize the data pointer (pos) to the start of the PIPE */
105 uds_fd_table
[minor
].pos
= 0;
107 /* the PIPE is initially empty */
108 uds_fd_table
[minor
].size
= 0;
110 /* the default for a new socket is to allow reading and writing.
111 * shutdown(2) will remove one or both flags.
113 uds_fd_table
[minor
].mode
= S_IRUSR
|S_IWUSR
;
115 /* In libc socket(2) sets this to the actual value later with the
116 * NWIOSUDSTYPE ioctl().
118 uds_fd_table
[minor
].type
= -1;
120 /* Clear the backlog by setting each entry to -1 */
121 for (i
= 0; i
< UDS_SOMAXCONN
; i
++) {
122 /* initially no connections are pending */
123 uds_fd_table
[minor
].backlog
[i
] = -1;
126 memset(&uds_fd_table
[minor
].ancillary_data
, '\0', sizeof(struct
128 for (i
= 0; i
< OPEN_MAX
; i
++) {
129 uds_fd_table
[minor
].ancillary_data
.fds
[i
] = -1;
132 /* default the size to UDS_SOMAXCONN */
133 uds_fd_table
[minor
].backlog_size
= UDS_SOMAXCONN
;
135 /* the socket isn't listening for incoming connections until
136 * listen(2) is called
138 uds_fd_table
[minor
].listening
= 0;
140 /* initially the socket is not connected to a peer */
141 uds_fd_table
[minor
].peer
= -1;
143 /* there isn't a child waiting to be accept(2)'d */
144 uds_fd_table
[minor
].child
= -1;
146 /* initially the socket is not bound or listening on an address */
147 memset(&(uds_fd_table
[minor
].addr
), '\0', sizeof(struct sockaddr_un
));
148 memset(&(uds_fd_table
[minor
].source
), '\0', sizeof(struct sockaddr_un
));
149 memset(&(uds_fd_table
[minor
].target
), '\0', sizeof(struct sockaddr_un
));
151 /* Initially the socket isn't suspended. */
152 uds_fd_table
[minor
].suspended
= UDS_NOT_SUSPENDED
;
154 /* and the socket doesn't have an I/O grant initially */
155 uds_fd_table
[minor
].io_gr
= (cp_grant_id_t
) 0;
157 /* since there is no I/O grant it effectively has no size either */
158 uds_fd_table
[minor
].io_gr_size
= 0;
160 /* The process isn't suspended so we don't flag it as revivable */
161 uds_fd_table
[minor
].ready_to_revive
= 0;
163 /* get the effective user id and effective group id from the endpoint */
164 /* this is needed in the REQ_NEWNODE request to PFS. */
165 rc
= getnucred(uds_fd_table
[minor
].endpoint
, &ucred
);
167 /* roll back the changes we made to the descriptor */
168 memset(&(uds_fd_table
[minor
]), '\0', sizeof(uds_fd_t
));
170 /* likely error: invalid endpoint / proc doesn't exist */
171 uds_set_reply(dev_m_out
, DEV_OPEN_REPL
, dev_m_in
->USER_ENDPT
,
172 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, errno
);
176 /* Prepare Request to the FS side of PFS */
178 fs_m_in
.m_type
= REQ_NEWNODE
;
179 fs_m_in
.REQ_MODE
= I_NAMED_PIPE
;
180 fs_m_in
.REQ_DEV
= NO_DEV
;
181 fs_m_in
.REQ_UID
= ucred
.uid
;
182 fs_m_in
.REQ_GID
= ucred
.gid
;
184 /* Request a new inode on the pipe file system */
186 rc
= fs_newnode(&fs_m_in
, &fs_m_out
);
188 /* roll back the changes we made to the descriptor */
189 memset(&(uds_fd_table
[minor
]), '\0', sizeof(uds_fd_t
));
191 /* likely error: get_block() failed */
192 uds_set_reply(dev_m_out
, DEV_OPEN_REPL
, dev_m_in
->USER_ENDPT
,
193 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, rc
);
197 /* Process the response */
199 uds_fd_table
[minor
].inode_nr
= fs_m_out
.RES_INODE_NR
;
201 /* prepare the reply */
203 uds_fd_table
[minor
].syscall_done
= 1;
204 uds_set_reply(dev_m_out
, DEV_OPEN_REPL
, dev_m_in
->USER_ENDPT
,
205 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, minor
);
209 int uds_close(message
*dev_m_in
, message
*dev_m_out
)
212 message fs_m_in
, fs_m_out
;
216 static int call_count
= 0;
217 printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in
),
219 printf("Endpoint: 0x%x\n", dev_m_in
->USER_ENDPT
);
222 minor
= uds_minor(dev_m_in
);
224 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
225 /* attempted to close a socket that hasn't been opened --
226 * something is very wrong :(
228 uds_set_reply(dev_m_out
, DEV_CLOSE_REPL
, dev_m_in
->USER_ENDPT
,
229 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINVAL
);
233 /* no need to track the syscall in case of cancellation. close() is
234 * atomic and can't be cancelled. no need to update the endpoint here,
235 * we won't be needing it to kill the socket
238 /* if the socket is connected, disconnect it */
239 if (uds_fd_table
[minor
].peer
!= -1) {
241 /* set peer of this peer to -1 */
242 uds_fd_table
[uds_fd_table
[minor
].peer
].peer
= -1;
244 /* error to pass to peer */
245 uds_fd_table
[uds_fd_table
[minor
].peer
].err
= ECONNRESET
;
247 /* if peer was blocked on I/O revive peer */
248 if (uds_fd_table
[uds_fd_table
[minor
].peer
].suspended
) {
249 int peer
= uds_fd_table
[minor
].peer
;
251 uds_fd_table
[peer
].ready_to_revive
= 1;
252 uds_unsuspend(dev_m_in
->m_source
, peer
);
256 if (uds_fd_table
[minor
].ancillary_data
.nfiledes
> 0) {
257 clear_fds(minor
, &(uds_fd_table
[minor
].ancillary_data
));
260 /* Prepare Request to the FS side of PFS */
262 fs_m_in
.m_type
= REQ_PUTNODE
;
263 fs_m_in
.REQ_INODE_NR
= uds_fd_table
[minor
].inode_nr
;
264 fs_m_in
.REQ_COUNT
= 1;
266 /* set the socket back to its original UDS_FREE state */
267 memset(&(uds_fd_table
[minor
]), '\0', sizeof(uds_fd_t
));
269 /* Request the removal of the inode from the pipe file system */
271 rc
= fs_putnode(&fs_m_in
, &fs_m_out
);
273 perror("fs_putnode");
274 /* likely error: get_block() failed */
278 uds_set_reply(dev_m_out
, DEV_CLOSE_REPL
, dev_m_in
->USER_ENDPT
,
279 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, OK
);
283 int uds_select(message
*dev_m_in
, message
*dev_m_out
)
289 static int call_count
= 0;
290 printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in
),
292 printf("Endpoint: 0x%x\n", dev_m_in
->USER_ENDPT
);
295 minor
= uds_minor(dev_m_in
);
297 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
299 /* attempted to close a socket that hasn't been opened --
300 * something is very wrong :(
303 uds_sel_reply(dev_m_out
, DEV_SEL_REPL1
, minor
, EINVAL
);
307 /* setup select(2) framework */
308 uds_fd_table
[minor
].selecting
= 1;
309 uds_fd_table
[minor
].select_proc
= dev_m_in
->m_source
;
311 /* track the system call we are performing in case it gets cancelled */
312 uds_fd_table
[minor
].call_nr
= dev_m_in
->m_type
;
313 uds_fd_table
[minor
].ioctl
= 0;
314 uds_fd_table
[minor
].syscall_done
= 0;
316 /* Can't update the process endpoint here, no info. */
318 uds_fd_table
[minor
].sel_ops_in
= dev_m_in
->USER_ENDPT
;
319 uds_fd_table
[minor
].sel_ops_out
= 0;
321 /* check if there is data available to read */
322 bytes
= uds_perform_read(minor
, dev_m_in
->m_source
, 1, 1);
325 /* there is data in the pipe for us to read */
326 uds_fd_table
[minor
].sel_ops_out
|= SEL_RD
;
328 } else if (uds_fd_table
[minor
].listening
== 1) {
330 /* check for pending connections */
331 for (i
= 0; i
< uds_fd_table
[minor
].backlog_size
; i
++) {
332 if (uds_fd_table
[minor
].backlog
[i
] != -1) {
333 uds_fd_table
[minor
].sel_ops_out
|= SEL_RD
;
339 /* check if we can write without blocking */
340 bytes
= uds_perform_write(minor
, dev_m_in
->m_source
, PIPE_BUF
, 1);
342 uds_fd_table
[minor
].sel_ops_out
|= SEL_WR
;
345 uds_fd_table
[minor
].syscall_done
= 1;
346 uds_sel_reply(dev_m_out
, DEV_SEL_REPL1
, minor
,
347 uds_fd_table
[minor
].sel_ops_out
);
349 return uds_fd_table
[minor
].sel_ops_out
;
352 static int uds_perform_read(int minor
, endpoint_t m_source
,
353 size_t size
, int pretend
)
360 static int call_count
= 0;
361 printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor
,
365 /* skip reads and writes of 0 (or less!) bytes */
370 /* check if we are allowed to read */
371 if (!(uds_fd_table
[minor
].mode
& S_IRUSR
)) {
373 /* socket is shutdown for reading */
377 if (uds_fd_table
[minor
].size
== 0) {
383 /* maybe a process is blocked waiting to write? if
384 * needed revive the writer
386 if (uds_fd_table
[minor
].peer
!= -1 &&
387 uds_fd_table
[uds_fd_table
[minor
].peer
].suspended
) {
388 int peer
= uds_fd_table
[minor
].peer
;
390 uds_fd_table
[peer
].ready_to_revive
= 1;
391 uds_unsuspend(m_source
, peer
);
395 printf("(uds) [%d] suspending read request\n", minor
);
398 /* Process is reading from an empty pipe,
399 * suspend it so some bytes can be written
401 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_READ
;
407 return (size
> uds_fd_table
[minor
].size
) ?
408 uds_fd_table
[minor
].size
: size
;
412 /* Prepare Request to the FS side of PFS */
413 fs_m_in
.m_type
= REQ_READ
;
414 fs_m_in
.REQ_INODE_NR
= uds_fd_table
[minor
].inode_nr
;
415 fs_m_in
.REQ_GRANT
= uds_fd_table
[minor
].io_gr
;
416 fs_m_in
.REQ_SEEK_POS_HI
= 0;
417 fs_m_in
.REQ_SEEK_POS_LO
= uds_fd_table
[minor
].pos
;
418 fs_m_in
.REQ_NBYTES
= (size
> uds_fd_table
[minor
].size
) ?
419 uds_fd_table
[minor
].size
: size
;
421 /* perform the read */
422 rc
= fs_readwrite(&fs_m_in
, &fs_m_out
);
424 perror("fs_readwrite");
428 /* Process the response */
430 printf("(uds) [%d] read complete\n", minor
);
433 /* move the position of the data pointer up to data we haven't
436 uds_fd_table
[minor
].pos
+= fs_m_out
.RES_NBYTES
;
438 /* decrease the number of unread bytes */
439 uds_fd_table
[minor
].size
-= fs_m_out
.RES_NBYTES
;
441 /* if we have 0 unread bytes, move the data pointer back to the
442 * start of the buffer
444 if (uds_fd_table
[minor
].size
== 0) {
445 uds_fd_table
[minor
].pos
= 0;
448 /* maybe a big write was waiting for us to read some data, if
449 * needed revive the writer
451 if (uds_fd_table
[minor
].peer
!= -1 &&
452 uds_fd_table
[uds_fd_table
[minor
].peer
].suspended
) {
453 int peer
= uds_fd_table
[minor
].peer
;
455 uds_fd_table
[peer
].ready_to_revive
= 1;
456 uds_unsuspend(m_source
, peer
);
459 /* see if peer is blocked on select() and a write is possible
460 * (from peer to minor)
462 if (uds_fd_table
[minor
].peer
!= -1 &&
463 uds_fd_table
[uds_fd_table
[minor
].peer
].selecting
== 1 &&
464 (uds_fd_table
[minor
].size
+ uds_fd_table
[minor
].pos
+ 1
467 int peer
= uds_fd_table
[minor
].peer
;
469 /* if the peer wants to know about write being possible
470 * and it doesn't know about it already, then let the peer know.
472 if ((uds_fd_table
[peer
].sel_ops_in
& SEL_WR
) &&
473 !(uds_fd_table
[peer
].sel_ops_out
& SEL_WR
)) {
475 /* a write on peer is possible now */
476 uds_fd_table
[peer
].sel_ops_out
|= SEL_WR
;
477 uds_fd_table
[peer
].status_updated
= 1;
478 uds_unsuspend(m_source
, peer
);
482 return fs_m_out
.RES_NBYTES
; /* return number of bytes read */
485 static int uds_perform_write(int minor
, endpoint_t m_source
,
486 size_t size
, int pretend
)
493 static int call_count
= 0;
494 printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor
,
498 /* skip reads and writes of 0 (or less!) bytes */
503 /* check if we are allowed to write */
504 if (!(uds_fd_table
[minor
].mode
& S_IWUSR
)) {
506 /* socket is shutdown for writing */
510 if (size
> PIPE_BUF
) {
512 /* message is too big to ever write to the PIPE */
516 if (uds_fd_table
[minor
].type
== SOCK_STREAM
||
517 uds_fd_table
[minor
].type
== SOCK_SEQPACKET
) {
519 /* if we're writing with a connection oriented socket,
520 * then it needs a peer to write to
522 if (uds_fd_table
[minor
].peer
== -1) {
523 if (uds_fd_table
[minor
].err
== ECONNRESET
) {
525 uds_fd_table
[minor
].err
= 0;
532 peer
= uds_fd_table
[minor
].peer
;
535 } else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
539 /* locate the "peer" we want to write to */
540 for (i
= 0; i
< NR_FDS
; i
++) {
542 /* look for a SOCK_DGRAM socket that is bound on
545 if (uds_fd_table
[i
].type
== SOCK_DGRAM
&&
546 uds_fd_table
[i
].addr
.sun_family
== AF_UNIX
&&
547 !strncmp(uds_fd_table
[minor
].target
.sun_path
,
548 uds_fd_table
[i
].addr
.sun_path
, UNIX_PATH_MAX
)) {
563 /* check if write would overrun buffer. check if message
564 * boundry preserving types (SEQPACKET and DGRAM) wouldn't write
565 * to an empty buffer. check if connectionless sockets have a
566 * target to write to.
568 if ((uds_fd_table
[peer
].pos
+uds_fd_table
[peer
].size
+size
> PIPE_BUF
) ||
569 ((uds_fd_table
[minor
].type
== SOCK_SEQPACKET
||
570 uds_fd_table
[minor
].type
== SOCK_DGRAM
) &&
571 uds_fd_table
[peer
].size
> 0)) {
577 /* if needed revive the reader */
578 if (uds_fd_table
[peer
].suspended
) {
579 uds_fd_table
[peer
].ready_to_revive
= 1;
580 uds_unsuspend(m_source
, peer
);
584 printf("(uds) [%d] suspending write request\n", minor
);
587 /* Process is reading from an empty pipe,
588 * suspend it so some bytes can be written
590 uds_fd_table
[minor
].suspended
= UDS_SUSPENDED_WRITE
;
598 /* Prepare Request to the FS side of PFS */
599 fs_m_in
.m_type
= REQ_WRITE
;
600 fs_m_in
.REQ_INODE_NR
= uds_fd_table
[peer
].inode_nr
;
601 fs_m_in
.REQ_GRANT
= uds_fd_table
[minor
].io_gr
;
602 fs_m_in
.REQ_SEEK_POS_HI
= 0;
603 fs_m_in
.REQ_SEEK_POS_LO
= uds_fd_table
[peer
].pos
+
604 uds_fd_table
[peer
].size
;
605 fs_m_in
.REQ_NBYTES
= size
;
607 /* Request the write */
608 rc
= fs_readwrite(&fs_m_in
, &fs_m_out
);
610 perror("fs_readwrite");
614 /* Process the response */
616 printf("(uds) [%d] write complete\n", minor
);
618 /* increase the count of unread bytes */
619 uds_fd_table
[peer
].size
+= fs_m_out
.RES_NBYTES
;
622 /* fill in the source address to be returned by recvfrom & recvmsg */
623 if (uds_fd_table
[minor
].type
== SOCK_DGRAM
) {
624 memcpy(&uds_fd_table
[peer
].source
, &uds_fd_table
[minor
].addr
,
625 sizeof(struct sockaddr_un
));
628 /* revive peer that was waiting for us to write */
629 if (uds_fd_table
[peer
].suspended
) {
630 uds_fd_table
[peer
].ready_to_revive
= 1;
631 uds_unsuspend(m_source
, peer
);
634 /* see if peer is blocked on select()*/
635 if (uds_fd_table
[peer
].selecting
== 1 && fs_m_out
.RES_NBYTES
> 0) {
637 /* if the peer wants to know about data ready to read
638 * and it doesn't know about it already, then let the peer
639 * know we have data for it.
641 if ((uds_fd_table
[peer
].sel_ops_in
& SEL_RD
) &&
642 !(uds_fd_table
[peer
].sel_ops_out
& SEL_RD
)) {
644 /* a read on peer is possible now */
645 uds_fd_table
[peer
].sel_ops_out
|= SEL_RD
;
646 uds_fd_table
[peer
].status_updated
= 1;
647 uds_unsuspend(m_source
, peer
);
651 return fs_m_out
.RES_NBYTES
; /* return number of bytes written */
654 int uds_read(message
*dev_m_in
, message
*dev_m_out
)
660 static int call_count
= 0;
661 printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in
),
663 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in
->USER_ENDPT
,
667 minor
= uds_minor(dev_m_in
);
669 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
671 /* attempted to close a socket that hasn't been opened --
672 * something is very wrong :(
674 uds_set_reply(dev_m_out
, DEV_REVIVE
, dev_m_in
->USER_ENDPT
,
675 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINVAL
);
680 /* track the system call we are performing in case it gets cancelled */
681 uds_fd_table
[minor
].call_nr
= dev_m_in
->m_type
;
682 uds_fd_table
[minor
].ioctl
= 0;
683 uds_fd_table
[minor
].syscall_done
= 0;
685 /* Update the process endpoint. */
686 uds_fd_table
[minor
].endpoint
= dev_m_in
->USER_ENDPT
;
688 /* setup select(2) framework */
689 uds_fd_table
[minor
].selecting
= 0;
691 /* save I/O Grant info */
692 uds_fd_table
[minor
].io_gr
= (cp_grant_id_t
) dev_m_in
->IO_GRANT
;
693 uds_fd_table
[minor
].io_gr_size
= dev_m_in
->COUNT
;
695 bytes
= uds_perform_read(minor
, dev_m_in
->m_source
,
696 uds_fd_table
[minor
].io_gr_size
, 0);
698 uds_set_reply(dev_m_out
, DEV_REVIVE
, uds_fd_table
[minor
].endpoint
,
699 uds_fd_table
[minor
].io_gr
, bytes
);
704 int uds_write(message
*dev_m_in
, message
*dev_m_out
)
710 static int call_count
= 0;
711 printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in
),
713 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in
->USER_ENDPT
,
717 minor
= uds_minor(dev_m_in
);
719 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
721 /* attempted to close a socket that hasn't been opened --
722 * something is very wrong :(
724 uds_set_reply(dev_m_out
, DEV_REVIVE
, dev_m_in
->USER_ENDPT
,
725 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINVAL
);
730 /* track the system call we are performing in case it gets cancelled */
731 uds_fd_table
[minor
].call_nr
= dev_m_in
->m_type
;
732 uds_fd_table
[minor
].ioctl
= 0;
733 uds_fd_table
[minor
].syscall_done
= 0;
735 /* Update the process endpoint. */
736 uds_fd_table
[minor
].endpoint
= dev_m_in
->USER_ENDPT
;
738 /* setup select(2) framework */
739 uds_fd_table
[minor
].selecting
= 0;
741 /* save I/O Grant info */
742 uds_fd_table
[minor
].io_gr
= (cp_grant_id_t
) dev_m_in
->IO_GRANT
;
743 uds_fd_table
[minor
].io_gr_size
= dev_m_in
->COUNT
;
745 bytes
= uds_perform_write(minor
, dev_m_in
->m_source
,
746 uds_fd_table
[minor
].io_gr_size
, 0);
748 uds_set_reply(dev_m_out
, DEV_REVIVE
, uds_fd_table
[minor
].endpoint
,
749 uds_fd_table
[minor
].io_gr
, bytes
);
754 int uds_ioctl(message
*dev_m_in
, message
*dev_m_out
)
759 static int call_count
= 0;
760 printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in
),
762 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in
->USER_ENDPT
,
766 minor
= uds_minor(dev_m_in
);
768 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
770 /* attempted to close a socket that hasn't been opened --
771 * something is very wrong :(
773 uds_set_reply(dev_m_out
, DEV_REVIVE
, dev_m_in
->USER_ENDPT
,
774 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINVAL
);
779 /* track the system call we are performing in case it gets cancelled */
780 uds_fd_table
[minor
].call_nr
= dev_m_in
->m_type
;
781 uds_fd_table
[minor
].ioctl
= dev_m_in
->COUNT
;
782 uds_fd_table
[minor
].syscall_done
= 0;
784 /* setup select(2) framework */
785 uds_fd_table
[minor
].selecting
= 0;
787 /* update the owner endpoint - yes it's really stored in POSITION */
788 uds_fd_table
[minor
].owner
= dev_m_in
->POSITION
;
790 switch (dev_m_in
->COUNT
) { /* Handle the ioctl(2) command */
794 /* connect to a listening socket -- connect() */
795 rc
= do_connect(dev_m_in
, dev_m_out
);
801 /* accept an incoming connection -- accept() */
802 rc
= do_accept(dev_m_in
, dev_m_out
);
808 /* set the backlog_size and put the socket into the
809 * listening state -- listen()
811 rc
= do_listen(dev_m_in
, dev_m_out
);
817 /* set the type for this socket (i.e.
818 * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
820 rc
= do_socket(dev_m_in
, dev_m_out
);
826 /* set the address for this socket -- bind() */
827 rc
= do_bind(dev_m_in
, dev_m_out
);
833 /* get the address for this socket -- getsockname() */
834 rc
= do_getsockname(dev_m_in
, dev_m_out
);
840 /* get the address for the peer -- getpeername() */
841 rc
= do_getpeername(dev_m_in
, dev_m_out
);
847 /* shutdown a socket for reading, writing, or
850 rc
= do_shutdown(dev_m_in
, dev_m_out
);
856 /* connect two sockets -- socketpair() */
857 rc
= do_socketpair(dev_m_in
, dev_m_out
);
861 case NWIOSUDSPAIROLD
:
863 /* connect two sockets -- socketpair() */
864 rc
= do_socketpair_old(dev_m_in
, dev_m_out
);
870 /* get socket type -- getsockopt(SO_TYPE) */
871 rc
= do_getsockopt_sotype(dev_m_in
, dev_m_out
);
875 case NWIOGUDSPEERCRED
:
877 /* get peer endpoint -- getsockopt(SO_PEERCRED) */
878 rc
= do_getsockopt_peercred(dev_m_in
, dev_m_out
);
882 case NWIOGUDSPEERCREDOLD
:
884 /* get peer endpoint -- getsockopt(SO_PEERCRED) */
885 rc
= do_getsockopt_peercred_old(dev_m_in
, dev_m_out
);
891 /* set target address -- sendto() */
892 rc
= do_sendto(dev_m_in
, dev_m_out
);
898 /* get from address -- recvfrom() */
899 rc
= do_recvfrom(dev_m_in
, dev_m_out
);
905 /* get the send buffer size -- getsockopt(SO_SNDBUF) */
906 rc
= do_getsockopt_sndbuf(dev_m_in
, dev_m_out
);
912 /* set the send buffer size -- setsockopt(SO_SNDBUF) */
913 rc
= do_setsockopt_sndbuf(dev_m_in
, dev_m_out
);
919 /* get the send buffer size -- getsockopt(SO_SNDBUF) */
920 rc
= do_getsockopt_rcvbuf(dev_m_in
, dev_m_out
);
926 /* set the send buffer size -- setsockopt(SO_SNDBUF) */
927 rc
= do_setsockopt_rcvbuf(dev_m_in
, dev_m_out
);
933 /* set the control data -- sendmsg() */
934 rc
= do_sendmsg(dev_m_in
, dev_m_out
);
940 /* set the control data -- recvmsg() */
941 rc
= do_recvmsg(dev_m_in
, dev_m_out
);
947 /* the IOCTL command is not valid for /dev/uds --
948 * this happens a lot and is normal. a lot of
949 * libc functions determine the socket type with
950 * IOCTLs. Any not for us simply get a EBADIOCTL
958 uds_fd_table
[minor
].syscall_done
= 1;
960 uds_set_reply(dev_m_out
, DEV_REVIVE
, dev_m_in
->USER_ENDPT
,
961 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, rc
);
966 int uds_unsuspend(endpoint_t m_source
, int minor
)
972 fdp
= &uds_fd_table
[minor
];
974 if (fdp
->status_updated
== 1) {
976 /* clear the status_updated flag */
977 fdp
->status_updated
= 0;
980 /* prepare the response */
981 uds_sel_reply(&m_out
, DEV_SEL_REPL2
, minor
, fdp
->sel_ops_out
);
982 } else if (fdp
->ready_to_revive
== 1) {
984 /* clear the ready to revive flag */
985 fdp
->ready_to_revive
= 0;
987 switch (fdp
->suspended
) {
989 case UDS_SUSPENDED_READ
:
991 bytes
= uds_perform_read(minor
, m_source
,
994 if (bytes
== SUSPEND
) {
999 fdp
->suspended
= UDS_NOT_SUSPENDED
;
1001 uds_set_reply(&m_out
, DEV_REVIVE
, fdp
->endpoint
,
1006 case UDS_SUSPENDED_WRITE
:
1008 bytes
= uds_perform_write(minor
, m_source
,
1009 fdp
->io_gr_size
, 0);
1011 if (bytes
== SUSPEND
) {
1016 fdp
->suspended
= UDS_NOT_SUSPENDED
;
1018 uds_set_reply(&m_out
, DEV_REVIVE
, fdp
->endpoint
,
1023 case UDS_SUSPENDED_CONNECT
:
1024 case UDS_SUSPENDED_ACCEPT
:
1026 /* In both cases, the process
1027 * that send the notify()
1028 * already performed the connection.
1029 * The only thing to do here is
1033 fdp
->suspended
= UDS_NOT_SUSPENDED
;
1035 uds_set_reply(&m_out
, DEV_REVIVE
, fdp
->endpoint
,
1046 if (r
== OK
) reply(m_source
, &m_out
);
1050 int uds_cancel(message
*dev_m_in
, message
*dev_m_out
)
1054 /* XXX: should become a noop? */
1056 static int call_count
= 0;
1057 printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in
),
1059 printf("Endpoint: 0x%x\n", dev_m_in
->USER_ENDPT
);
1062 minor
= uds_minor(dev_m_in
);
1064 if (uds_fd_table
[minor
].state
!= UDS_INUSE
) {
1066 /* attempted to close a socket that hasn't been opened --
1067 * something is very wrong :(
1069 uds_set_reply(dev_m_out
, DEV_NO_STATUS
, dev_m_in
->USER_ENDPT
,
1070 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINVAL
);
1075 /* Update the process endpoint. */
1076 uds_fd_table
[minor
].endpoint
= dev_m_in
->USER_ENDPT
;
1078 /* setup select(2) framework */
1079 uds_fd_table
[minor
].selecting
= 0;
1081 /* the system call was cancelled, so if the socket was suspended
1082 * (which is likely the case), then it is not suspended anymore.
1084 uds_fd_table
[minor
].suspended
= UDS_NOT_SUSPENDED
;
1086 /* If there is a system call and it isn't complete, roll back */
1087 if (uds_fd_table
[minor
].call_nr
&& !uds_fd_table
[minor
].syscall_done
) {
1090 if (uds_fd_table
[minor
].call_nr
== DEV_IOCTL_S
) {
1092 switch (uds_fd_table
[minor
].ioctl
) {
1094 case NWIOSUDSACCEPT
: /* accept() */
1096 /* partial accept() only changes
1097 * uds_fd_table[minorparent].child
1100 for (i
= 0; i
< NR_FDS
; i
++) {
1101 if (uds_fd_table
[i
].child
==
1104 uds_fd_table
[i
].child
= -1;
1111 case NWIOSUDSCONN
: /* connect() */
1113 /* partial connect() sets addr
1114 * and adds minor to server backlog
1117 for (i
= 0; i
< NR_FDS
; i
++) {
1119 /* find a socket that is in
1122 if (uds_fd_table
[i
].state
==
1125 /* see if minor is in
1128 for (j
= 0; j
< uds_fd_table
[i
].backlog_size
; j
++) {
1130 if (uds_fd_table
[i
].backlog
[j
] == minor
) {
1132 /* remove from backlog */
1133 uds_fd_table
[i
].backlog
[j
] = -1;
1140 /* clear the address */
1141 memset(&(uds_fd_table
[minor
].addr
),
1143 sizeof(struct sockaddr_un
));
1147 case NWIOSUDSTADDR
: /* sendto() */
1148 case NWIOSUDSADDR
: /* bind() */
1149 case NWIOGUDSADDR
: /* getsockname() */
1150 case NWIOGUDSPADDR
: /* getpeername() */
1151 case NWIOSUDSTYPE
: /* socket() */
1152 case NWIOSUDSBLOG
: /* listen() */
1153 case NWIOSUDSSHUT
: /* shutdown() */
1154 case NWIOSUDSPAIR
: /* socketpair() */
1155 case NWIOGUDSSOTYPE
: /* SO_TYPE */
1156 case NWIOGUDSPEERCRED
: /* SO_PEERCRED */
1158 /* these are atomic, never suspend,
1159 * and can't be cancelled once called
1166 /* DEV_READ_S or DEV_WRITE_S don't need to do anything
1167 * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT,
1168 * DEV_CLOSE are atomic, never suspend, and can't
1169 * be cancelled once called.
1172 uds_fd_table
[minor
].syscall_done
= 1;
1176 uds_set_reply(dev_m_out
, DEV_NO_STATUS
, dev_m_in
->USER_ENDPT
,
1177 (cp_grant_id_t
) dev_m_in
->IO_GRANT
, EINTR
);