From f07fbf75c065fd7f351e0bc90ab0a42c33416fb2 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Fri, 29 Dec 2023 13:15:29 -0800 Subject: [PATCH] Added peer ID support to sock fd. --- docs/man/CMakeLists.txt | 2 + docs/man/nng_ipc.7.adoc | 10 +- docs/man/nng_ipc_options.5.adoc | 64 ++++-------- docs/man/nng_options.5.adoc | 64 +++++++++--- docs/man/nng_socket.7.adoc | 3 +- include/nng/nng.h | 16 ++- src/core/sockfd.c | 13 +++ src/platform/posix/CMakeLists.txt | 1 + src/platform/posix/posix_peerid.c | 122 +++++++++++++++++++++++ src/platform/posix/posix_peerid.h | 26 +++++ src/platform/posix/posix_sockfd.c | 136 +++++++++++++++++++++++--- src/sp/transport/socket/sockfd_test.c | 130 ++++++++++++++++++++++-- 12 files changed, 494 insertions(+), 93 deletions(-) create mode 100644 src/platform/posix/posix_peerid.c create mode 100644 src/platform/posix/posix_peerid.h diff --git a/docs/man/CMakeLists.txt b/docs/man/CMakeLists.txt index a33d4ee8d..17d43c8ef 100644 --- a/docs/man/CMakeLists.txt +++ b/docs/man/CMakeLists.txt @@ -302,6 +302,7 @@ if (NNG_ENABLE_DOC) nng_mtx_unlock nng_opts_parse nng_random + nng_socket_pair nng_thread_create nng_thread_destroy nng_thread_set_name @@ -388,6 +389,7 @@ if (NNG_ENABLE_DOC) nng_rep nng_req nng_respondent + nng_socket nng_sub nng_surveyor nng_tcp diff --git a/docs/man/nng_ipc.7.adoc b/docs/man/nng_ipc.7.adoc index 856a00acc..c085e4d20 100644 --- a/docs/man/nng_ipc.7.adoc +++ b/docs/man/nng_ipc.7.adoc @@ -1,6 +1,6 @@ = nng_ipc(7) // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -107,14 +107,14 @@ except for abstract sockets, which use xref:nng_sockaddr_abstract.5.adoc[`nng_so The following transport options are supported by this transport, where supported by the underlying platform. -* xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_PEER_GID[`NNG_OPT_IPC_PEER_GID`] -* xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_PEER_PID[`NNG_OPT_IPC_PEER_PID`] -* xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_PEER_UID[`NNG_OPT_IPC_PEER_UID`] -* xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_PEER_ZONEID[`NNG_OPT_IPC_PEER_ZONEID`] * xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_PERMISSIONS[`NNG_OPT_IPC_PERMISSIONS`] * xref:nng_ipc_options.5.adoc#NNG_OPT_IPC_SECURITY_DESCRIPTOR[`NNG_OPT_IPC_SECURITY_DESCRIPTOR`] * xref:nng_options.5.adoc#NNG_OPT_LOCADDR[`NNG_OPT_LOCADDR`] * xref:nng_options.5.adoc#NNG_OPT_REMADDR[`NNG_OPT_REMADDR`] +* xref:nng_options.5.adoc#NNG_OPT_PEER_GID[`NNG_OPT_PEER_GID`] +* xref:nng_options.5.adoc#NNG_OPT_PEER_PID[`NNG_OPT_PEER_PID`] +* xref:nng_options.5.adoc#NNG_OPT_PEER_UID[`NNG_OPT_PEER_UID`] +* xref:nng_options.5.adoc#NNG_OPT_PEER_ZONEID[`NNG_OPT_PEER_ZONEID`] * xref:nng_options.5.adoc#NNG_OPT_URL[`NNG_OPT_URL`] == SEE ALSO diff --git a/docs/man/nng_ipc_options.5.adoc b/docs/man/nng_ipc_options.5.adoc index 72f383eab..516fbe809 100644 --- a/docs/man/nng_ipc_options.5.adoc +++ b/docs/man/nng_ipc_options.5.adoc @@ -1,6 +1,6 @@ = nng_ipc_options(5) // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -43,43 +43,9 @@ have other access restrictions. An attempt has been made to include details about such restrictions in the description of the option. -NOTE: The availability of any of the following options is platform-specific, +NOTE: The availability of the following options is platform-specific, as the implementations of IPC are quite different on Windows and POSIX systems. -=== IPC Options - -[[NNG_OPT_IPC_PEER_GID]]((`NNG_OPT_IPC_PEER_GID`)):: -(`uint64_t`) -This read-only option provides a connected peer's primary -group id. -This is the effective group id of the peer when either the underlying -`listen()` or `connect()` calls were made, and is not forgeable. -This option is generally only available on POSIX systems. - -[[NNG_OPT_IPC_PEER_PID]]((`NNG_OPT_IPC_PEER_PID`)):: -(`uint64_t`) -This read-only option provides the the process id -of the connected peer. -This option is only available on Windows, Linux, and certain other systems. -+ -NOTE: Applications should not assume that the process ID does not change, -as it is possible (although unsupported!) for a nefarious process to pass a -file descriptor between processes. -However, it is not possible for a nefarious application to forge the identity -of a well-behaved one using this method. - -[[NNG_OPT_IPC_PEER_UID]]((`NNG_OPT_IPC_PEER_UID`)):: -(`uint64_t`) -This read-only option provides a connected peer's user id. -This is the effective user id of the peer when either the underlying -`listen()` or `connect()` calls were made, and is not forgeable. -This option is generally only available on POSIX systems. - -[[NNG_OPT_IPC_PEER_ZONEID]]((`NNG_OPT_IPC_PEER_ZONEID`)):: -(`uint64_t`) -This read-only option provides a connected peer's the zone id. -Zones (and this option) are only supported on Solaris and illumos systems. - [[NNG_OPT_IPC_PERMISSIONS]]((`NNG_OPT_IPC_PERMISSIONS`)):: (`int`) This write-only option may be applied to a listener to configure the @@ -115,10 +81,18 @@ named pipe. The value is a pointer, `PSECURITY_DESCRIPTOR`, and may only be applied to listeners that have not been started yet. +=== Common Platform Specific Options + +The following options are supported by this transport when the underlying platform supports them: + +* xref:nng_options.5.adoc#NNG_OPT_PEER_GID[`NNG_OPT_PEER_GID`] (also available as `NNG_OPT_IPC_PEER_GID`) +* xref:nng_options.5.adoc#NNG_OPT_PEER_PID[`NNG_OPT_PEER_PID`] (also available as `NNG_OPT_IPC_PEER_PID`) +* xref:nng_options.5.adoc#NNG_OPT_PEER_UID[`NNG_OPT_PEER_UID`] (also available as `NNG_OPT_IPC_PEER_UID`) +* xref:nng_options.5.adoc#NNG_OPT_PEER_ZONEID[`NNG_OPT_PEER_ZONEID`] (also available as `NNG_OPT_IPC_PEER_ZONEID`) + === Inherited Options -Generally, the following option values are also available for TLS objects, -when appropriate for the context: +Generally, the following option values are also available when appropriate for the context: * xref:nng_options.5.adoc#NNG_OPT_LOCADDR[`NNG_OPT_LOCADDR`] * xref:nng_options.5.adoc#NNG_OPT_REMADDR[`NNG_OPT_REMADDR`] @@ -126,11 +100,11 @@ when appropriate for the context: == SEE ALSO [.text-left] -xref:nng_ipc_dialer_getopt.3ipc.adoc[nng_ipc_dialer_getopt(3ipc)], -xref:nng_ipc_dialer_setopt.3ipc.adoc[nng_ipc_dialer_setopt(3ipc)], -xref:nng_ipc_getopt.3ipc.adoc[nng_ipc_getopt(3ipc)], -xref:nng_ipc_listener_getopt.3ipc.adoc[nng_ipc_listener_getopt(3ipc)], -xref:nng_ipc_listener_setopt.3ipc.adoc[nng_ipc_listener_setopt(3ipc)], -xref:nng_ipc_setopt.3ipc.adoc[nng_ipc_setopt(3ipc)], +xref:nng_dialer_get.3.adoc[nng_dialer_get(3)], +xref:nng_dialer_set.3.adoc[nng_dialer_set(3)], +xref:nng_listener_get.3.adoc[nng_listener_get(3)], +xref:nng_listener_set.3.adoc[nng_listener_set(3)], +xref:nng_pipe_get.3.adoc[nng_pipe_get(3)], xref:nng_options.5.adoc[nng_options(5)] -xref:nng.7.adoc[nng(7)] +xref:nng.7.adoc[nng(7)], +xref:nng_ipc.7.adoc[nng_ipc(7)] diff --git a/docs/man/nng_options.5.adoc b/docs/man/nng_options.5.adoc index e4e5124d4..dd971f9f9 100644 --- a/docs/man/nng_options.5.adoc +++ b/docs/man/nng_options.5.adoc @@ -1,6 +1,6 @@ = nng_options(5) // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -39,6 +39,10 @@ nng_options - socket, dialer, listener, and pipe options #define NNG_OPT_RECVMAXSZ "recv-size-max" #define NNG_OPT_RECONNMINT "reconnect-time-min" #define NNG_OPT_RECONNMAXT "reconnect-time-max" +#define NNG_OPT_PEER_GID "ipc:peer-gid" +#define NNG_OPT_PEER_PID "ipc:peer-pid" +#define NNG_OPT_PEER_UID "ipc:peer-uid" +#define NNG_OPT_PEER_ZONEID "ipc:peer-zoneid" ---- == DESCRIPTION @@ -328,27 +332,59 @@ This read-only option is used to obtain the 16-bit number for the socket's proto This read-only option is used to obtain the 16-bit number of the peer protocol for the socket. -[[NNG_OPT_PROTONAME]] -((`NNG_OPT_PROTONAME`)):: -(string) -This read-only option is used to obtain the name of the socket's protocol. +[[NNG_OPT_PEER_GID]] +((`NNG_OPT_PEER_GID`)):: +(`uint64_t`) +This read-only option provides a connected peer's primary group id, when known. +This is the effective group id of the peer when either the underlying +`listen()` or `connect()` calls were made, and is not forgeable. +This option is generally only available on POSIX systems, only on certain transports. + +[[NNG_OPT_PEER_PID]] +((`NNG_OPT_PEER_PID`)):: +(`uint64_t`) +This read-only option provides the process id of the connected peer, when known. +This option is only available on certain platforms and transports. ++ +NOTE: Applications should not assume that the process ID does not change, +as it may be possible for a process to pass a file descriptor between processes. +However, it is not possible for a nefarious application to forge the identity +of a well-behaved one using this method. + +[[NNG_OPT_PEER_UID]] +((`NNG_OPT_PEER_UID`)):: +(`uint64_t`) +This read-only option provides a connected peer's user id. +This is the effective user id of the peer when either the underlying +`listen()` or `connect()` calls were made, and cannot be forged. +This option is generally only available on POSIX systems, on certain transports. + +[[NNG_OPT_PEER_ZONEID]] +((`NNG_OPT_PEER_ZONEID`)):: +(`uint64_t`) +This read-only option provides a connected peer's the zone id. +Zones (and this option) are only supported on Solaris and illumos systems, on select transports. [[NNG_OPT_PEERNAME]] ((`NNG_OPT_PEERNAME`)):: (string) -This read-only option is used to obtain the name of the peer protocol for -the socket. +This read-only option is used to obtain the name of the peer protocol for the socket. + +[[NNG_OPT_PROTONAME]] +((`NNG_OPT_PROTONAME`)):: +(string) +This read-only option is used to obtain the name of the socket's protocol. == SEE ALSO [.text-left] -xref:nng_dialer_getopt.3.adoc[nng_dialer_getopt(3)], -xref:nng_dialer_setopt.3.adoc[nng_dialer_setopt(3)], -xref:nng_getopt.3.adoc[nng_getopt(3)], -xref:nng_listener_getopt.3.adoc[nng_listener_getopt(3)], -xref:nng_listener_setopt.3.adoc[nng_listener_setopt(3)], -xref:nng_pipe_getopt.3.adoc[nng_pipe_getopt(3)], -xref:nng_setopt.3.adoc[nng_setopt(3)], +xref:nng_dialer_get.3.adoc[nng_dialer_get(3)], +xref:nng_dialer_set.3.adoc[nng_dialer_set(3)], +xref:nng_listener_get.3.adoc[nng_listener_get(3)], +xref:nng_listener_set.3.adoc[nng_listener_set(3)], +xref:nng_pipe_get.3.adoc[nng_pipe_get(3)], +xref:nng_socket_get.3.adoc[nng_socket_get(3)], +xref:nng_socket_set.3.adoc[nng_socket_set(3)], xref:nng_ipc_options.5.adoc[nng_ipc_options(5)], xref:nng_tcp_options.5.adoc[nng_tcp_options(5)], xref:nng_tls_options.5.adoc[nng_tls_options(5)], diff --git a/docs/man/nng_socket.7.adoc b/docs/man/nng_socket.7.adoc index 630076a18..e73b599a7 100644 --- a/docs/man/nng_socket.7.adoc +++ b/docs/man/nng_socket.7.adoc @@ -43,7 +43,8 @@ This transport uses the URL `socket://`, without further qualification. === Socket Address -Not documented. +The socket address will be of family `NNG_AF_UNSPEC`. +There are no further socket details available. === Transport Options diff --git a/include/nng/nng.h b/include/nng/nng.h index 57e8d847e..06733d775 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -811,24 +811,30 @@ NNG_DECL nng_listener nng_pipe_listener(nng_pipe); // this for security. #define NNG_OPT_IPC_PERMISSIONS "ipc:permissions" +// IPC peer options may also be used in some cases with other socket types. + // Peer UID. This is only available on POSIX style systems. -#define NNG_OPT_IPC_PEER_UID "ipc:peer-uid" +#define NNG_OPT_PEER_UID "ipc:peer-uid" +#define NNG_OPT_IPC_PEER_UID NNG_OPT_PEER_UID // Peer GID (primary group). This is only available on POSIX style systems. -#define NNG_OPT_IPC_PEER_GID "ipc:peer-gid" +#define NNG_OPT_PEER_GID "ipc:peer-gid" +#define NNG_OPT_IPC_PEER_GID NNG_OPT_PEER_GID // Peer process ID. Available on Windows, Linux, and SunOS. -// In theory we could obtain this with the first message sent, +// In theory, we could obtain this with the first message sent, // but we have elected not to do this for now. (Nice RFE for a FreeBSD // guru though.) -#define NNG_OPT_IPC_PEER_PID "ipc:peer-pid" +#define NNG_OPT_PEER_PID "ipc:peer-pid" +#define NNG_OPT_IPC_PEER_PID NNG_OPT_PEER_PID // Peer Zone ID. Only on SunOS systems. (Linux containers have no // definable kernel identity; they are a user-land fabrication made up // from various pieces of different namespaces. FreeBSD does have // something called JailIDs, but it isn't obvious how to determine this, // or even if processes can use IPC across jail boundaries.) -#define NNG_OPT_IPC_PEER_ZONEID "ipc:peer-zoneid" +#define NNG_OPT_PEER_ZONEID "ipc:peer-zoneid" +#define NNG_OPT_IPC_PEER_ZONEID NNG_OPT_PEER_ZONEID // WebSocket Options. diff --git a/src/core/sockfd.c b/src/core/sockfd.c index 42a41e5e9..1b4dbc1d7 100644 --- a/src/core/sockfd.c +++ b/src/core/sockfd.c @@ -165,11 +165,24 @@ sfd_listener_set_fd(void *arg, const void *buf, size_t sz, nni_type t) return (0); } +static int +sfd_listener_get_addr(void *arg, void *buf, size_t *szp, nni_type t) +{ + NNI_ARG_UNUSED(arg); + nng_sockaddr sa; + sa.s_family = NNG_AF_UNSPEC; + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + static const nni_option sfd_listener_options[] = { { .o_name = NNG_OPT_SOCKET_FD, .o_set = sfd_listener_set_fd, }, + { + .o_name = NNG_OPT_LOCADDR, + .o_get = sfd_listener_get_addr, + }, { .o_name = NULL, }, diff --git a/src/platform/posix/CMakeLists.txt b/src/platform/posix/CMakeLists.txt index 0a88419e9..b8e3782ea 100644 --- a/src/platform/posix/CMakeLists.txt +++ b/src/platform/posix/CMakeLists.txt @@ -79,6 +79,7 @@ if (NNG_PLATFORM_POSIX) posix_ipcconn.c posix_ipcdial.c posix_ipclisten.c + posix_peerid.c posix_pipe.c posix_resolv_gai.c posix_sockaddr.c diff --git a/src/platform/posix/posix_peerid.c b/src/platform/posix/posix_peerid.c new file mode 100644 index 000000000..e0020150c --- /dev/null +++ b/src/platform/posix/posix_peerid.c @@ -0,0 +1,122 @@ +// +// Copyright 2023 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// 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" + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(NNG_HAVE_GETPEERUCRED) +#include +#elif defined(NNG_HAVE_LOCALPEERCRED) || defined(NNG_HAVE_SOCKPEERCRED) +#include +#endif +#if defined(NNG_HAVE_GETPEEREID) +#include +#include +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +#ifndef SOL_LOCAL +#define SOL_LOCAL 0 +#endif + + +int +nni_posix_peerid(int fd, uint64_t *euid, uint64_t *egid, uint64_t *prid, + uint64_t *znid) +{ +#if defined(NNG_HAVE_GETPEEREID) && !defined(NNG_HAVE_LOCALPEERCRED) + uid_t uid; + gid_t gid; + + if (getpeereid(fd, &uid, &gid) != 0) { + return (nni_plat_errno(errno)); + } + *euid = uid; + *egid = gid; + *prid = (uint64_t) -1; + *znid = (uint64_t) -1; + return (0); +#elif defined(NNG_HAVE_GETPEERUCRED) + ucred_t *ucp = NULL; + if (getpeerucred(fd, &ucp) != 0) { + return (nni_plat_errno(errno)); + } + *euid = ucred_geteuid(ucp); + *egid = ucred_getegid(ucp); + *prid = ucred_getpid(ucp); + *znid = ucred_getzoneid(ucp); + ucred_free(ucp); + return (0); +#elif defined(NNG_HAVE_SOCKPEERCRED) + struct sockpeercred uc; + socklen_t len = sizeof(uc); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) != 0) { + return (nni_plat_errno(errno)); + } + *euid = uc.uid; + *egid = uc.gid; + *prid = uc.pid; + *znid = (uint64_t) -1; + return (0); +#elif defined(NNG_HAVE_SOPEERCRED) + struct ucred uc; + socklen_t len = sizeof(uc); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) != 0) { + return (nni_plat_errno(errno)); + } + *euid = uc.uid; + *egid = uc.gid; + *prid = uc.pid; + *znid = (uint64_t) -1; + return (0); +#elif defined(NNG_HAVE_LOCALPEERCRED) + struct xucred xu; + socklen_t len = sizeof(xu); + if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERCRED, &xu, &len) != 0) { + return (nni_plat_errno(errno)); + } + *euid = xu.cr_uid; + *egid = xu.cr_gid; + *prid = (uint64_t) -1; + *znid = (uint64_t) -1; +#if defined(NNG_HAVE_LOCALPEERPID) // documented on macOS since 10.8 + { + pid_t pid; + if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, &pid, &len) == + 0) { + *prid = (uint64_t) pid; + } + } +#endif // NNG_HAVE_LOCALPEERPID + return (0); +#else + if (fd < 0) { + return (NNG_ECLOSED); + } + NNI_ARG_UNUSED(euid); + NNI_ARG_UNUSED(egid); + NNI_ARG_UNUSED(prid); + NNI_ARG_UNUSED(znid); + return (NNG_ENOTSUP); +#endif +} + diff --git a/src/platform/posix/posix_peerid.h b/src/platform/posix/posix_peerid.h new file mode 100644 index 000000000..9b5a24bf1 --- /dev/null +++ b/src/platform/posix/posix_peerid.h @@ -0,0 +1,26 @@ +// +// 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. +// + +#ifndef PLATFORM_POSIX_PEERID_H +#define PLATFORM_POSIX_PEERID_H + +// This file defines structures we will use for emulating asynchronous I/O +// on POSIX. POSIX lacks the support for callback based asynchronous I/O +// that we have on Windows, although it has a non-widely support aio layer +// that is not very performant on many systems. So we emulate this using +// one of several possible different backends. + +#include "core/nng_impl.h" +#include + +int +nni_posix_peerid(int fd, + uint64_t *euid, uint64_t *egid, uint64_t *prid, uint64_t *znid); + +#endif // PLATFORM_POSIX_PEERID_H \ No newline at end of file diff --git a/src/platform/posix/posix_sockfd.c b/src/platform/posix/posix_sockfd.c index 2642ac205..b0d88a31b 100644 --- a/src/platform/posix/posix_sockfd.c +++ b/src/platform/posix/posix_sockfd.c @@ -19,15 +19,17 @@ #include "core/sockfd.h" #include "platform/posix/posix_aio.h" +#include "platform/posix/posix_peerid.h" struct nni_sfd_conn { - nng_stream stream; - nni_posix_pfd * pfd; - nni_list readq; - nni_list writeq; - bool closed; - nni_mtx mtx; - nni_reap_node reap; + nng_stream stream; + nni_posix_pfd *pfd; + int fd; + nni_list readq; + nni_list writeq; + bool closed; + nni_mtx mtx; + nni_reap_node reap; }; static void @@ -41,12 +43,12 @@ sfd_dowrite(nni_sfd_conn *c) } while ((aio = nni_list_first(&c->writeq)) != NULL) { - unsigned i; - int n; - int niov; - unsigned naiov; - nni_iov * aiov; - struct iovec iovec[16]; + unsigned i; + int n; + int niov; + unsigned naiov; + nni_iov *aiov; + struct iovec iovec[16]; nni_aio_get_iov(aio, &naiov, &aiov); @@ -110,7 +112,7 @@ sfd_doread(nni_sfd_conn *c) int n; int niov; unsigned naiov; - nni_iov * aiov; + nni_iov *aiov; struct iovec iovec[16]; nni_aio_get_iov(aio, &naiov, &aiov); @@ -164,7 +166,7 @@ static void sfd_error(void *arg, int err) { nni_sfd_conn *c = arg; - nni_aio * aio; + nni_aio *aio; nni_mtx_lock(&c->mtx); while (((aio = nni_list_first(&c->readq)) != NULL) || @@ -330,7 +332,108 @@ sfd_recv(void *arg, nni_aio *aio) nni_mtx_unlock(&c->mtx); } +static int +sfd_get_addr(void *arg, void *buf, size_t *szp, nni_type t) +{ + NNI_ARG_UNUSED(arg); + nng_sockaddr sa; + sa.s_family = NNG_AF_UNSPEC; + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +sfd_get_peer_uid(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_sfd_conn *c = arg; + int rv; + uint64_t ignore; + uint64_t id = 0; + + rv = nni_posix_peerid(c->fd, &id, &ignore, &ignore, &ignore); + if (rv != 0) { + return (rv); + } + return (nni_copyout_u64(id, buf, szp, t)); +} + +static int +sfd_get_peer_gid(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_sfd_conn *c = arg; + int rv; + uint64_t ignore; + uint64_t id = 0; + + rv = nni_posix_peerid(c->fd, &ignore, &id, &ignore, &ignore); + if (rv != 0) { + return (rv); + } + return (nni_copyout_u64(id, buf, szp, t)); +} + +static int +sfd_get_peer_zoneid(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_sfd_conn *c = arg; + int rv; + uint64_t ignore; + uint64_t id = 0; + + rv = nni_posix_peerid(c->fd, &ignore, &ignore, &ignore, &id); + if (rv != 0) { + return (rv); + } + if (id == (uint64_t) -1) { + // NB: -1 is not a legal zone id (illumos/Solaris) + return (NNG_ENOTSUP); + } + return (nni_copyout_u64(id, buf, szp, t)); +} + +static int +sfd_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_sfd_conn *c = arg; + int rv; + uint64_t ignore; + uint64_t id = 0; + + rv = nni_posix_peerid(c->fd, &ignore, &ignore, &id, &ignore); + if (rv != 0) { + return (rv); + } + if (id == (uint64_t) -1) { + // NB: -1 is not a legal process id + return (NNG_ENOTSUP); + } + return (nni_copyout_u64(id, buf, szp, t)); +} + static const nni_option sfd_options[] = { + { + .o_name = NNG_OPT_LOCADDR, + .o_get = sfd_get_addr, + }, + { + .o_name = NNG_OPT_REMADDR, + .o_get = sfd_get_addr, + }, + { + .o_name = NNG_OPT_PEER_PID, + .o_get = sfd_get_peer_pid, + }, + { + .o_name = NNG_OPT_PEER_UID, + .o_get = sfd_get_peer_uid, + }, + { + .o_name = NNG_OPT_PEER_GID, + .o_get = sfd_get_peer_gid, + }, + { + .o_name = NNG_OPT_PEER_ZONEID, + .o_get = sfd_get_peer_zoneid, + }, { .o_name = NULL, }, @@ -354,7 +457,7 @@ int nni_sfd_conn_alloc(nni_sfd_conn **cp, int fd) { nni_sfd_conn *c; - int rv; + int rv; if ((c = NNI_ALLOC_STRUCT(c)) == NULL) { return (NNG_ENOMEM); } @@ -364,6 +467,7 @@ nni_sfd_conn_alloc(nni_sfd_conn **cp, int fd) } c->closed = false; + c->fd = fd; nni_mtx_init(&c->mtx); nni_aio_list_init(&c->readq); diff --git a/src/sp/transport/socket/sockfd_test.c b/src/sp/transport/socket/sockfd_test.c index 485c67baf..9d6d1853a 100644 --- a/src/sp/transport/socket/sockfd_test.c +++ b/src/sp/transport/socket/sockfd_test.c @@ -12,6 +12,13 @@ #include +#ifdef NNG_PLATFORM_POSIX +#include +#ifdef NNG_PLATFORM_SUNOS +#include +#endif +#endif + // FDC tests. static void test_sfd_connect_fail(void) @@ -193,13 +200,13 @@ test_sockfd_close_pending(void) { // this test verifies that closing a socket pair that has not // started negotiation with the other side still works. - int fds[2]; - nng_socket s0; + int fds[2]; + nng_socket s0; nng_listener l; NUTS_PASS(nng_socket_pair(fds)); NUTS_OPEN(s0); - nng_listen(s0, "sock://", &l, 0); + nng_listen(s0, "socket://", &l, 0); nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0]); nng_msleep(10); NUTS_CLOSE(s0); @@ -211,19 +218,125 @@ test_sockfd_close_peer(void) { // this test verifies that closing a socket peer // during negotiation is ok. - int fds[2]; - nng_socket s0; + int fds[2]; + nng_socket s0; nng_listener l; NUTS_PASS(nng_socket_pair(fds)); NUTS_OPEN(s0); - nng_listen(s0, "sock://", &l, 0); - nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0]); + NUTS_PASS(nng_listen(s0, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0])); close(fds[1]); nng_msleep(100); NUTS_CLOSE(s0); } +void +test_sockfd_listener_sockaddr(void) +{ + // this test verifies that closing a socket peer + // during negotiation is ok. + int fds[2]; + nng_socket s0; + nng_listener l; + nng_sockaddr sa; + + NUTS_PASS(nng_socket_pair(fds)); + NUTS_OPEN(s0); + NUTS_PASS(nng_listen(s0, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0])); + NUTS_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); + NUTS_ASSERT(sa.s_family == NNG_AF_UNSPEC); + close(fds[1]); + NUTS_CLOSE(s0); +} + +void +test_sockfd_pipe_sockaddr(void) +{ + // this test verifies that closing a socket peer + // during negotiation is ok. + int fds[2]; + nng_socket s0, s1; + nng_listener l; + nng_sockaddr sa; + nng_msg *msg; + nng_pipe p; + + NUTS_PASS(nng_socket_pair(fds)); + NUTS_OPEN(s0); + NUTS_OPEN(s1); + NUTS_PASS(nng_listen(s0, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0])); + NUTS_PASS(nng_listen(s1, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[1])); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); + + NUTS_SEND(s0, "something"); + NUTS_PASS(nng_recvmsg(s1, &msg, 0)); + p = nng_msg_get_pipe(msg); + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &sa)); + NUTS_ASSERT(sa.s_family == NNG_AF_UNSPEC); + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &sa)); + NUTS_ASSERT(sa.s_family == NNG_AF_UNSPEC); + NUTS_CLOSE(s0); + NUTS_CLOSE(s1); +} + +void +test_sockfd_pipe_peer(void) +{ + // this test verifies that closing a socket peer + // during negotiation is ok. + int fds[2]; + nng_socket s0, s1; + nng_listener l; + nng_msg *msg; + nng_pipe p; + uint64_t id; + + NUTS_PASS(nng_socket_pair(fds)); + NUTS_OPEN(s0); + NUTS_OPEN(s1); + NUTS_PASS(nng_listen(s0, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[0])); + NUTS_PASS(nng_listen(s1, "socket://", &l, 0)); + NUTS_PASS(nng_listener_set_int(l, NNG_OPT_SOCKET_FD, fds[1])); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); + + NUTS_SEND(s0, "something"); + NUTS_PASS(nng_recvmsg(s1, &msg, 0)); + p = nng_msg_get_pipe(msg); + NUTS_ASSERT(nng_pipe_id(p) != -1); +#if defined(NNG_PLATFORM_DARWIN) || defined(NNG_PLATFORM_LINUX) + NUTS_PASS(nng_pipe_get_uint64(p, NNG_OPT_PEER_PID, &id)); + NUTS_ASSERT(id == (uint64_t) getpid()); +#endif +#if defined(NNG_PLATFORM_DARWIN) || defined(NNG_PLATFORM_LINUX) + NUTS_PASS(nng_pipe_get_uint64(p, NNG_OPT_PEER_UID, &id)); + NUTS_ASSERT(id == (uint64_t) getuid()); +#endif +#if defined(NNG_PLATFORM_DARWIN) || defined(NNG_PLATFORM_LINUX) + NUTS_PASS(nng_pipe_get_uint64(p, NNG_OPT_PEER_GID, &id)); + NUTS_ASSERT(id == (uint64_t) getgid()); +#endif +#if defined(NNG_PLATFORM_SUNOS) + NUTS_PASS(nng_pipe_get_uint64(p, NNG_OPT_PEER_ZONEID, &id)); + NUTS_ASSERT(id == (uint64_t) getzoneid()); +#else + NUTS_FAIL(nng_pipe_get_uint64(p, NNG_OPT_PEER_ZONEID, &id), NNG_ENOTSUP); +#endif + + NUTS_CLOSE(s0); + NUTS_CLOSE(s1); +} + NUTS_TESTS = { { "socket connect fail", test_sfd_connect_fail }, { "socket malformed address", test_sfd_malformed_address }, @@ -235,6 +348,9 @@ NUTS_TESTS = { { "socket exchange large", test_sfd_large }, { "socket close pending", test_sockfd_close_pending }, { "socket close peer", test_sockfd_close_peer }, + { "socket listener address", test_sockfd_listener_sockaddr }, + { "socket pipe address", test_sockfd_pipe_sockaddr }, + { "socket pipe peer id", test_sockfd_pipe_peer }, #endif { NULL, NULL },