Remove building with NOCRYPTO option
[minix.git] / minix / net / uds / uds.c
blob2052a2ac2d5da8f572025a6a1c32f7c1f8978fce
1 /* UNIX Domain Sockets - uds.c - socket management */
3 #include "uds.h"
5 static struct udssock uds_array[NR_UDSSOCK];
6 static TAILQ_HEAD(uds_freelist, udssock) uds_freelist;
7 static unsigned int uds_in_use;
8 static int uds_running;
10 static const struct sockevent_ops uds_ops;
12 static SLIST_HEAD(udshash, udssock) udshash[UDSHASH_SLOTS];
15 * Initialize file-to-socket hash table.
17 static void
18 udshash_init(void)
20 unsigned int slot;
22 for (slot = 0; slot < __arraycount(udshash); slot++)
23 SLIST_INIT(&udshash[slot]);
27 * Return a hash table slot number for the given <dev,ino> pair.
29 static unsigned int
30 udshash_slot(dev_t dev, ino_t ino)
33 assert(dev != NO_DEV);
34 assert(ino != 0);
37 * Effectively combining two 64-bit numbers into a single 6-or-so-bit
38 * hash is not too easy. This hash function is probably among the
39 * worst options. Then again it is not all that critical as we are not
40 * expecting that many bound UDS sockets in the system anyway.
42 return (unsigned int)(dev ^ ino) % UDSHASH_SLOTS;
46 * Look for a socket that is bound to the given <dev,ino> pair. Return a
47 * pointer to the socket if found, or NULL otherwise.
49 static struct udssock *
50 udshash_get(dev_t dev, ino_t ino)
52 struct udssock *uds;
53 unsigned int slot;
55 slot = udshash_slot(dev, ino);
57 SLIST_FOREACH(uds, &udshash[slot], uds_hash) {
58 if (uds->uds_dev == dev && uds->uds_ino == ino)
59 return uds;
62 return NULL;
66 * Add a socket to the file-to-socket hash table. The socket must have its
67 * device and inode fields set, and must not be in the hash table already.
69 static void
70 udshash_add(struct udssock * uds)
72 unsigned int slot;
74 slot = udshash_slot(uds->uds_dev, uds->uds_ino);
76 SLIST_INSERT_HEAD(&udshash[slot], uds, uds_hash);
80 * Remove a socket from the file-to-socket hash table. The socket must be in
81 * the hash table.
83 static void
84 udshash_del(struct udssock * uds)
86 unsigned int slot;
88 slot = udshash_slot(uds->uds_dev, uds->uds_ino);
90 /* This macro is O(n). */
91 SLIST_REMOVE(&udshash[slot], uds, udssock, uds_hash);
95 * Return the socket identifier for the given UDS socket object.
97 sockid_t
98 uds_get_id(struct udssock * uds)
101 return (sockid_t)(uds - uds_array);
105 * Given either NULL or a previously returned socket, return the next in-use
106 * UDS socket of the given socket type, or NULL if there are no more matches.
107 * The sockets are returned in random order, but each matching socket is
108 * returned exactly once (until any socket is allocated or freed).
110 struct udssock *
111 uds_enum(struct udssock * prev, int type)
113 sockid_t id;
115 if (prev != NULL)
116 id = uds_get_id(prev) + 1;
117 else
118 id = 0;
120 for (; id < NR_UDSSOCK; id++)
121 if ((uds_array[id].uds_flags & UDSF_IN_USE) &&
122 uds_get_type(&uds_array[id]) == type)
123 return &uds_array[id];
125 return NULL;
129 * Invalidate credentials on the socket.
131 static void
132 uds_clear_cred(struct udssock * uds)
135 uds->uds_cred.unp_pid = -1;
136 uds->uds_cred.unp_euid = -1;
137 uds->uds_cred.unp_egid = -1;
141 * Obtain the credentials (process, user, and group ID) of the given user
142 * endpoint and associate them with the socket for later retrieval. It is
143 * important to note that this information is obtained once at connect time,
144 * and never updated later. The party receiving the credentials must take this
145 * into account.
147 static void
148 uds_get_cred(struct udssock * uds, endpoint_t user_endpt)
150 int r;
152 if ((uds->uds_cred.unp_pid = r = getepinfo(user_endpt,
153 &uds->uds_cred.unp_euid, &uds->uds_cred.unp_egid)) < 0) {
154 printf("UDS: failed obtaining credentials of %d (%d)\n",
155 user_endpt, r);
157 uds_clear_cred(uds);
162 * Allocate and initialize a UDS socket. On succes, return OK with a pointer
163 * to the new socket in 'udsp'. On failure, return a negative error code.
165 static int
166 uds_alloc(struct udssock ** udsp)
168 struct udssock *uds;
169 int r;
171 /* Allocate, initialize, and return a UNIX domain socket object. */
172 if (TAILQ_EMPTY(&uds_freelist))
173 return ENOBUFS;
175 uds = TAILQ_FIRST(&uds_freelist);
177 uds->uds_conn = NULL; /* not connected */
178 uds->uds_link = NULL; /* not connecting or linked */
179 uds->uds_queued = 0;
180 uds->uds_flags = UDSF_IN_USE; /* may be found through enumeration */
181 uds->uds_pathlen = 0; /* not bound: no path */
182 uds->uds_dev = NO_DEV; /* not hashed: no socket file device */
183 uds->uds_ino = 0; /* not hashed: no socket file inode */
184 uds_clear_cred(uds); /* no bind/connect-time credentials */
185 TAILQ_INIT(&uds->uds_queue); /* an empty queue */
187 if ((r = uds_io_setup(uds)) != OK)
188 return r;
190 TAILQ_REMOVE(&uds_freelist, uds, uds_next);
192 assert(uds_in_use < NR_UDSSOCK);
193 uds_in_use++;
195 *udsp = uds;
196 return OK;
200 * Free a previously allocated socket.
202 static void
203 uds_free(struct sock * sock)
205 struct udssock *uds = (struct udssock *)sock;
207 uds_io_cleanup(uds);
209 uds->uds_flags = 0; /* no longer in use */
211 TAILQ_INSERT_HEAD(&uds_freelist, uds, uds_next);
213 assert(uds_in_use > 0);
214 if (--uds_in_use == 0 && uds_running == FALSE)
215 sef_cancel();
219 * Create a new socket.
221 static sockid_t
222 uds_socket(int domain, int type, int protocol, endpoint_t user_endpt __unused,
223 struct sock ** sockp, const struct sockevent_ops ** ops)
225 struct udssock *uds;
226 int r;
228 dprintf(("UDS: socket(%d,%d,%d)\n", domain, type, protocol));
230 if (domain != PF_UNIX) {
231 /* This means the service was configured incorrectly. */
232 printf("UDS: got request for domain %d\n", domain);
234 return EAFNOSUPPORT;
237 /* We support the following three socket types. */
238 switch (type) {
239 case SOCK_STREAM:
240 case SOCK_SEQPACKET:
241 case SOCK_DGRAM:
242 break;
243 default:
244 return EPROTOTYPE;
248 * The PF_UNIX domain does not support particular protocols, so the
249 * given protocol must be zero (= anything that matches).
251 if (protocol != UDSPROTO_UDS)
252 return EPROTONOSUPPORT;
254 if ((r = uds_alloc(&uds)) != OK)
255 return r;
257 dprintf(("UDS: socket returns %d\n", uds_get_id(uds)));
259 *sockp = &uds->uds_sock;
260 *ops = &uds_ops;
261 return uds_get_id(uds);
265 * Connect a pair of sockets.
267 static int
268 uds_pair(struct sock * sock1, struct sock * sock2, endpoint_t user_endpt)
270 struct udssock *uds1 = (struct udssock *)sock1;
271 struct udssock *uds2 = (struct udssock *)sock2;
273 dprintf(("UDS: pair(%d,%d)\n", uds_get_id(uds1), uds_get_id(uds2)));
275 /* Only connection-oriented types are acceptable. */
276 if (uds_get_type(uds1) == SOCK_DGRAM)
277 return EOPNOTSUPP;
279 /* Connect the sockets. */
280 uds1->uds_conn = uds2;
281 uds2->uds_conn = uds1;
282 uds1->uds_flags |= UDSF_CONNECTED;
283 uds2->uds_flags |= UDSF_CONNECTED;
285 /* Obtain the (same) credentials for both sides of the connection. */
286 uds_get_cred(uds1, user_endpt);
287 memcpy(&uds2->uds_cred, &uds1->uds_cred, sizeof(uds2->uds_cred));
289 return OK;
293 * Disconnect a UDS socket, notifying or freeing up the other end of the
294 * connection depending on whether the socket was linked, that is, on the
295 * accept queue of a listening socket.
297 static void
298 uds_disconnect(struct udssock * uds, int was_linked)
300 struct udssock *conn;
302 assert(uds_is_connected(uds));
303 assert(uds_has_conn(uds));
305 conn = uds->uds_conn;
307 assert(uds_is_connected(conn));
308 assert(uds_has_conn(conn));
309 assert(!uds_has_link(conn));
310 assert(conn->uds_conn == uds);
312 /* Disconnect the sockets. */
313 uds->uds_conn = NULL;
314 conn->uds_conn = NULL;
317 * If the given socket is linked, then it is a connected socket for
318 * which the other end has been created but not yet accepted. In that
319 * case, the other end ('conn') will have to be freed up. Otherwise,
320 * it is a regular user-created socket and we must properly transition
321 * it into disconnected state.
323 if (!was_linked) {
324 sockevent_raise(&conn->uds_sock, SEV_SEND | SEV_RECV);
327 * Clear the peer credentials so that they will not be mistaken
328 * for having been obtained at bind time.
330 uds_clear_cred(conn);
331 } else
332 sockevent_raise(&conn->uds_sock, SEV_CLOSE);
336 * Add the socket 'link' to the queue of the socket 'uds'. This also implies
337 * that 'link's link socket is set to 'uds'.
339 static void
340 uds_add_queue(struct udssock * uds, struct udssock * link)
343 dprintf(("UDS: add_queue(%d,%d)\n",
344 uds_get_id(uds), uds_get_id(link)));
346 TAILQ_INSERT_TAIL(&uds->uds_queue, link, uds_next);
348 uds->uds_queued++;
349 assert(uds->uds_queued != 0);
351 link->uds_link = uds;
355 * Remove the socket 'link' from the queue of the socket 'uds'. This also
356 * reset 'link's link to NULL.
358 static void
359 uds_del_queue(struct udssock * uds, struct udssock * link)
362 dprintf(("UDS: del_queue(%d,%d)\n",
363 uds_get_id(uds), uds_get_id(link)));
365 assert(link->uds_link == uds);
367 TAILQ_REMOVE(&uds->uds_queue, link, uds_next);
369 assert(uds->uds_queued > 0);
370 uds->uds_queued--;
372 link->uds_link = NULL;
376 * Remove all sockets from the queue of the socket 'uds', with the exception of
377 * 'except' if non-NULL. Raise an ECONNRESET error on all removed sockets that
378 * are not equal to 'uds'.
380 static void
381 uds_clear_queue(struct udssock * uds, struct udssock * except)
383 struct udssock *link, *tmp;
384 int found;
386 dprintf(("UDS: clear_queue(%d,%d)\n",
387 uds_get_id(uds), (except != NULL) ? uds_get_id(except) : -1));
389 found = 0;
392 * Abort all connecting sockets queued on this socket, except for the
393 * given exception, which may be NULL.
395 TAILQ_FOREACH_SAFE(link, &uds->uds_queue, uds_next, tmp) {
396 if (link == except) {
397 found++;
399 continue;
402 dprintf(("UDS: clear_queue removes %d\n", uds_get_id(link)));
404 assert(uds_get_type(link) == SOCK_DGRAM ||
405 uds_is_connecting(link) || uds_is_connected(link));
407 uds_del_queue(uds, link);
410 * Generate an error only if the socket was not linked to
411 * itself (only datagram sockets can be linked to themselves).
412 * The error is not helpful for applications in that case.
414 if (uds != link)
415 sockevent_set_error(&link->uds_sock, ECONNRESET);
418 * If this is a listening socket, disconnect the connecting or
419 * connected end. If a connected peer was already created for
420 * the queued socket, dispose of that peer.
422 * Clear credentials obtained when starting to connect (in
423 * which case the socket is always a connection-oriented
424 * socket), so that they will not be mistaken for credentials
425 * obtained at bind time.
427 if (uds_get_type(link) != SOCK_DGRAM) {
428 if (uds_is_connected(link))
429 uds_disconnect(link, TRUE /*was_linked*/);
430 else
431 uds_clear_cred(link);
435 assert(uds->uds_queued == found);
439 * Check whether the socket address given in 'addr', with length 'addr_len', is
440 * a valid UNIX domain socket address (including a path to a socket file). On
441 * success, return the (non-zero) length of the socket file's path, minus the
442 * null terminator which may in fact not be present. The caller is responsible
443 * for copying and terminating the path as needed. A pointer to the path as
444 * stored in 'addr' is returned in 'pathp'. On failure, return an error code.
446 static int
447 uds_check_addr(const struct sockaddr * addr, socklen_t addr_len,
448 const char ** pathp)
450 const char *p;
451 size_t len;
454 * We could cast to a sockaddr_un structure pointer first, but that
455 * would not provide any benefits here. Instead, we use sa_data as the
456 * generic equivalent of sun_path.
458 if (addr_len < offsetof(struct sockaddr, sa_data))
459 return EINVAL;
461 if (addr->sa_family != AF_UNIX)
462 return EAFNOSUPPORT;
464 len = (size_t)addr_len - offsetof(struct sockaddr, sa_data);
465 if (len > 0 && (p = memchr(addr->sa_data, '\0', len)) != NULL)
466 len = (size_t)(p - addr->sa_data);
468 /* The given path name must not be an empty string. */
469 if (len == 0)
470 return ENOENT;
472 /* This check should be redundant but better safe than sorry. */
473 if (len >= UDS_PATH_MAX)
474 return EINVAL;
476 *pathp = (const char *)addr->sa_data;
477 return len;
481 * Given the socket file path given as 'path' with length 'path_len' (not
482 * necessarily null terminated), store a socket address with the path in
483 * 'addr', and return the socket address length in 'addr_len'. The calling
484 * libraries (libsockdriver, libsockevent) and the static assert in uds.h
485 * guarantee that 'addr' is sufficiently large to store any address we generate
486 * here. The libraries may subsequently copy out only a part of it to the user
487 * process. This function always succeeds.
489 void
490 uds_make_addr(const char * path, size_t len, struct sockaddr * addr,
491 socklen_t * addr_len)
495 * Generate the address. The stored length (sa_len/sun_len) does not
496 * include a null terminator. The entire structure does include a null
497 * terminator, but only if the socket is bound.
499 addr->sa_len = offsetof(struct sockaddr, sa_data) + len;
500 addr->sa_family = AF_UNIX;
501 if (len > 0) {
502 /* This call may (intentionally) overrun the sa_data size. */
503 memcpy((char *)addr->sa_data, path, len);
504 ((char *)addr->sa_data)[len] = '\0';
506 /* The socket is bound, so include the null terminator. */
507 len++;
508 assert(len <= UDS_PATH_MAX);
511 /* Note that this length may be different from sa_len/sun_len now. */
512 *addr_len = offsetof(struct sockaddr, sa_data) + len;
516 * Bind a socket to a local address.
518 static int
519 uds_bind(struct sock * sock, const struct sockaddr * addr, socklen_t addr_len,
520 endpoint_t user_endpt)
522 struct udssock *uds = (struct udssock *)sock;
523 struct udssock *uds2;
524 const char *path;
525 size_t len;
526 dev_t dev;
527 ino_t ino;
528 int r;
530 dprintf(("UDS: bind(%d)\n", uds_get_id(uds)));
532 /* A socket may be bound at any time, but only once. */
533 if (uds_is_bound(uds))
534 return EINVAL;
536 /* Verify that the user gave us an acceptable address. */
537 if ((r = uds_check_addr(addr, addr_len, &path)) < 0)
538 return r;
539 len = (size_t)r;
541 /* Attempt to create the socket file on the file system. */
542 r = socketpath(user_endpt, path, len, SPATH_CREATE, &dev, &ino);
543 if (r != OK)
544 return r;
545 assert(dev != NO_DEV && ino != 0);
548 * It is possible that a socket file of a previously bound socket was
549 * unlinked, and due to inode number reuse, a new socket file has now
550 * been created with the same <dev,ino> pair. In that case, we must
551 * unbind the old socket, because it must no longer be found. The old
552 * socket will still have a path (and behave as though it is bound) but
553 * no longer be found through hash lookups.
555 if ((uds2 = udshash_get(dev, ino)) != NULL) {
556 udshash_del(uds2);
558 uds2->uds_dev = NO_DEV;
559 uds2->uds_ino = 0;
563 * Obtain credentials for the socket, unless the socket is already
564 * connecting or connected, in which case we must not replace the
565 * credentials we obtained already. We later clear those credentials
566 * upon a connection failure or disconnect, so that if the socket is
567 * then put in listening mode, we know there are no bind-time
568 * credentials. Not ideal, but we really need two separate sets of
569 * credentials if we want to get this right, which is a waste of memory
570 * as no sane application writer would ever rely on credential passing
571 * after recycling a socket..
573 if (uds_get_type(uds) != SOCK_DGRAM && !uds_is_connecting(uds) &&
574 !uds_is_connected(uds))
575 uds_get_cred(uds, user_endpt);
577 /* Asssign the address to the socket. */
578 uds->uds_pathlen = len;
579 memcpy(&uds->uds_path, path, len);
580 uds->uds_dev = dev;
581 uds->uds_ino = ino;
583 udshash_add(uds);
585 return OK;
589 * Look up a UDS socket based on a user-given address. If a socket exists for
590 * the address, check if it is type-compatible with the given UDS socket.
591 * On succes, return OK, with 'peerp' set to the socket that was found. On
592 * failure, return a negative error code.
595 uds_lookup(struct udssock * uds, const struct sockaddr * addr,
596 socklen_t addr_len, endpoint_t user_endpt, struct udssock ** peerp)
598 struct udssock *peer;
599 const char *path;
600 size_t len;
601 dev_t dev;
602 ino_t ino;
603 int r;
605 /* Verify that the user gave us an acceptable address. */
606 if ((r = uds_check_addr(addr, addr_len, &path)) < 0)
607 return r;
608 len = (size_t)r;
610 /* Attempt to look up the socket file on the file system. */
611 r = socketpath(user_endpt, path, len, SPATH_CHECK, &dev, &ino);
612 if (r != OK)
613 return r;
614 assert(dev != NO_DEV && ino != 0);
616 if ((peer = udshash_get(dev, ino)) == NULL)
617 return ECONNREFUSED;
618 if (uds_get_type(peer) != uds_get_type(uds))
619 return EPROTOTYPE;
621 *peerp = peer;
622 return OK;
626 * Given the listening socket 'uds', and the socket 'link' that is calling or
627 * has called connect(2) and is or will be linked to the listening socket's
628 * queue, create a new socket and connect it to 'link', putting both sockets in
629 * the connected state. The given link socket may be in unconnected,
630 * connecting, or disconnected state prior to the call. Return OK or an error
631 * code. The link state of the link socket remains unchanged in any case.
633 static int
634 uds_attach(struct udssock * uds, struct udssock * link)
636 struct udssock *conn;
637 int r;
640 * Allocate a new socket to use as peer socket for the connection that
641 * is about to be established. The new socket is not yet known by
642 * libsockevent.
644 if ((r = uds_alloc(&conn)) != OK)
645 return r;
648 * Ask libsockevent to clone the sock object in the new UDS socket from
649 * the listening socket. This adds the sock object to libsockevent's
650 * data structures and ensures that we can safely use the socket
651 * despite the fact that it has not yet been accepted (and thus
652 * returned to libsockevent). From this moment on, we must either
653 * return the socket's ID (but not a pointer to it!) from uds_accept()
654 * or raise SEV_CLOSE on it.
656 sockevent_clone(&uds->uds_sock, &conn->uds_sock, uds_get_id(conn));
658 /* Connect the link socket to the new socket. */
659 link->uds_conn = conn;
660 link->uds_flags |= UDSF_CONNECTED;
663 * Connect the new socket to the link socket as well. The child
664 * socket should also inherit pretty much all settings from the
665 * listening socket, including the bind path and the listening socket's
666 * bind-time credentials.
668 conn->uds_conn = link;
669 conn->uds_flags = uds->uds_flags & (UDSF_PASSCRED | UDSF_CONNWAIT);
670 conn->uds_flags |= UDSF_CONNECTED;
671 conn->uds_pathlen = uds->uds_pathlen;
672 memcpy(conn->uds_path, uds->uds_path, (size_t)uds->uds_pathlen);
673 memcpy(&conn->uds_cred, &uds->uds_cred, sizeof(conn->uds_cred));
675 return OK;
679 * Connect a socket to a remote address.
681 static int
682 uds_connect(struct sock * sock, const struct sockaddr * addr,
683 socklen_t addr_len, endpoint_t user_endpt)
685 struct udssock *uds = (struct udssock *)sock;
686 struct udssock *link;
687 int r;
689 dprintf(("UDS: connect(%d)\n", uds_get_id(uds)));
691 /* For connection-oriented sockets, several state checks apply. */
692 if (uds_get_type(uds) != SOCK_DGRAM) {
693 if (uds_is_listening(uds))
694 return EOPNOTSUPP;
695 if (uds_is_connecting(uds))
696 return EALREADY;
697 if (uds_is_connected(uds))
698 return EISCONN;
699 /* Disconnected sockets may be reconnected, see below. */
700 } else {
702 * Connectionless sockets may be unconnected by providing an
703 * address with family AF_UNSPEC. Handle this case first here.
705 if (addr_len >= offsetof(struct sockaddr, sa_data) &&
706 addr->sa_family == AF_UNSPEC) {
708 * Reset this socket's previous connection to another
709 * socket, if any. Unconnecting has no effect on other
710 * sockets connected to this socket, though.
712 if (uds_has_link(uds))
713 uds_del_queue(uds->uds_link, uds);
715 return OK;
720 * Find the socket identified by the given address. If it exists at
721 * all, see if it is a proper match.
723 if ((r = uds_lookup(uds, addr, addr_len, user_endpt, &link)) != OK)
724 return r;
727 * Handle connectionless sockets first, in which case a connect links
728 * the socket to a send target and limits receipt to datagrams from
729 * that target. We actually point the socket to the peer socket,
730 * through uds_link. That also means that if the target socket
731 * disappears, we have to reset any sockets connected to it, in which
732 * case we return them to the unconnected state. In order to allow
733 * finding all sockets connected to a particular socket, we put all
734 * those sockets on their target's queue, hence why we use uds_link and
735 * not uds_conn. As mentioned before, we allow reconnecting without
736 * restrictions.
737 * TODO: see if reconnecting should clear a pending ECONNRESET.
739 * An important note: 'uds' and 'link' may actually be the same socket,
740 * if the caller chooses to connect a socket with itself!
742 if (uds_get_type(uds) == SOCK_DGRAM) {
743 /* Reconnecting to the same socket has no effect. */
744 if (uds_has_link(uds) && uds->uds_link == link)
745 return OK;
748 * If the intended target is linked to another socket, we
749 * refuse linking to it. Sending or receiving would never work
750 * anyway. Do allow a socket to link to itself after being
751 * linked to another socket. The error code is the same as in
752 * the sending code, borrowed from Linux.
754 if (uds != link && uds_has_link(link) && link->uds_link != uds)
755 return EPERM;
758 * Reset this socket's previous link to another socket, if any.
760 if (uds_has_link(uds))
761 uds_del_queue(uds->uds_link, uds);
764 * Reset any links to this socket, except for the one by
765 * the intended target. Sending or receiving would no longer
766 * work anyway. If the socket was linked to itself, clear its
767 * self-link without generating an ECONNRESET. If the socket
768 * is relinking to itself, reestablish the link after first
769 * clearing it.
771 uds_clear_queue(uds, (uds != link) ? link : NULL);
773 uds_add_queue(link, uds);
775 return OK;
779 * For connection-oriented sockets there is more to do. First, make
780 * sure that the peer is a listening socket, that it has not been shut
781 * down, and that its backlog is not already at the configured maximum.
783 if (!uds_is_listening(link))
784 return ECONNREFUSED;
786 if (uds_is_shutdown(link, SFL_SHUT_RD | SFL_SHUT_WR))
787 return ECONNREFUSED;
789 if (link->uds_queued >= link->uds_backlog)
790 return ECONNREFUSED;
793 * The behavior of connect(2) now depends on whether LOCAL_CONNWAIT is
794 * set on either the connecting or the listening socket. If it is not,
795 * the socket will be connected to a new as-yet invisible socket, which
796 * will be the one returned from accept(2) later. If it was, the
797 * socket will be put in the connecting state.
799 if (!((uds->uds_flags | link->uds_flags) & UDSF_CONNWAIT)) {
800 if ((r = uds_attach(link, uds)) != OK)
801 return r;
803 assert(uds_is_connected(uds));
804 } else {
806 * Disconnected sockets now stop being connected. Any pending
807 * data can still be received, though.
809 uds->uds_flags &= ~UDSF_CONNECTED;
811 r = SUSPEND;
814 /* Obtain credentials for the socket. */
815 uds_get_cred(uds, user_endpt);
817 /* Add the socket at the end of the listening socket's queue. */
818 uds_add_queue(link, uds);
820 assert(r != SUSPEND || uds_is_connecting(uds));
823 * Let an accept call handle the rest, which will in turn resume this
824 * connect call. The sockevent library ensures that this works even if
825 * the call is non-blocking.
827 sockevent_raise(&link->uds_sock, SEV_ACCEPT);
829 return r;
833 * Put a socket in listening mode.
835 static int
836 uds_listen(struct sock * sock, int backlog)
838 struct udssock *uds = (struct udssock *)sock;
840 /* The maximum backlog value must not exceed its field size. */
841 assert(SOMAXCONN <= USHRT_MAX);
843 dprintf(("UDS: listen(%d)\n", uds_get_id(uds)));
845 /* Only connection-oriented types may be put in listening mode. */
846 if (uds_get_type(uds) == SOCK_DGRAM)
847 return EOPNOTSUPP;
849 /* A connecting or connected socket may not listen. */
850 if (uds_is_connecting(uds) || uds_is_connected(uds))
851 return EINVAL;
853 /* POSIX says that this is now the appropriate error code here. */
854 if (!uds_is_bound(uds))
855 return EDESTADDRREQ;
858 * The socket is now entering the listening state. If it was
859 * previously disconnected, clear the connection flag.
861 uds->uds_flags &= ~UDSF_CONNECTED;
864 * We do not remove sockets from the backlog if it is now being dropped
865 * below the current number of queued sockets. We only refuse newly
866 * connecting sockets beyond the backlog size.
868 uds->uds_backlog = backlog;
870 return OK;
874 * Test whether an accept request would block. Return OK if a socket could be
875 * accepted, an appropriate error code if an accept call would fail instantly,
876 * or SUSPEND if the accept request would block waiting for a connection.
878 static int
879 uds_test_accept(struct sock * sock)
881 struct udssock *uds = (struct udssock *)sock;
884 * Ensure that the socket is in listening mode. If not, we must return
885 * the error code that is appropriate for this socket type.
887 if (uds_get_type(uds) == SOCK_DGRAM)
888 return EOPNOTSUPP;
889 if (!uds_is_listening(uds))
890 return EINVAL;
893 * If the socket has been shut down, new connections are no longer
894 * accepted and accept calls no longer block. This is not a POSIX
895 * requirement, but rather an application convenience feature.
897 if (uds->uds_queued == 0) {
898 if (uds_is_shutdown(uds, SFL_SHUT_RD | SFL_SHUT_WR))
899 return ECONNABORTED;
901 return SUSPEND;
904 return OK;
908 * Accept a connection on a listening socket, creating a new socket. On
909 * success, return the new socket identifier, with the new socket stored in
910 * 'newsockp'. Otherwise, return an error code.
912 static sockid_t
913 uds_accept(struct sock * sock, struct sockaddr * addr, socklen_t * addr_len,
914 endpoint_t user_endpt __unused, struct sock ** newsockp)
916 struct udssock *uds = (struct udssock *)sock;
917 struct udssock *link, *conn;
918 sockid_t r;
920 dprintf(("UDS: accept(%d)\n", uds_get_id(uds)));
922 if ((r = uds_test_accept(sock)) != OK)
923 return r;
926 * Take the first connecting socket off the listening queue.
928 assert(!TAILQ_EMPTY(&uds->uds_queue));
930 link = TAILQ_FIRST(&uds->uds_queue);
933 * Depending on the LOCAL_CONNWAIT setting at the time of connect(2),
934 * the socket may be connecting or connected. In the latter case, its
935 * attached socket is the socket we will return now. Otherwise we have
936 * to attach a socket first.
938 assert(uds_is_connecting(link) || uds_is_connected(link));
940 if (uds_is_connecting(link)) {
942 * Attach a new socket. If this fails, return the error but
943 * leave the connecting socket on the listening queue.
945 if ((r = uds_attach(uds, link)) != OK)
946 return r;
948 assert(uds_is_connected(link));
951 * Wake up blocked (connect, send, select) calls on the peer
952 * socket.
954 sockevent_raise(&link->uds_sock, SEV_CONNECT);
957 uds_del_queue(uds, link);
959 /* Return the peer socket's address to the caller. */
960 uds_make_addr(link->uds_path, link->uds_pathlen, addr, addr_len);
962 conn = link->uds_conn;
964 dprintf(("UDS: accept returns %d\n", uds_get_id(conn)));
967 * We already cloned the sock object, so return its ID but not a
968 * pointer to it. That tells libsockevent not to reinitialize it.
970 *newsockp = NULL;
971 return uds_get_id(conn);
975 * Set socket options.
977 static int
978 uds_setsockopt(struct sock * sock, int level, int name,
979 const struct sockdriver_data * data, socklen_t len)
981 struct udssock *uds = (struct udssock *)sock;
982 int r, val;
984 dprintf(("UDS: setsockopt(%d,%d,%d)\n", uds_get_id(uds), level, name));
986 switch (level) {
987 case SOL_SOCKET:
988 switch (name) {
989 case SO_SNDBUF:
990 case SO_RCVBUF:
992 * The send buffer size may not be changed because the
993 * buffer is the same as the other side's receive
994 * buffer, and what the other side is may vary from
995 * send call to send call. Changing the receive buffer
996 * size would disallow us from even accurately guessing
997 * the send buffer size in getsockopt calls. Therefore
998 * both are hardcoded and cannot actually be changed.
999 * In order to support applications that want at least
1000 * a certain minimum, we do accept requests to shrink
1001 * either buffer, but we ignore the given size.
1003 if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
1004 len)) != OK)
1005 return r;
1007 if (val <= 0 || (size_t)val > uds_io_buflen())
1008 return EINVAL;
1010 return OK; /* ignore new value */
1013 break;
1015 case UDSPROTO_UDS:
1016 switch (name) {
1017 case LOCAL_CREDS:
1018 if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
1019 len)) != OK)
1020 return r;
1022 if (val)
1023 uds->uds_flags |= UDSF_PASSCRED;
1024 else
1025 uds->uds_flags &= ~UDSF_PASSCRED;
1028 * In incredibly rare cases, disabling this flag may
1029 * allow blocked sends to be resumed, because suddenly
1030 * no room for the credentials is needed in the receive
1031 * buffer anymore.
1033 if (!val)
1034 sockevent_raise(&uds->uds_sock, SEV_SEND);
1036 return OK;
1038 case LOCAL_CONNWAIT:
1039 if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
1040 len)) != OK)
1041 return r;
1043 if (val)
1044 uds->uds_flags |= UDSF_CONNWAIT;
1045 else
1046 uds->uds_flags &= ~UDSF_CONNWAIT;
1049 * Changing the setting does not affect sockets that
1050 * are currently pending to be accepted. Therefore,
1051 * uds_accept() may have to deal with either case on a
1052 * socket-by-socket basis.
1054 return OK;
1056 case LOCAL_PEEREID:
1057 /* This option may be retrieved but not set. */
1058 return ENOPROTOOPT;
1061 break;
1064 return ENOPROTOOPT;
1068 * Retrieve socket options.
1070 static int
1071 uds_getsockopt(struct sock * sock, int level, int name,
1072 const struct sockdriver_data * data, socklen_t * len)
1074 struct udssock *uds = (struct udssock *)sock;
1075 int val;
1077 dprintf(("UDS: getsockopt(%d,%d,%d)\n", uds_get_id(uds), level, name));
1079 switch (level) {
1080 case SOL_SOCKET:
1081 switch (name) {
1082 case SO_SNDBUF:
1083 case SO_RCVBUF:
1084 /* See uds_setsockopt() for why this is static. */
1085 val = (int)uds_io_buflen();
1087 return sockdriver_copyout_opt(data, &val, sizeof(val),
1088 len);
1091 break;
1093 case UDSPROTO_UDS:
1094 switch (name) {
1095 case LOCAL_CREDS:
1096 val = !!(uds->uds_flags & UDSF_PASSCRED);
1098 return sockdriver_copyout_opt(data, &val, sizeof(val),
1099 len);
1101 case LOCAL_CONNWAIT:
1102 val = !!(uds->uds_flags & UDSF_CONNWAIT);
1104 return sockdriver_copyout_opt(data, &val, sizeof(val),
1105 len);
1107 case LOCAL_PEEREID:
1108 /* getpeereid(3) documents these error codes. */
1109 if (uds_get_type(uds) == SOCK_DGRAM)
1110 return EINVAL;
1111 if (!uds_is_connected(uds))
1112 return ENOTCONN;
1115 * This is a custom MINIX3 error, indicating that there
1116 * are no credentials to return. This could be due to
1117 * a failure to obtain them (which *should* not happen)
1118 * but also if the socket was bound while connected,
1119 * disconnected, and then reused as listening socket.
1121 if (uds->uds_conn->uds_cred.unp_pid == -1)
1122 return EINVAL;
1124 return sockdriver_copyout_opt(data,
1125 &uds->uds_conn->uds_cred,
1126 sizeof(uds->uds_conn->uds_cred), len);
1129 break;
1132 return ENOPROTOOPT;
1136 * Retrieve a socket's local address.
1138 static int
1139 uds_getsockname(struct sock * sock, struct sockaddr * addr,
1140 socklen_t * addr_len)
1142 struct udssock *uds = (struct udssock *)sock;
1144 dprintf(("UDS: getsockname(%d)\n", uds_get_id(uds)));
1146 uds_make_addr(uds->uds_path, uds->uds_pathlen, addr, addr_len);
1148 return OK;
1152 * Retrieve a socket's remote address.
1154 static int
1155 uds_getpeername(struct sock * sock, struct sockaddr * addr,
1156 socklen_t * addr_len)
1158 struct udssock *uds = (struct udssock *)sock;
1159 struct udssock *peer;
1161 dprintf(("UDS: getpeername(%d)\n", uds_get_id(uds)));
1164 * For disconnected sockets, we no longer have a peer socket and thus
1165 * also no peer address. Too bad, but NetBSD does the same.
1167 * For connecting sockets we could in fact return a peer address, but
1168 * POSIX says (and other platforms agree) that we should deny the call.
1170 peer = uds_get_peer(uds);
1172 if (peer == NULL || uds_is_connecting(uds))
1173 return ENOTCONN;
1175 uds_make_addr(peer->uds_path, peer->uds_pathlen, addr, addr_len);
1177 return OK;
1181 * Shut down socket send and receive operations. Note that 'flags' is a
1182 * bitwise mask with libsockevent's SFL_SHUT_{RD,WR} flags rather than the set
1183 * of SHUT_{RD,WR,RDWR} values from userland.
1185 static int
1186 uds_shutdown(struct sock * sock, unsigned int flags)
1188 struct udssock *uds = (struct udssock *)sock;
1189 struct udssock *conn;
1190 unsigned int mask;
1192 dprintf(("UDS: shutdown(%d,0x%x)\n", uds_get_id(uds), flags));
1195 * If we are shutting down the socket for reading, we can already close
1196 * any in-flight file descriptors associated with this socket.
1198 if (flags & SFL_SHUT_RD)
1199 uds_io_reset(uds);
1202 * A shutdown on this side of a connection may have an effect on
1203 * ongoing operations on the other side. Fire appropriate events.
1205 if (uds_is_connected(uds)) {
1206 assert(uds_get_type(uds) != SOCK_DGRAM);
1208 conn = uds->uds_conn;
1210 mask = 0;
1211 if (flags & SFL_SHUT_RD)
1212 mask |= SEV_SEND;
1213 if (flags & SFL_SHUT_WR)
1214 mask |= SEV_RECV;
1216 sockevent_raise(&conn->uds_sock, mask);
1219 return OK;
1223 * Close a socket.
1225 * The 'force' flag is unused because we need never wait for data to be sent,
1226 * since we keep all in-flight data on the receiver side.
1228 static int
1229 uds_close(struct sock * sock, int force __unused)
1231 struct udssock *uds = (struct udssock *)sock;
1233 dprintf(("UDS: close(%d)\n", uds_get_id(uds)));
1235 if (uds_get_type(uds) == SOCK_DGRAM) {
1236 /* If this socket is linked to a target, disconnect it. */
1237 if (uds_has_link(uds))
1238 uds_del_queue(uds->uds_link, uds);
1240 /* Reset all sockets linked to this socket as a target. */
1241 uds_clear_queue(uds, NULL);
1242 } else if (uds_is_listening(uds)) {
1244 * Abort all connecting sockets queued on this socket, and
1245 * break all connections for connected sockets queued on this
1246 * socket, freeing their peers.
1248 uds_clear_queue(uds, NULL);
1249 } else if (uds_has_link(uds)) {
1251 * This socket is connecting or connected while the other side
1252 * has not been accepted yet. Remove the socket from the
1253 * listening socket's queue, and if it was connected, get rid
1254 * of its peer socket altogether.
1256 assert(uds_is_listening(uds->uds_link));
1258 uds_del_queue(uds->uds_link, uds);
1260 if (uds_is_connected(uds))
1261 uds_disconnect(uds, TRUE /*was_linked*/);
1262 } else if (uds_is_connected(uds)) {
1264 * Decouple the peer socket from this socket, and possibly wake
1265 * up any pending operations on it. The socket remains marked
1266 * as connected, but will now be disconnected.
1268 uds_disconnect(uds, FALSE /*was_linked*/);
1271 if (uds_is_hashed(uds))
1272 udshash_del(uds);
1274 return OK;
1277 static const struct sockevent_ops uds_ops = {
1278 .sop_pair = uds_pair,
1279 .sop_bind = uds_bind,
1280 .sop_connect = uds_connect,
1281 .sop_listen = uds_listen,
1282 .sop_accept = uds_accept,
1283 .sop_test_accept = uds_test_accept,
1284 .sop_pre_send = uds_pre_send,
1285 .sop_send = uds_send,
1286 .sop_test_send = uds_test_send,
1287 .sop_pre_recv = uds_pre_recv,
1288 .sop_recv = uds_recv,
1289 .sop_test_recv = uds_test_recv,
1290 .sop_setsockopt = uds_setsockopt,
1291 .sop_getsockopt = uds_getsockopt,
1292 .sop_getsockname = uds_getsockname,
1293 .sop_getpeername = uds_getpeername,
1294 .sop_shutdown = uds_shutdown,
1295 .sop_close = uds_close,
1296 .sop_free = uds_free
1300 * Initialize the service.
1302 static int
1303 uds_init(int type __unused, sef_init_info_t * info __unused)
1305 unsigned int i;
1307 /* Initialize the list of free sockets. */
1308 TAILQ_INIT(&uds_freelist);
1310 for (i = 0; i < __arraycount(uds_array); i++) {
1311 uds_array[i].uds_flags = 0;
1313 TAILQ_INSERT_TAIL(&uds_freelist, &uds_array[i], uds_next);
1316 /* Initialize the file-to-socket hash table. */
1317 udshash_init();
1319 /* Initialize the input/output module. */
1320 uds_io_init();
1322 /* Initialize the status module. */
1323 uds_stat_init();
1325 /* Initialize the sockevent library. */
1326 sockevent_init(uds_socket);
1328 uds_in_use = 0;
1329 uds_running = TRUE;
1331 return OK;
1335 * Clean up before shutdown.
1337 static void
1338 uds_cleanup(void)
1341 /* Tell the status module to clean up. */
1342 uds_stat_cleanup();
1346 * The service has received a signal.
1348 static void
1349 uds_signal(int signo)
1352 /* Only check for the termination signal. Ignore anything else. */
1353 if (signo != SIGTERM)
1354 return;
1356 /* Exit only once all sockets have been closed. */
1357 uds_running = FALSE;
1359 if (uds_in_use == 0)
1360 sef_cancel();
1364 * Perform initialization using the System Event Framework (SEF).
1366 static void
1367 uds_startup(void)
1370 /* Register initialization callbacks. */
1371 sef_setcb_init_fresh(uds_init);
1373 /* Register signal callback. */
1374 sef_setcb_signal_handler(uds_signal);
1376 /* Let SEF perform startup. */
1377 sef_startup();
1381 * The UNIX Domain Sockets driver.
1384 main(void)
1386 message m;
1387 int r, ipc_status;
1389 /* Initialize the service. */
1390 uds_startup();
1392 /* Loop receiving and processing messages until instructed to stop. */
1393 while (uds_running || uds_in_use > 0) {
1394 if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK) {
1395 if (r == EINTR)
1396 continue; /* sef_cancel() was called */
1398 panic("UDS: sef_receive_status failed: %d", r);
1402 * Messages from the MIB service are (ultimately) for the
1403 * status module. Everything else is assumed to be a socket
1404 * request and passed to libsockevent, which will ignore
1405 * anything it does not recognize.
1407 if (m.m_source == MIB_PROC_NR)
1408 rmib_process(&m, ipc_status);
1409 else
1410 sockevent_process(&m, ipc_status);
1413 /* Clean up before graceful shutdown. */
1414 uds_cleanup();
1416 return EXIT_SUCCESS;