diff options
| author | Garrett D'Amore <garrett@damore.org> | 2024-12-30 11:45:36 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-12-30 12:12:07 -0800 |
| commit | 9c6b2929d8019dcc11935550bc3520ae39c2964e (patch) | |
| tree | c8311a91c02e7f78dbc8c26d8456b373ef33b5f4 /src/platform/windows | |
| parent | 60c9c1c4054a5dbb3c1cad2068e1a793789618ff (diff) | |
| download | nng-9c6b2929d8019dcc11935550bc3520ae39c2964e.tar.gz nng-9c6b2929d8019dcc11935550bc3520ae39c2964e.tar.bz2 nng-9c6b2929d8019dcc11935550bc3520ae39c2964e.zip | |
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.
Diffstat (limited to 'src/platform/windows')
| -rw-r--r-- | src/platform/windows/win_tcplisten.c | 76 |
1 files changed, 76 insertions, 0 deletions
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, @@ -449,6 +518,13 @@ static const nni_option tcp_listener_options[] = { .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, }, }; |
