aboutsummaryrefslogtreecommitdiff
path: root/src/platform/windows
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-12-30 11:45:36 -0800
committerGarrett D'Amore <garrett@damore.org>2024-12-30 12:12:07 -0800
commit9c6b2929d8019dcc11935550bc3520ae39c2964e (patch)
treec8311a91c02e7f78dbc8c26d8456b373ef33b5f4 /src/platform/windows
parent60c9c1c4054a5dbb3c1cad2068e1a793789618ff (diff)
downloadnng-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.c76
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,
},
};