From b6d8f8b720a8ae8787576c107ebdc3b283fd7c65 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 25 Dec 2023 17:41:34 -0800 Subject: [PATCH] Create nng_socket_pair --- include/nng/supplemental/util/platform.h | 7 +++++ src/core/platform.h | 17 +++++++++-- src/platform/posix/CMakeLists.txt | 4 ++- src/platform/posix/posix_socketpair.c | 37 ++++++++++++++++++++++++ src/platform/windows/CMakeLists.txt | 1 + src/platform/windows/win_socketpair.c | 37 ++++++++++++++++++++++++ src/sp/transport/fdconn/fdc_test.c | 31 ++++---------------- src/supplemental/util/platform.c | 6 ++++ 8 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 src/platform/posix/posix_socketpair.c create mode 100644 src/platform/windows/win_socketpair.c diff --git a/include/nng/supplemental/util/platform.h b/include/nng/supplemental/util/platform.h index feca858ad..f98bc176b 100644 --- a/include/nng/supplemental/util/platform.h +++ b/include/nng/supplemental/util/platform.h @@ -104,6 +104,13 @@ NNG_DECL void nng_cv_wake1(nng_cv *); // nng_random returns a "strong" (cryptographic sense) random number. NNG_DECL uint32_t nng_random(void); +// nng_socket_pair is used to create a bound pair of file descriptors +// typically using the socketpair() call. The descriptors are backed +// by reliable, bidirectional, byte streams. This will return NNG_ENOTSUP +// if the platform lacks support for this. The argument is a pointer +// to an array of file descriptors (or HANDLES or similar). +NNG_DECL int nng_socket_pair(int *); + #ifdef __cplusplus } #endif diff --git a/src/core/platform.h b/src/core/platform.h index 897599219..7da9c57af 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -386,9 +386,9 @@ extern int nni_ipc_listener_alloc(nng_stream_listener **, const nng_url *); typedef struct nni_plat_udp nni_plat_udp; // nni_plat_udp_open initializes a UDP socket, binding to the local -// address specified specified in the AIO. The remote address is +// address specified in the AIO. The remote address is // not used. The resulting nni_plat_udp structure is returned in the -// the aio's a_pipe. +// aio's a_pipe. extern int nni_plat_udp_open(nni_plat_udp **, nni_sockaddr *); // nni_plat_udp_close closes the underlying UDP socket. @@ -434,6 +434,19 @@ extern void nni_plat_pipe_close(int, int); extern int nni_plat_udp_sockname(nni_plat_udp *, nni_sockaddr *); +// nni_socket_pair is used to create a socket pair using socketpair() +// on POSIX systems. (Windows might provide a similar solution, using +// AF_UNIX at some point, in which case the arguments will actually be +// an array of HANDLEs.) If not supported, this returns NNG_ENOTSUP. +// +// This API can only create a pair of open file descriptors, suitable for use +// with the fdconn transport, each bound to the other. The transport must be +// a bidirectional reliable byte stream. This should be suitable for use +// in APIs to transport file descriptors, or across a fork/exec boundary (so +// that child processes may use these with fdconn to inherit a socket that is +// connected to the parent.) +extern int nni_socket_pair(int *); + // // File/Store Support // diff --git a/src/platform/posix/CMakeLists.txt b/src/platform/posix/CMakeLists.txt index 793c1a97d..b9ea443b4 100644 --- a/src/platform/posix/CMakeLists.txt +++ b/src/platform/posix/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2020 Staysail Systems, Inc. +# Copyright 2023 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this @@ -61,6 +61,7 @@ if (NNG_PLATFORM_POSIX) nng_check_sym(LOCAL_PEERPID sys/un.h NNG_HAVE_LOCALPEERPID) nng_check_sym(getpeerucred ucred.h NNG_HAVE_GETPEERUCRED) nng_check_sym(atomic_flag_test_and_set stdatomic.h NNG_HAVE_STDATOMIC) + nng_check_sym(socketpair sys/socket.h NNG_HAVE_SOCKETPAIR) nng_sources( posix_impl.h @@ -82,6 +83,7 @@ if (NNG_PLATFORM_POSIX) posix_pipe.c posix_resolv_gai.c posix_sockaddr.c + posix_socketpair.c posix_tcpconn.c posix_tcpdial.c posix_tcplisten.c diff --git a/src/platform/posix/posix_socketpair.c b/src/platform/posix/posix_socketpair.c new file mode 100644 index 000000000..c2641a004 --- /dev/null +++ b/src/platform/posix/posix_socketpair.c @@ -0,0 +1,37 @@ +// +// Copyright 2023 Staysail Systems, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include "core/nng_impl.h" + +#ifdef NNG_HAVE_SOCKETPAIR +// This provides an implementation of socketpair(), which is supposed +// to be present on XPG6 and newer. This trivial implementation +// only supports SOCK_STREAM over AF_UNIX. Which is sufficient for +// most purposes. The fds array should point to an int[2]. +#include +#include + +int +nni_socket_pair(int *fds) +{ + int rv; + rv = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if (rv != 0) { + return (nni_plat_errno(errno)); + } + + return (0); +} +#else +int +nni_socket_pair(int *fds) +{ + return (NNG_ENOTSUP); +} +#endif \ No newline at end of file diff --git a/src/platform/windows/CMakeLists.txt b/src/platform/windows/CMakeLists.txt index d1d158e09..adf67ebde 100644 --- a/src/platform/windows/CMakeLists.txt +++ b/src/platform/windows/CMakeLists.txt @@ -39,6 +39,7 @@ if (NNG_PLATFORM_WINDOWS) win_rand.c win_resolv.c win_sockaddr.c + win_socketpair.c win_tcp.c win_tcpconn.c win_tcpdial.c diff --git a/src/platform/windows/win_socketpair.c b/src/platform/windows/win_socketpair.c new file mode 100644 index 000000000..6d5241e21 --- /dev/null +++ b/src/platform/windows/win_socketpair.c @@ -0,0 +1,37 @@ +// +// Copyright 2023 Staysail Systems, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include "core/nng_impl.h" + + +#ifdef NNG_HAVE_SOCKETPAIR_TODO +// TODO: Windows lacks socketpair. We can emulate it with an explcit +// implementation based on AF_UNIX. + +#include +#include + +int +nni_socket_pair(int *fds) +{ + int rv; + rv = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if (rv != 0) { + return (nni_plat_errno(errno)); + } + + return (0); +} +#else +int +nni_socket_pair(int *fds) +{ + return (NNG_ENOTSUP); +} +#endif \ No newline at end of file diff --git a/src/sp/transport/fdconn/fdc_test.c b/src/sp/transport/fdconn/fdc_test.c index 6f3511195..3683357df 100644 --- a/src/sp/transport/fdconn/fdc_test.c +++ b/src/sp/transport/fdconn/fdc_test.c @@ -23,27 +23,6 @@ test_fdc_connect_fail(void) NUTS_CLOSE(s); } -void -test_tcp_local_address_connect(void) -{ - - nng_socket s1; - nng_socket s2; - char addr[NNG_MAXADDRLEN]; - uint16_t port; - - NUTS_OPEN(s1); - NUTS_OPEN(s2); - port = nuts_next_port(); - (void) snprintf(addr, sizeof(addr), "tcp://127.0.0.1:%u", port); - NUTS_PASS(nng_listen(s1, addr, NULL, 0)); - (void) snprintf( - addr, sizeof(addr), "tcp://127.0.0.1;127.0.0.1:%u", port); - NUTS_PASS(nng_dial(s2, addr, NULL, 0)); - NUTS_CLOSE(s2); - NUTS_CLOSE(s1); -} - void test_fdc_malformed_address(void) { @@ -64,7 +43,6 @@ test_fdc_listen(void) NUTS_CLOSE(s1); } -#include void test_fdc_accept(void) { @@ -72,7 +50,7 @@ test_fdc_accept(void) nng_listener l; int fds[2]; - NUTS_PASS(socketpair(PF_UNIX, SOCK_STREAM, 0, fds)); + NUTS_PASS(nng_socket_pair(fds)); // make sure we won't have to deal with SIGPIPE - EPIPE is better signal(SIGPIPE, SIG_IGN); NUTS_OPEN(s1); @@ -93,7 +71,7 @@ test_fdc_exchange(void) nng_listener l1, l2; int fds[2]; - NUTS_PASS(socketpair(PF_UNIX, SOCK_STREAM, 0, fds)); + NUTS_PASS(nng_socket_pair(fds)); // make sure we won't have to deal with SIGPIPE - EPIPE is better signal(SIGPIPE, SIG_IGN); NUTS_OPEN(s1); @@ -127,7 +105,7 @@ test_fdc_recv_max(void) size_t sz; int fds[2]; - NUTS_PASS(socketpair(PF_UNIX, SOCK_STREAM, 0, fds)); + NUTS_PASS(nng_socket_pair(fds)); NUTS_OPEN(s0); NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 100)); @@ -157,11 +135,12 @@ NUTS_TESTS = { { "fdc connect fail", test_fdc_connect_fail }, { "fdc malformed address", test_fdc_malformed_address }, +#ifdef NNG_HAVE_SOCKETPAIR { "fdc listen", test_fdc_listen }, { "fdc accept", test_fdc_accept }, { "fdc exchange", test_fdc_exchange }, { "fdc recv max", test_fdc_recv_max }, +#endif - // { "fdc recv max", test_tcp_recv_max }, { NULL, NULL }, }; \ No newline at end of file diff --git a/src/supplemental/util/platform.c b/src/supplemental/util/platform.c index ddc2d0889..99daaef64 100644 --- a/src/supplemental/util/platform.c +++ b/src/supplemental/util/platform.c @@ -164,3 +164,9 @@ nng_random(void) (void) nni_init(); return (nni_random()); } + +int +nng_socket_pair(int *fds) +{ + return (nni_socket_pair(fds)); +} \ No newline at end of file