VM: make mapping types explicit
[minix.git] / servers / pfs / dev_uds.c
blobd5e9a212740aef3583da7e701beed2c453d54c8b
1 /*
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.
16 * Also See...
18 * table.c, uds.c, uds.h
20 * Overview
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.
28 #define DEBUG 0
30 #include "inc.h"
31 #include "const.h"
32 #include "glo.h"
33 #include "uds.h"
35 static int uds_perform_read(int minor, endpoint_t m_source, size_t
36 size, int pretend);
37 static int uds_perform_write(int minor, endpoint_t m_source, size_t
38 size, int pretend);
40 int uds_open(message *dev_m_in, message *dev_m_out)
42 message fs_m_in, fs_m_out;
43 struct ucred ucred;
44 int rc, i;
45 int minor;
47 #if DEBUG == 1
48 static int call_count = 0;
49 printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in),
50 ++call_count);
51 printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
52 #endif
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) {
66 minor = i;
67 break;
71 if (minor == -1) {
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);
76 return 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
84 * another socket
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
127 ancillary));
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);
166 if (rc == -1) {
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);
173 return 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);
187 if (rc != OK) {
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);
194 return 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);
206 return minor;
209 int uds_close(message *dev_m_in, message *dev_m_out)
211 int minor;
212 message fs_m_in, fs_m_out;
213 int rc;
215 #if DEBUG == 1
216 static int call_count = 0;
217 printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in),
218 ++call_count);
219 printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
220 #endif
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);
230 return 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);
272 if (rc != OK) {
273 perror("fs_putnode");
274 /* likely error: get_block() failed */
275 return rc;
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);
280 return OK;
283 int uds_select(message *dev_m_in, message *dev_m_out)
285 int i, bytes;
286 int minor;
288 #if DEBUG == 1
289 static int call_count = 0;
290 printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in),
291 ++call_count);
292 printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
293 #endif
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);
304 return 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);
323 if (bytes > 0) {
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;
334 break;
339 /* check if we can write without blocking */
340 bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
341 if (bytes > 0) {
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)
355 int rc;
356 message fs_m_in;
357 message fs_m_out;
359 #if DEBUG == 1
360 static int call_count = 0;
361 printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor,
362 ++call_count);
363 #endif
365 /* skip reads and writes of 0 (or less!) bytes */
366 if (size <= 0) {
367 return 0;
370 /* check if we are allowed to read */
371 if (!(uds_fd_table[minor].mode & S_IRUSR)) {
373 /* socket is shutdown for reading */
374 return EPIPE;
377 if (uds_fd_table[minor].size == 0) {
379 if (pretend) {
380 return SUSPEND;
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);
394 #if DEBUG == 1
395 printf("(uds) [%d] suspending read request\n", minor);
396 #endif
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;
402 return SUSPEND;
405 if (pretend) {
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);
423 if (rc != OK) {
424 perror("fs_readwrite");
425 return rc;
428 /* Process the response */
429 #if DEBUG == 1
430 printf("(uds) [%d] read complete\n", minor);
431 #endif
433 /* move the position of the data pointer up to data we haven't
434 * read yet
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
465 < PIPE_BUF)) {
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)
488 int rc, peer, i;
489 message fs_m_in;
490 message fs_m_out;
492 #if DEBUG == 1
493 static int call_count = 0;
494 printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor,
495 ++call_count);
496 #endif
498 /* skip reads and writes of 0 (or less!) bytes */
499 if (size <= 0) {
500 return 0;
503 /* check if we are allowed to write */
504 if (!(uds_fd_table[minor].mode & S_IWUSR)) {
506 /* socket is shutdown for writing */
507 return EPIPE;
510 if (size > PIPE_BUF) {
512 /* message is too big to ever write to the PIPE */
513 return EMSGSIZE;
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;
526 return ECONNRESET;
527 } else {
528 return ENOTCONN;
530 } else {
532 peer = uds_fd_table[minor].peer;
535 } else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
537 peer = -1;
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
543 * the target address
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)) {
550 peer = i;
551 break;
556 if (peer == -1) {
557 if (pretend)
558 return SUSPEND;
560 return ENOENT;
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)) {
573 if (pretend) {
574 return SUSPEND;
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);
583 #if DEBUG == 1
584 printf("(uds) [%d] suspending write request\n", minor);
585 #endif
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;
591 return SUSPEND;
594 if (pretend) {
595 return size;
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);
609 if (rc != OK) {
610 perror("fs_readwrite");
611 return rc;
614 /* Process the response */
615 #if DEBUG == 1
616 printf("(uds) [%d] write complete\n", minor);
617 #endif
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)
656 int bytes;
657 int minor;
659 #if DEBUG == 1
660 static int call_count = 0;
661 printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
662 ++call_count);
663 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
664 dev_m_in->POSITION);
665 #endif
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);
677 return 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);
701 return bytes;
704 int uds_write(message *dev_m_in, message *dev_m_out)
706 int bytes;
707 int minor;
709 #if DEBUG == 1
710 static int call_count = 0;
711 printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
712 ++call_count);
713 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
714 dev_m_in->POSITION);
715 #endif
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);
727 return 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);
751 return bytes;
754 int uds_ioctl(message *dev_m_in, message *dev_m_out)
756 int rc, minor;
758 #if DEBUG == 1
759 static int call_count = 0;
760 printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
761 ++call_count);
762 printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
763 dev_m_in->POSITION);
764 #endif
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);
776 return 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 */
792 case NWIOSUDSCONN:
794 /* connect to a listening socket -- connect() */
795 rc = do_connect(dev_m_in, dev_m_out);
797 break;
799 case NWIOSUDSACCEPT:
801 /* accept an incoming connection -- accept() */
802 rc = do_accept(dev_m_in, dev_m_out);
804 break;
806 case NWIOSUDSBLOG:
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);
813 break;
815 case NWIOSUDSTYPE:
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);
822 break;
824 case NWIOSUDSADDR:
826 /* set the address for this socket -- bind() */
827 rc = do_bind(dev_m_in, dev_m_out);
829 break;
831 case NWIOGUDSADDR:
833 /* get the address for this socket -- getsockname() */
834 rc = do_getsockname(dev_m_in, dev_m_out);
836 break;
838 case NWIOGUDSPADDR:
840 /* get the address for the peer -- getpeername() */
841 rc = do_getpeername(dev_m_in, dev_m_out);
843 break;
845 case NWIOSUDSSHUT:
847 /* shutdown a socket for reading, writing, or
848 * both -- shutdown()
850 rc = do_shutdown(dev_m_in, dev_m_out);
852 break;
854 case NWIOSUDSPAIR:
856 /* connect two sockets -- socketpair() */
857 rc = do_socketpair(dev_m_in, dev_m_out);
859 break;
861 case NWIOSUDSPAIROLD:
863 /* connect two sockets -- socketpair() */
864 rc = do_socketpair_old(dev_m_in, dev_m_out);
866 break;
868 case NWIOGUDSSOTYPE:
870 /* get socket type -- getsockopt(SO_TYPE) */
871 rc = do_getsockopt_sotype(dev_m_in, dev_m_out);
873 break;
875 case NWIOGUDSPEERCRED:
877 /* get peer endpoint -- getsockopt(SO_PEERCRED) */
878 rc = do_getsockopt_peercred(dev_m_in, dev_m_out);
880 break;
882 case NWIOGUDSPEERCREDOLD:
884 /* get peer endpoint -- getsockopt(SO_PEERCRED) */
885 rc = do_getsockopt_peercred_old(dev_m_in, dev_m_out);
887 break;
889 case NWIOSUDSTADDR:
891 /* set target address -- sendto() */
892 rc = do_sendto(dev_m_in, dev_m_out);
894 break;
896 case NWIOGUDSFADDR:
898 /* get from address -- recvfrom() */
899 rc = do_recvfrom(dev_m_in, dev_m_out);
901 break;
903 case NWIOGUDSSNDBUF:
905 /* get the send buffer size -- getsockopt(SO_SNDBUF) */
906 rc = do_getsockopt_sndbuf(dev_m_in, dev_m_out);
908 break;
910 case NWIOSUDSSNDBUF:
912 /* set the send buffer size -- setsockopt(SO_SNDBUF) */
913 rc = do_setsockopt_sndbuf(dev_m_in, dev_m_out);
915 break;
917 case NWIOGUDSRCVBUF:
919 /* get the send buffer size -- getsockopt(SO_SNDBUF) */
920 rc = do_getsockopt_rcvbuf(dev_m_in, dev_m_out);
922 break;
924 case NWIOSUDSRCVBUF:
926 /* set the send buffer size -- setsockopt(SO_SNDBUF) */
927 rc = do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
929 break;
931 case NWIOSUDSCTRL:
933 /* set the control data -- sendmsg() */
934 rc = do_sendmsg(dev_m_in, dev_m_out);
936 break;
938 case NWIOGUDSCTRL:
940 /* set the control data -- recvmsg() */
941 rc = do_recvmsg(dev_m_in, dev_m_out);
943 break;
945 default:
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
951 * response.
954 rc = EBADIOCTL;
957 if (rc != SUSPEND)
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);
963 return rc;
966 int uds_unsuspend(endpoint_t m_source, int minor)
968 int r = OK, bytes;
969 message m_out;
970 uds_fd_t *fdp;
972 fdp = &uds_fd_table[minor];
974 if (fdp->status_updated == 1) {
976 /* clear the status_updated flag */
977 fdp->status_updated = 0;
978 fdp->selecting = 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,
992 fdp->io_gr_size, 0);
994 if (bytes == SUSPEND) {
995 r = SUSPEND;
996 break;
999 fdp->suspended = UDS_NOT_SUSPENDED;
1001 uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
1002 fdp->io_gr, bytes);
1004 break;
1006 case UDS_SUSPENDED_WRITE:
1008 bytes = uds_perform_write(minor, m_source,
1009 fdp->io_gr_size, 0);
1011 if (bytes == SUSPEND) {
1012 r = SUSPEND;
1013 break;
1016 fdp->suspended = UDS_NOT_SUSPENDED;
1018 uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
1019 fdp->io_gr, bytes);
1021 break;
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
1030 * unblock.
1033 fdp->suspended = UDS_NOT_SUSPENDED;
1035 uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
1036 fdp->io_gr, OK);
1038 break;
1040 default:
1041 return(OK);
1046 if (r == OK) reply(m_source, &m_out);
1047 return(r);
1050 int uds_cancel(message *dev_m_in, message *dev_m_out)
1052 int i, j;
1053 int minor;
1054 /* XXX: should become a noop? */
1055 #if DEBUG == 1
1056 static int call_count = 0;
1057 printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in),
1058 ++call_count);
1059 printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
1060 #endif
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);
1072 return 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 ==
1102 minor) {
1104 uds_fd_table[i].child = -1;
1109 break;
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
1120 * use.
1122 if (uds_fd_table[i].state ==
1123 UDS_INUSE) {
1125 /* see if minor is in
1126 * the backlog
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),
1142 '\0',
1143 sizeof(struct sockaddr_un));
1145 break;
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 */
1157 default:
1158 /* these are atomic, never suspend,
1159 * and can't be cancelled once called
1161 break;
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);
1179 return EINTR;