From 771fb1c367b0e2ee27b733c584cffc8529d0c250 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Tue, 9 Dec 2025 23:28:13 -0600 Subject: [PATCH] roken: Split up mini_inetd_addrinfo() To speed up tests/gss/check-gssmask we need to remove the `sleep 10` found there, and to do that we need to make the gssmask daemons use roken_detach_prep()/roken_detach_finish(), and to do that we need to split up mini_inetd_addrinfo(). This commit authored by Claude with human guidance and review. --- lib/roken/mini_inetd.c | 184 +++++++++++++++++++++++------------ lib/roken/roken.h.in | 6 ++ lib/roken/version-script.map | 2 + 3 files changed, 129 insertions(+), 63 deletions(-) diff --git a/lib/roken/mini_inetd.c b/lib/roken/mini_inetd.c index a9398f4fd..e0eef4d63 100644 --- a/lib/roken/mini_inetd.c +++ b/lib/roken/mini_inetd.c @@ -67,6 +67,124 @@ accept_it (rk_socket_t s, rk_socket_t *ret_socket) } } +/** + * Create listening sockets on specified addresses + * + * Creates and binds sockets for the specified addresses, then listens + * on them. Returns the listening sockets via \a ret_fds and the count + * via \a ret_num. The caller is responsible for freeing \a ret_fds. + * + * This function is intended for use with mini_inetd_accept() to allow + * signaling readiness between the listen and accept phases (e.g., for + * daemonization). + * + * @param[in] ai Addresses to listen on + * @param[out] ret_fds Receives array of listening sockets + * @param[out] ret_num Receives number of sockets in array + * + * @see mini_inetd_accept() + */ +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +mini_inetd_addrinfo_listen (struct addrinfo *ai, + rk_socket_t **ret_fds, + int *ret_num) +{ + struct addrinfo *a; + int nalloc, i; + rk_socket_t *fds; + + for (nalloc = 0, a = ai; a != NULL; a = a->ai_next) + ++nalloc; + + fds = malloc (nalloc * sizeof(*fds)); + if (fds == NULL) { + errx (1, "mini_inetd: out of memory"); + UNREACHABLE(return); + } + + for (i = 0, a = ai; a != NULL; a = a->ai_next) { + fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (rk_IS_BAD_SOCKET(fds[i])) + continue; + socket_set_reuseaddr (fds[i], 1); + socket_set_ipv6only(fds[i], 1); + if (rk_IS_SOCKET_ERROR(bind (fds[i], a->ai_addr, a->ai_addrlen))) { + warn ("bind af = %d", a->ai_family); + rk_closesocket(fds[i]); + fds[i] = rk_INVALID_SOCKET; + continue; + } + if (rk_IS_SOCKET_ERROR(listen (fds[i], SOMAXCONN))) { + warn ("listen af = %d", a->ai_family); + rk_closesocket(fds[i]); + fds[i] = rk_INVALID_SOCKET; + continue; + } + ++i; + } + if (i == 0) + errx (1, "no sockets"); + + *ret_fds = fds; + *ret_num = i; +} + +/** + * Accept a connection on listening sockets + * + * Waits for and accepts a connection on one of the listening sockets + * created by mini_inetd_addrinfo_listen(). On return, all listening + * sockets are closed and the \a fds array is freed. + * + * If the \a ret_socket parameter is \a NULL, on return STDIN and STDOUT + * will be connected to the accepted socket. If the \a ret_socket + * parameter is non-NULL, the accepted socket will be returned in + * *ret_socket and STDIN/STDOUT will be left unmodified. + * + * @param[in] fds Array of listening sockets (freed by this function) + * @param[in] num Number of sockets in array + * @param[out] ret_socket If non-NULL receives the accepted socket. + * + * @see mini_inetd_addrinfo_listen() + */ +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +mini_inetd_accept (rk_socket_t *fds, int num, rk_socket_t *ret_socket) +{ + int ret; + int i; + fd_set orig_read_set, read_set; + rk_socket_t max_fd = (rk_socket_t)-1; + + FD_ZERO(&orig_read_set); + + for (i = 0; i < num; ++i) { +#ifndef NO_LIMIT_FD_SETSIZE + if (fds[i] >= FD_SETSIZE) + errx (1, "fd too large"); +#endif + FD_SET(fds[i], &orig_read_set); + max_fd = max(max_fd, fds[i]); + } + + do { + read_set = orig_read_set; + + ret = select (max_fd + 1, &read_set, NULL, NULL, NULL); + if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) + err (1, "select"); + } while (ret <= 0); + + for (i = 0; i < num; ++i) + if (FD_ISSET (fds[i], &read_set)) { + accept_it (fds[i], ret_socket); + for (i = 0; i < num; ++i) + rk_closesocket(fds[i]); + free(fds); + return; + } + abort (); +} + /** * Listen on a specified addresses * @@ -88,71 +206,11 @@ accept_it (rk_socket_t s, rk_socket_t *ret_socket) ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL mini_inetd_addrinfo (struct addrinfo *ai, rk_socket_t *ret_socket) { - int ret; - struct addrinfo *a; - int n, nalloc, i; rk_socket_t *fds; - fd_set orig_read_set, read_set; - rk_socket_t max_fd = (rk_socket_t)-1; + int num; - for (nalloc = 0, a = ai; a != NULL; a = a->ai_next) - ++nalloc; - - fds = malloc (nalloc * sizeof(*fds)); - if (fds == NULL) { - errx (1, "mini_inetd: out of memory"); - UNREACHABLE(return); - } - - FD_ZERO(&orig_read_set); - - for (i = 0, a = ai; a != NULL; a = a->ai_next) { - fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (rk_IS_BAD_SOCKET(fds[i])) - continue; - socket_set_reuseaddr (fds[i], 1); - socket_set_ipv6only(fds[i], 1); - if (rk_IS_SOCKET_ERROR(bind (fds[i], a->ai_addr, a->ai_addrlen))) { - warn ("bind af = %d", a->ai_family); - rk_closesocket(fds[i]); - fds[i] = rk_INVALID_SOCKET; - continue; - } - if (rk_IS_SOCKET_ERROR(listen (fds[i], SOMAXCONN))) { - warn ("listen af = %d", a->ai_family); - rk_closesocket(fds[i]); - fds[i] = rk_INVALID_SOCKET; - continue; - } -#ifndef NO_LIMIT_FD_SETSIZE - if (fds[i] >= FD_SETSIZE) - errx (1, "fd too large"); -#endif - FD_SET(fds[i], &orig_read_set); - max_fd = max(max_fd, fds[i]); - ++i; - } - if (i == 0) - errx (1, "no sockets"); - n = i; - - do { - read_set = orig_read_set; - - ret = select (max_fd + 1, &read_set, NULL, NULL, NULL); - if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) - err (1, "select"); - } while (ret <= 0); - - for (i = 0; i < n; ++i) - if (FD_ISSET (fds[i], &read_set)) { - accept_it (fds[i], ret_socket); - for (i = 0; i < n; ++i) - rk_closesocket(fds[i]); - free(fds); - return; - } - abort (); + mini_inetd_addrinfo_listen(ai, &fds, &num); + mini_inetd_accept(fds, num, ret_socket); } /** diff --git a/lib/roken/roken.h.in b/lib/roken/roken.h.in index c72d259a3..2487515de 100644 --- a/lib/roken/roken.h.in +++ b/lib/roken/roken.h.in @@ -1197,6 +1197,12 @@ extern const char *__progname; ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL mini_inetd_addrinfo (struct addrinfo*, rk_socket_t *); +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +mini_inetd_addrinfo_listen (struct addrinfo *, rk_socket_t **, int *); + +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +mini_inetd_accept (rk_socket_t *, int, rk_socket_t *); + ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL mini_inetd (int, rk_socket_t *); diff --git a/lib/roken/version-script.map b/lib/roken/version-script.map index fd2b891f8..33adff512 100644 --- a/lib/roken/version-script.map +++ b/lib/roken/version-script.map @@ -20,7 +20,9 @@ HEIMDAL_ROKEN_2.0 { hex_encode; issuid; mini_inetd; + mini_inetd_accept; mini_inetd_addrinfo; + mini_inetd_addrinfo_listen; net_read; net_write; parse_bytes;