From 9c6b2929d8019dcc11935550bc3520ae39c2964e Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 30 Dec 2024 11:45:36 -0800 Subject: fixes #863 socket activation: for TCP and IPC (POSIX only) This introduces a new option "NNG_OPT_LISTEN_FD", understood by TCP, TLS, and (on POSIX systems) IPC. This option is used to pass a file descriptor or handle (Windows) that is already listening (ready for ACCEPT to be called). For TCP and TLS, the socket must be of type AF_INET or AF_INET6, and for IPC it must be of type AF_UNIX. --- src/platform/windows/win_tcplisten.c | 76 ++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'src/platform/windows') diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c index 0dd5ae16..91ecccb0 100644 --- a/src/platform/windows/win_tcplisten.c +++ b/src/platform/windows/win_tcplisten.c @@ -429,6 +429,75 @@ tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t) return (nni_copyout_int(port, buf, szp, t)); } +static int +tcp_listener_set_listen_fd(void *arg, const void *buf, size_t sz, nni_type t) +{ + tcp_listener *l = arg; + int fd; + SOCKADDR_STORAGE ss; + int len = sizeof(ss); + int rv; + + if ((rv = nni_copyin_int(&fd, buf, sz, 0, NNI_MAXINT, t)) != 0) { + return (rv); + } + + if (getsockname(fd, (void *) &ss, &len) != 0) { + return (nni_win_error(GetLastError())); + } + + if (((nni_win_sockaddr2nn(&l->sa, &ss, len)) != 0) || +#ifdef NNG_ENABLE_IPV6 + ((ss.ss_family != AF_INET) && (ss.ss_family != AF_INET6)) +#else + (ss.ss_family != AF_INET) +#endif + ) { + return (NNG_EADDRINVAL); + } + + nni_mtx_lock(&l->mtx); + if (l->started) { + nni_mtx_unlock(&l->mtx); + return (NNG_EBUSY); + } + if (l->closed) { + nni_mtx_unlock(&l->mtx); + return (NNG_ECLOSED); + } + + int yes = 1; + (void) setsockopt( + l->s, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(yes)); + + l->ss = ss; + l->s = (SOCKET) fd; + if ((rv = nni_win_io_register((HANDLE) l->s)) != 0) { + l->s = INVALID_SOCKET; + nni_mtx_unlock(&l->mtx); + return (rv); + } + l->started = true; + nni_mtx_unlock(&l->mtx); + return (0); +} + +#ifdef NNG_TEST_LIB +// this is readable only for test code -- user code should never rely on this +static int +tcp_listener_get_listen_fd(void *arg, void *buf, size_t *szp, nni_type t) +{ + int rv; + tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); + NNI_ASSERT(l->started); + NNI_ASSERT(!l->closed); + rv = nni_copyout_int((int) l->s, buf, szp, t); + nni_mtx_unlock(&l->mtx); + return (rv); +} +#endif + static const nni_option tcp_listener_options[] = { { .o_name = NNG_OPT_LOCADDR, @@ -448,6 +517,13 @@ static const nni_option tcp_listener_options[] = { .o_name = NNG_OPT_TCP_BOUND_PORT, .o_get = tcp_listener_get_port, }, + { + .o_name = NNG_OPT_LISTEN_FD, + .o_set = tcp_listener_set_listen_fd, +#ifdef NNG_TEST_LIB + .o_get = tcp_listener_get_listen_fd, +#endif + }, { .o_name = NULL, }, -- cgit v1.2.3-70-g09d2