From cc419cf01d9c060a3bd3fc318f9b9bc9e736dae9 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 25 Oct 2025 11:43:59 -0700 Subject: Add stream direct address functions for socket addresses. This is going to be used to facilitate debugging, and eliminate some inconveniences around these things. We plan to move the pipe functions to use these directly, hopefully moving away from the pipe_getopt hack. (The transport API will need to grow these. For now this is just the streams.) --- docs/ref/api/stream.md | 16 ++++++ docs/ref/xref.md | 2 + include/nng/nng.h | 2 + src/core/pipe.c | 13 ++++- src/core/pipe.h | 3 +- src/core/socket.c | 21 +++++--- src/core/stream.c | 42 ++++++++++++++- src/core/stream.h | 2 + src/platform/posix/posix_ipc.h | 2 +- src/platform/posix/posix_ipcconn.c | 47 ++++++++--------- src/platform/posix/posix_sockfd.c | 42 +++++++-------- src/platform/posix/posix_tcp.h | 4 +- src/platform/posix/posix_tcpconn.c | 80 +++++++++++------------------ src/platform/windows/win_ipcconn.c | 48 ++++++++--------- src/platform/windows/win_ipclisten.c | 8 +-- src/platform/windows/win_resolv.c | 2 +- src/platform/windows/win_tcp.c | 1 - src/platform/windows/win_tcp.h | 46 ++++++++--------- src/platform/windows/win_tcpconn.c | 75 +++++++++++---------------- src/platform/windows/win_tcpdial.c | 38 ++++++++------ src/platform/windows/win_tcplisten.c | 18 ++++--- src/supplemental/http/http_api.h | 4 +- src/supplemental/http/http_conn.c | 15 +++--- src/supplemental/http/http_public.c | 14 ++++- src/supplemental/tls/tls_stream.c | 18 +++++++ src/supplemental/websocket/websocket.c | 18 +++++++ src/supplemental/websocket/websocket_test.c | 6 +++ 27 files changed, 343 insertions(+), 244 deletions(-) diff --git a/docs/ref/api/stream.md b/docs/ref/api/stream.md index 38c6adb8..6b02d8db 100644 --- a/docs/ref/api/stream.md +++ b/docs/ref/api/stream.md @@ -76,6 +76,18 @@ stream itself. > or be aborted, these functions are unsafe to call from functions that may not block, such as the > completion function registered with an [`nng_aio`] when it is created. +## Stream Addresses + +```c +nng_err nng_stream_peer_addr(nng_stream *s, const nng_sockaddr **valp); +nng_err nng_stream_self_addr(nng_stream *s, const nng_sockaddr **valp); +``` + +{{hi:`nng_stream_peer_addr`}} +{{hi:`nng_stream_self_addr`}} +These functions are used to obtain value of the local (self) or remote (peer) addresses +for the given stream _s_. + ## Getting Stream Options ```c @@ -102,6 +114,10 @@ are available, and which type they may be accessed using. In the case of `nng_stream_get_string`, the string pointer is only guaranteed to be valid while the stream exists. Callers should make a copy of the data if required before closing the stream. +> [!NOTE]: +> The `nng_stream_get_addr` function is deprecated and will be removed. Use the +> [`nng_stream_peer_addr`] or [`nng_stream_self_addr`] functions instead. + ## Stream Factories ```c diff --git a/docs/ref/xref.md b/docs/ref/xref.md index 8ac6e2f5..d64840cb 100644 --- a/docs/ref/xref.md +++ b/docs/ref/xref.md @@ -170,6 +170,8 @@ [`nng_stream_listener_set_size`]: ../api/stream.md#stream-factory-options [`nng_stream_listener_set_addr`]: ../api/stream.md#stream-factory-options [`nng_stream_listener_set_string`]: ../api/stream.md#stream-factory-options +[`nng_stream_peer_addr`]: ../api/stream.md#stream-addresses +[`nng_stream_self_addr`]: ../api/stream.md#stream-addresses [`nng_init`]: ../api/init.md#initialization [`nng_fini`]: ../api/init.md#finalization [`nng_sub0_ctx_subscribe`]: ../proto/sub.md#context-operations diff --git a/include/nng/nng.h b/include/nng/nng.h index afb347de..c5881b3b 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1162,6 +1162,8 @@ NNG_DECL nng_err nng_stream_get_string( nng_stream *, const char *, const char **); NNG_DECL nng_err nng_stream_get_addr( nng_stream *, const char *, nng_sockaddr *); +NNG_DECL nng_err nng_stream_peer_addr(nng_stream *, const nng_sockaddr **); +NNG_DECL nng_err nng_stream_self_addr(nng_stream *, const nng_sockaddr **); NNG_DECL nng_err nng_stream_peer_cert(nng_stream *, nng_tls_cert **); NNG_DECL nng_err nng_stream_dialer_alloc(nng_stream_dialer **, const char *); diff --git a/src/core/pipe.c b/src/core/pipe.c index db2c4d41..baa2d6f9 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -421,7 +421,7 @@ nni_pipe_bump_error(nni_pipe *p, int err) } char * -nni_pipe_peer_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]) +nni_pipe_peer_str_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]) { nng_sockaddr sa; size_t sz = sizeof(sa); @@ -431,6 +431,17 @@ nni_pipe_peer_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]) return (buf); } +char * +nni_pipe_self_str_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]) +{ + nng_sockaddr sa; + size_t sz = sizeof(sa); + sa.s_family = AF_UNSPEC; + nni_pipe_getopt(p, NNG_OPT_LOCADDR, &sa, &sz, NNI_TYPE_SOCKADDR); + nng_str_sockaddr(&sa, buf, NNG_MAXADDRSTRLEN); + return (buf); +} + nng_err nni_pipe_peer_cert(nni_pipe *p, nng_tls_cert **certp) { diff --git a/src/core/pipe.h b/src/core/pipe.h index 4ed61660..6ef3c206 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -69,7 +69,8 @@ extern void nni_pipe_bump_rx(nni_pipe *, size_t); extern void nni_pipe_bump_tx(nni_pipe *, size_t); extern void nni_pipe_bump_error(nni_pipe *, int); -extern char *nni_pipe_peer_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]); +extern char *nni_pipe_peer_str_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]); +extern char *nni_pipe_self_str_addr(nni_pipe *p, char buf[NNG_MAXADDRSTRLEN]); extern int nni_pipe_alloc_dialer(void **, nni_dialer *); extern int nni_pipe_alloc_listener(void **, nni_listener *); diff --git a/src/core/socket.c b/src/core/socket.c index 7112014e..a7633c9e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1301,7 +1301,8 @@ dialer_start_pipe(nni_dialer *d, nni_pipe *p) char addr[NNG_MAXADDRSTRLEN]; nng_log_debug("NNG-PIPEREJECT", "Pipe on socket<%u> from %s rejected by callback", - nni_pipe_sock_id(p), nni_pipe_peer_addr(p, addr)); + nni_pipe_sock_id(p), + nni_pipe_peer_str_addr(p, addr)); } nni_pipe_rele(p); return; @@ -1323,10 +1324,13 @@ dialer_start_pipe(nni_dialer *d, nni_pipe *p) #endif nni_pipe_run_cb(p, NNG_PIPE_EV_ADD_POST); if (nng_log_get_level() >= NNG_LOG_DEBUG) { - char addr[NNG_MAXADDRSTRLEN]; + char peer_addr[NNG_MAXADDRSTRLEN]; + char self_addr[NNG_MAXADDRSTRLEN]; nng_log_debug("NNG-CONNECT", - "Connected pipe<%u> on socket<%u> to %s", nni_pipe_id(p), - nni_sock_id(s), nni_pipe_peer_addr(p, addr)); + "Connected pipe<%u> on socket<%u> at %s to %s", + nni_pipe_id(p), nni_sock_id(s), + nni_pipe_self_str_addr(p, self_addr), + nni_pipe_peer_str_addr(p, peer_addr)); } nni_pipe_rele(p); } @@ -1429,10 +1433,13 @@ listener_start_pipe(nni_listener *l, nni_pipe *p) #endif nni_pipe_run_cb(p, NNG_PIPE_EV_ADD_POST); if (nng_log_get_level() >= NNG_LOG_DEBUG) { - char addr[NNG_MAXADDRSTRLEN]; + char peer_addr[NNG_MAXADDRSTRLEN]; + char self_addr[NNG_MAXADDRSTRLEN]; nng_log_debug("NNG-ACCEPT", - "Accepted pipe<%u> on socket<%u> from %s", nni_pipe_id(p), - nni_sock_id(s), nni_pipe_peer_addr(p, addr)); + "Accepted pipe<%u> on socket<%u> at %s from %s", + nni_pipe_id(p), nni_sock_id(s), + nni_pipe_self_str_addr(p, self_addr), + nni_pipe_peer_str_addr(p, peer_addr)); } // the socket now "owns" the pipe, and a pipe close should immediately diff --git a/src/core/stream.c b/src/core/stream.c index 5a5159df..6c7ad5f0 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -133,6 +133,15 @@ void nng_stream_free(nng_stream *s) { if (s != NULL) { + // These are mandatory - we have checks here for completeness. + NNI_ASSERT(s->s_close != NULL); + NNI_ASSERT(s->s_stop != NULL); + NNI_ASSERT(s->s_send != NULL); + NNI_ASSERT(s->s_recv != NULL); + NNI_ASSERT(s->s_free != NULL); + NNI_ASSERT(s->s_peer_addr != NULL); + NNI_ASSERT(s->s_self_addr != NULL); + s->s_free(s); } } @@ -155,6 +164,15 @@ nng_err nni_stream_get( nng_stream *s, const char *nm, void *data, size_t *szp, nni_type t) { + // TODO: eventually this needs die + if ((strcmp(nm, NNG_OPT_REMADDR) == 0) || + (strcmp(nm, NNG_OPT_LOCADDR) == 0)) { + if (t != NNI_TYPE_SOCKADDR) { + return (NNG_EBADTYPE); + } + return (nng_stream_get_addr(s, nm, (nng_sockaddr *) data)); + } + return (s->s_get(s, nm, data, szp, t)); } @@ -382,7 +400,29 @@ nng_stream_get_ms(nng_stream *s, const char *n, nng_duration *v) nng_err nng_stream_get_addr(nng_stream *s, const char *n, nng_sockaddr *v) { - return (nni_stream_get(s, n, v, NULL, NNI_TYPE_SOCKADDR)); + const nng_sockaddr *sap; + int rv = NNG_ENOTSUP; + if (strcmp(n, NNG_OPT_LOCADDR) == 0) { + rv = nng_stream_self_addr(s, &sap); + } else if (strcmp(n, NNG_OPT_REMADDR) == 0) { + rv = nng_stream_peer_addr(s, &sap); + } + if (rv == NNG_OK) { + *v = *sap; + } + return (rv); +} + +nng_err +nng_stream_self_addr(nng_stream *s, const nng_sockaddr **sa) +{ + return (s->s_self_addr(s, &*sa)); +} + +nng_err +nng_stream_peer_addr(nng_stream *s, const nng_sockaddr **sa) +{ + return (s->s_peer_addr(s, &*sa)); } nng_err diff --git a/src/core/stream.h b/src/core/stream.h index a9a17ec1..3c87e9c5 100644 --- a/src/core/stream.h +++ b/src/core/stream.h @@ -50,6 +50,8 @@ struct nng_stream { void (*s_send)(void *, nng_aio *); nng_err (*s_get)(void *, const char *, void *, size_t *, nni_type); nng_err (*s_set)(void *, const char *, const void *, size_t, nni_type); + nng_err (*s_peer_addr)(void *, const nng_sockaddr **); + nng_err (*s_self_addr)(void *, const nng_sockaddr **); nng_err (*s_peer_cert)(void *, nng_tls_cert **); }; diff --git a/src/platform/posix/posix_ipc.h b/src/platform/posix/posix_ipc.h index f1aa412d..7a48beaf 100644 --- a/src/platform/posix/posix_ipc.h +++ b/src/platform/posix/posix_ipc.h @@ -45,7 +45,7 @@ struct nni_ipc_dialer { #endif }; -extern int nni_posix_ipc_alloc( +extern nng_err nni_posix_ipc_alloc( nni_ipc_conn **, nni_sockaddr *, nni_ipc_dialer *, int); extern void nni_posix_ipc_dialer_rele(nni_ipc_dialer *); extern void nni_posix_ipc_dialer_cb(void *arg, unsigned events); diff --git a/src/platform/posix/posix_ipcconn.c b/src/platform/posix/posix_ipcconn.c index fd3cdbd8..11bd03d8 100644 --- a/src/platform/posix/posix_ipcconn.c +++ b/src/platform/posix/posix_ipcconn.c @@ -299,6 +299,14 @@ ipc_recv(void *arg, nni_aio *aio) nni_mtx_unlock(&c->mtx); } +static nng_err +ipc_sock_addr(void *arg, const nng_sockaddr **sap) +{ + ipc_conn *c = arg; + *sap = &c->sa; + return (NNG_OK); +} + static nng_err ipc_get_peer_uid(void *arg, void *buf, size_t *szp, nni_type t) { @@ -367,13 +375,6 @@ ipc_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type t) return (nni_copyout_int(id, buf, szp, t)); } -static nng_err -ipc_get_addr(void *arg, void *buf, size_t *szp, nni_type t) -{ - ipc_conn *c = arg; - return (nni_copyout_sockaddr(&c->sa, buf, szp, t)); -} - static void ipc_stop(void *arg) { @@ -412,14 +413,6 @@ ipc_free(void *arg) } static const nni_option ipc_options[] = { - { - .o_name = NNG_OPT_LOCADDR, - .o_get = ipc_get_addr, - }, - { - .o_name = NNG_OPT_REMADDR, - .o_get = ipc_get_addr, - }, { .o_name = NNG_OPT_IPC_PEER_PID, .o_get = ipc_get_peer_pid, @@ -455,7 +448,7 @@ ipc_set(void *arg, const char *name, const void *val, size_t sz, nni_type t) return (nni_setopt(ipc_options, name, c, val, sz, t)); } -int +nng_err nni_posix_ipc_alloc( nni_ipc_conn **cp, nni_sockaddr *sa, nni_ipc_dialer *d, int fd) { @@ -465,16 +458,18 @@ nni_posix_ipc_alloc( return (NNG_ENOMEM); } - c->closed = false; - c->dialer = d; - c->stream.s_free = ipc_free; - c->stream.s_close = ipc_close; - c->stream.s_stop = ipc_stop; - c->stream.s_send = ipc_send; - c->stream.s_recv = ipc_recv; - c->stream.s_get = ipc_get; - c->stream.s_set = ipc_set; - c->sa = *sa; + c->closed = false; + c->dialer = d; + c->stream.s_free = ipc_free; + c->stream.s_close = ipc_close; + c->stream.s_stop = ipc_stop; + c->stream.s_send = ipc_send; + c->stream.s_recv = ipc_recv; + c->stream.s_get = ipc_get; + c->stream.s_set = ipc_set; + c->stream.s_self_addr = ipc_sock_addr, + c->stream.s_peer_addr = ipc_sock_addr; + c->sa = *sa; nni_mtx_init(&c->mtx); nni_aio_list_init(&c->readq); diff --git a/src/platform/posix/posix_sockfd.c b/src/platform/posix/posix_sockfd.c index 6762987b..43225e7e 100644 --- a/src/platform/posix/posix_sockfd.c +++ b/src/platform/posix/posix_sockfd.c @@ -327,15 +327,6 @@ sfd_recv(void *arg, nni_aio *aio) nni_mtx_unlock(&c->mtx); } -static nng_err -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 nng_err sfd_get_peer_uid(void *arg, void *buf, size_t *szp, nni_type t) { @@ -405,14 +396,6 @@ sfd_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type 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, @@ -448,6 +431,15 @@ sfd_set(void *arg, const char *name, const void *buf, size_t sz, nni_type t) return (nni_setopt(sfd_options, name, c, buf, sz, t)); } +static nng_err +sfd_addr(void *arg, const nng_sockaddr **sap) +{ + static nng_sockaddr sa = { .s_family = NNG_AF_UNSPEC }; + NNI_ARG_UNUSED(arg); + *sap = &sa; + return (NNG_OK); +} + nng_err nni_sfd_conn_alloc(nni_sfd_conn **cp, int fd) { @@ -464,13 +456,15 @@ nni_sfd_conn_alloc(nni_sfd_conn **cp, int fd) nni_aio_list_init(&c->readq); nni_aio_list_init(&c->writeq); - c->stream.s_free = sfd_free; - c->stream.s_close = sfd_close; - c->stream.s_stop = sfd_stop; - c->stream.s_recv = sfd_recv; - c->stream.s_send = sfd_send; - c->stream.s_get = sfd_get; - c->stream.s_set = sfd_set; + c->stream.s_free = sfd_free; + c->stream.s_close = sfd_close; + c->stream.s_stop = sfd_stop; + c->stream.s_recv = sfd_recv; + c->stream.s_send = sfd_send; + c->stream.s_get = sfd_get; + c->stream.s_set = sfd_set; + c->stream.s_peer_addr = sfd_addr; + c->stream.s_self_addr = sfd_addr; *cp = c; return (NNG_OK); diff --git a/src/platform/posix/posix_tcp.h b/src/platform/posix/posix_tcp.h index 3b61d7da..20325841 100644 --- a/src/platform/posix/posix_tcp.h +++ b/src/platform/posix/posix_tcp.h @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2018 Devolutions // @@ -26,6 +26,8 @@ struct nni_tcp_conn { nni_aio *dial_aio; nni_tcp_dialer *dialer; nni_reap_node reap; + nng_sockaddr peer; + nng_sockaddr self; }; extern int nni_posix_tcp_alloc(nni_tcp_conn **, nni_tcp_dialer *, int); diff --git a/src/platform/posix/posix_tcpconn.c b/src/platform/posix/posix_tcpconn.c index 674e3f46..43dfb4e4 100644 --- a/src/platform/posix/posix_tcpconn.c +++ b/src/platform/posix/posix_tcpconn.c @@ -333,41 +333,19 @@ tcp_recv(void *arg, nni_aio *aio) } static nng_err -tcp_get_peername(void *arg, void *buf, size_t *szp, nni_type t) +tcp_get_peer_addr(void *arg, const nng_sockaddr **addr) { - nni_tcp_conn *c = arg; - struct sockaddr_storage ss; - socklen_t len = sizeof(ss); - int fd = nni_posix_pfd_fd(&c->pfd); - nng_err rv; - nng_sockaddr sa; - - if (getpeername(fd, (void *) &ss, &len) != 0) { - return (nni_plat_errno(errno)); - } - if ((rv = nni_posix_sockaddr2nn(&sa, &ss, len)) == NNG_OK) { - rv = nni_copyout_sockaddr(&sa, buf, szp, t); - } - return (rv); + nni_tcp_conn *c = arg; + *addr = &c->peer; + return (NNG_OK); } static nng_err -tcp_get_sockname(void *arg, void *buf, size_t *szp, nni_type t) +tcp_get_self_addr(void *arg, const nng_sockaddr **addr) { - nni_tcp_conn *c = arg; - struct sockaddr_storage ss; - socklen_t len = sizeof(ss); - int fd = nni_posix_pfd_fd(&c->pfd); - int rv; - nng_sockaddr sa; - - if (getsockname(fd, (void *) &ss, &len) != 0) { - return (nni_plat_errno(errno)); - } - if ((rv = nni_posix_sockaddr2nn(&sa, &ss, len)) == NNG_OK) { - rv = nni_copyout_sockaddr(&sa, buf, szp, t); - } - return (rv); + nni_tcp_conn *c = arg; + *addr = &c->self; + return (NNG_OK); } static nng_err @@ -401,14 +379,6 @@ tcp_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) } static const nni_option tcp_options[] = { - { - .o_name = NNG_OPT_REMADDR, - .o_get = tcp_get_peername, - }, - { - .o_name = NNG_OPT_LOCADDR, - .o_get = tcp_get_sockname, - }, { .o_name = NNG_OPT_TCP_NODELAY, .o_get = tcp_get_nodelay, @@ -452,13 +422,15 @@ nni_posix_tcp_alloc(nni_tcp_conn **cp, nni_tcp_dialer *d, int fd) nni_aio_list_init(&c->writeq); nni_posix_pfd_init(&c->pfd, fd, tcp_cb, c); - c->stream.s_free = tcp_free; - c->stream.s_stop = tcp_stop; - c->stream.s_close = tcp_close; - c->stream.s_recv = tcp_recv; - c->stream.s_send = tcp_send; - c->stream.s_get = tcp_get; - c->stream.s_set = tcp_set; + c->stream.s_free = tcp_free; + c->stream.s_stop = tcp_stop; + c->stream.s_close = tcp_close; + c->stream.s_recv = tcp_recv; + c->stream.s_send = tcp_send; + c->stream.s_get = tcp_get; + c->stream.s_set = tcp_set; + c->stream.s_peer_addr = tcp_get_peer_addr; + c->stream.s_self_addr = tcp_get_self_addr; *cp = c; return (0); @@ -467,9 +439,19 @@ nni_posix_tcp_alloc(nni_tcp_conn **cp, nni_tcp_dialer *d, int fd) void nni_posix_tcp_start(nni_tcp_conn *c, int nodelay, int keepalive) { + int fd = nni_posix_pfd_fd(&c->pfd); // Configure the initial socket options. - (void) setsockopt(nni_posix_pfd_fd(&c->pfd), IPPROTO_TCP, TCP_NODELAY, - &nodelay, sizeof(int)); - (void) setsockopt(nni_posix_pfd_fd(&c->pfd), SOL_SOCKET, SO_KEEPALIVE, - &keepalive, sizeof(int)); + (void) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(int)); + (void) setsockopt( + fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(int)); + + struct sockaddr_storage ss; + socklen_t len = sizeof(ss); + + // Get this info now so we can avoid system calls later. + (void) getpeername(fd, (void *) &ss, &len); + nni_posix_sockaddr2nn(&c->peer, &ss, len); + + (void) getsockname(fd, (void *) &ss, &len); + nni_posix_sockaddr2nn(&c->self, &ss, len); } diff --git a/src/platform/windows/win_ipcconn.c b/src/platform/windows/win_ipcconn.c index 45235387..a5ef16a6 100644 --- a/src/platform/windows/win_ipcconn.c +++ b/src/platform/windows/win_ipcconn.c @@ -9,8 +9,8 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/aio.h" -#include "core/nng_impl.h" +#include "../../core/nng_impl.h" +#include "win_impl.h" #include "win_ipc.h" @@ -276,7 +276,7 @@ ipc_send_cb(nni_win_io *io, int rv, size_t num) } static void -ipc_send_cancel(nni_aio *aio, void *arg, int rv) +ipc_send_cancel(nni_aio *aio, void *arg, nng_err rv) { ipc_conn *c = arg; nni_mtx_lock(&c->mtx); @@ -387,12 +387,6 @@ ipc_free(void *arg) NNI_FREE_STRUCT(c); } -static nng_err -ipc_conn_get_addr(void *c, void *buf, size_t *szp, nni_opt_type t) -{ - return (nni_copyout_sockaddr(&(CONN(c))->sa, buf, szp, t)); -} - static nng_err ipc_conn_get_peer_pid(void *c, void *buf, size_t *szp, nni_opt_type t) { @@ -414,14 +408,6 @@ ipc_conn_get_peer_pid(void *c, void *buf, size_t *szp, nni_opt_type t) } static const nni_option ipc_conn_options[] = { - { - .o_name = NNG_OPT_LOCADDR, - .o_get = ipc_conn_get_addr, - }, - { - .o_name = NNG_OPT_REMADDR, - .o_get = ipc_conn_get_addr, - }, { .o_name = NNG_OPT_IPC_PEER_PID, .o_get = ipc_conn_get_peer_pid, @@ -445,6 +431,14 @@ ipc_get(void *arg, const char *nm, void *val, size_t *szp, nni_opt_type t) return (nni_getopt(ipc_conn_options, nm, c, val, szp, t)); } +static nng_err +ipc_addr(void *arg, const nng_sockaddr **sap) +{ + ipc_conn *c = arg; + *sap = &c->sa; + return (NNG_OK); +} + int nni_win_ipc_init( nng_stream **connp, HANDLE p, const nng_sockaddr *sa, bool dialer) @@ -459,15 +453,17 @@ nni_win_ipc_init( nni_cv_init(&c->cv, &c->mtx); nni_aio_list_init(&c->recv_aios); nni_aio_list_init(&c->send_aios); - c->dialer = dialer; - c->sa = *sa; - c->stream.s_free = ipc_free; - c->stream.s_close = ipc_close; - c->stream.s_stop = ipc_stop; - c->stream.s_send = ipc_send; - c->stream.s_recv = ipc_recv; - c->stream.s_get = ipc_get; - c->stream.s_set = ipc_set; + c->dialer = dialer; + c->sa = *sa; + c->stream.s_free = ipc_free; + c->stream.s_close = ipc_close; + c->stream.s_stop = ipc_stop; + c->stream.s_send = ipc_send; + c->stream.s_recv = ipc_recv; + c->stream.s_get = ipc_get; + c->stream.s_set = ipc_set; + c->stream.s_self_addr = ipc_addr; + c->stream.s_peer_addr = ipc_addr; nni_win_io_init(&c->recv_io, ipc_recv_cb, c); nni_win_io_init(&c->send_io, ipc_send_cb, c); diff --git a/src/platform/windows/win_ipclisten.c b/src/platform/windows/win_ipclisten.c index 3bb71c7d..07c69507 100644 --- a/src/platform/windows/win_ipclisten.c +++ b/src/platform/windows/win_ipclisten.c @@ -9,7 +9,7 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/nng_impl.h" +#include "../../core/nng_impl.h" #include "win_ipc.h" @@ -158,7 +158,7 @@ ipc_listener_set_sec_desc(void *arg, void *desc) return (NNG_OK); } -static int +static nng_err ipc_listener_get_addr(void *arg, void *buf, size_t *szp, nni_type t) { ipc_listener *l = arg; @@ -175,7 +175,7 @@ static const nni_option ipc_listener_options[] = { }, }; -static int +static nng_err ipc_listener_set( void *arg, const char *name, const void *buf, size_t sz, nni_type t) { @@ -183,7 +183,7 @@ ipc_listener_set( return (nni_setopt(ipc_listener_options, name, l, buf, sz, t)); } -static int +static nng_err ipc_listener_get( void *arg, const char *name, void *buf, size_t *szp, nni_type t) { diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c index 50b030da..3ccbf982 100644 --- a/src/platform/windows/win_resolv.c +++ b/src/platform/windows/win_resolv.c @@ -31,7 +31,7 @@ static nni_mtx resolv_mtx; static nni_cv resolv_cv; static void -resolv_cancel(nni_aio *aio, void *arg, int rv) +resolv_cancel(nni_aio *aio, void *arg, nng_err rv) { nni_resolv_item *item = arg; diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c index 42667dea..006c99e8 100644 --- a/src/platform/windows/win_tcp.c +++ b/src/platform/windows/win_tcp.c @@ -12,7 +12,6 @@ #ifdef NNG_PLATFORM_WINDOWS -#include #include static LPFN_ACCEPTEX acceptex; diff --git a/src/platform/windows/win_tcp.h b/src/platform/windows/win_tcp.h index ec8ab80c..698160b2 100644 --- a/src/platform/windows/win_tcp.h +++ b/src/platform/windows/win_tcp.h @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -14,30 +14,30 @@ // This header file is private to the TCP support for Windows. -#include "core/nng_impl.h" +#include "../../core/nng_impl.h" struct nni_tcp_conn { - nng_stream ops; - SOCKET s; - nni_win_io recv_io; - nni_win_io send_io; - nni_win_io conn_io; - nni_list recv_aios; - nni_list send_aios; - nni_aio *conn_aio; - SOCKADDR_STORAGE sockname; - SOCKADDR_STORAGE peername; - nni_tcp_dialer *dialer; - void *listener; - int recv_rv; - int send_rv; - int conn_rv; - bool closed; - char buf[512]; // to hold acceptex results - bool sending; - bool recving; - nni_mtx mtx; - nni_cv cv; + nng_stream ops; + SOCKET s; + nni_win_io recv_io; + nni_win_io send_io; + nni_win_io conn_io; + nni_list recv_aios; + nni_list send_aios; + nni_aio *conn_aio; + nng_sockaddr sockname; + nng_sockaddr peername; + nni_tcp_dialer *dialer; + void *listener; + int recv_rv; + int send_rv; + int conn_rv; + bool closed; + char buf[512]; // to hold acceptex results + bool sending; + bool recving; + nni_mtx mtx; + nni_cv cv; }; extern int nni_win_tcp_init(nni_tcp_conn **, SOCKET); diff --git a/src/platform/windows/win_tcpconn.c b/src/platform/windows/win_tcpconn.c index 102700ec..dae6b58d 100644 --- a/src/platform/windows/win_tcpconn.c +++ b/src/platform/windows/win_tcpconn.c @@ -9,11 +9,10 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/nng_impl.h" +#include "../../core/nng_impl.h" #include "win_tcp.h" -#include #include static void @@ -180,7 +179,7 @@ tcp_send_start(nni_tcp_conn *c) } static void -tcp_send_cancel(nni_aio *aio, void *arg, int rv) +tcp_send_cancel(nni_aio *aio, void *arg, nng_err rv) { nni_tcp_conn *c = arg; nni_mtx_lock(&c->mtx); @@ -262,30 +261,6 @@ tcp_close(void *arg) nni_mtx_unlock(&c->mtx); } -static nng_err -tcp_get_peername(void *arg, void *buf, size_t *szp, nni_type t) -{ - nni_tcp_conn *c = arg; - nng_sockaddr sa; - - if (nni_win_sockaddr2nn(&sa, &c->peername, sizeof(c->peername)) < 0) { - return (NNG_EADDRINVAL); - } - return (nni_copyout_sockaddr(&sa, buf, szp, t)); -} - -static nng_err -tcp_get_sockname(void *arg, void *buf, size_t *szp, nni_type t) -{ - nni_tcp_conn *c = arg; - nng_sockaddr sa; - - if (nni_win_sockaddr2nn(&sa, &c->sockname, sizeof(c->sockname)) < 0) { - return (NNG_EADDRINVAL); - } - return (nni_copyout_sockaddr(&sa, buf, szp, t)); -} - static nng_err tcp_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) { @@ -314,15 +289,23 @@ tcp_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) return (nni_copyout_bool(b, buf, szp, t)); } +static nng_err +tcp_self_addr(void *arg, const nng_sockaddr **sap) +{ + nni_tcp_conn *c = arg; + *sap = &c->sockname; + return (NNG_OK); +} + +static nng_err +tcp_peer_addr(void *arg, const nng_sockaddr **sap) +{ + nni_tcp_conn *c = arg; + *sap = &c->peername; + return (NNG_OK); +} + static const nni_option tcp_options[] = { - { - .o_name = NNG_OPT_REMADDR, - .o_get = tcp_get_peername, - }, - { - .o_name = NNG_OPT_LOCADDR, - .o_get = tcp_get_sockname, - }, { .o_name = NNG_OPT_TCP_NODELAY, .o_get = tcp_get_nodelay, @@ -336,14 +319,14 @@ static const nni_option tcp_options[] = { }, }; -static int +static nng_err tcp_get(void *arg, const char *name, void *buf, size_t *szp, nni_type t) { nni_tcp_conn *c = arg; return (nni_getopt(tcp_options, name, c, buf, szp, t)); } -static int +static nng_err tcp_set(void *arg, const char *name, const void *buf, size_t sz, nni_type t) { nni_tcp_conn *c = arg; @@ -397,14 +380,16 @@ nni_win_tcp_init(nni_tcp_conn **connp, SOCKET s) nni_cv_init(&c->cv, &c->mtx); nni_aio_list_init(&c->recv_aios); nni_aio_list_init(&c->send_aios); - c->conn_aio = NULL; - c->ops.s_close = tcp_close; - c->ops.s_stop = tcp_stop; - c->ops.s_free = tcp_free; - c->ops.s_send = tcp_send; - c->ops.s_recv = tcp_recv; - c->ops.s_get = tcp_get; - c->ops.s_set = tcp_set; + c->conn_aio = NULL; + c->ops.s_close = tcp_close; + c->ops.s_stop = tcp_stop; + c->ops.s_free = tcp_free; + c->ops.s_send = tcp_send; + c->ops.s_recv = tcp_recv; + c->ops.s_get = tcp_get; + c->ops.s_set = tcp_set; + c->ops.s_peer_addr = tcp_peer_addr; + c->ops.s_self_addr = tcp_self_addr; nni_win_io_init(&c->recv_io, tcp_recv_cb, c); nni_win_io_init(&c->send_io, tcp_send_cb, c); diff --git a/src/platform/windows/win_tcpdial.c b/src/platform/windows/win_tcpdial.c index 72e4f8a7..a3d64869 100644 --- a/src/platform/windows/win_tcpdial.c +++ b/src/platform/windows/win_tcpdial.c @@ -9,11 +9,10 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/nng_impl.h" +#include "../../core/nng_impl.h" #include "win_tcp.h" -#include #include struct nni_tcp_dialer { @@ -145,8 +144,9 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt) nng_stream_free(&c->ops); nni_aio_finish_error(aio, rv); } else { - DWORD yes = 1; - int len; + DWORD yes = 1; + int len; + SOCKADDR_STORAGE sa; (void) setsockopt(c->s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, (char *) &yes, sizeof(yes)); @@ -157,8 +157,13 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt) (void) setsockopt( c->s, IPPROTO_TCP, TCP_NODELAY, (char *) &nd, sizeof(nd)); - len = sizeof(SOCKADDR_STORAGE); - (void) getsockname(c->s, (SOCKADDR *) &c->sockname, &len); + len = sizeof(sa); + (void) getsockname(c->s, (SOCKADDR *) &sa, &len); + nni_win_sockaddr2nn(&c->sockname, &sa, len); + + len = sizeof(sa); + (void) getpeername(c->s, (SOCKADDR *) &sa, &len); + nni_win_sockaddr2nn(&c->peername, &sa, len); nni_aio_set_output(aio, 0, c); nni_aio_finish(aio, 0, 0); @@ -169,19 +174,21 @@ void nni_tcp_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) { SOCKET s; - SOCKADDR_STORAGE ss; + SOCKADDR_STORAGE peername; + SOCKADDR_STORAGE sockname; int len; nni_tcp_conn *c; int rv; nni_aio_reset(aio); - if ((len = nni_win_nn2sockaddr(&ss, sa)) <= 0) { + if ((len = nni_win_nn2sockaddr(&peername, sa)) <= 0) { nni_aio_finish_error(aio, NNG_EADDRINVAL); return; } - if ((s = socket(ss.ss_family, SOCK_STREAM, 0)) == INVALID_SOCKET) { + if ((s = socket(peername.ss_family, SOCK_STREAM, 0)) == + INVALID_SOCKET) { nni_aio_finish_error(aio, nni_win_error(GetLastError())); return; } @@ -192,8 +199,6 @@ nni_tcp_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) return; } - c->peername = ss; - nni_win_io_init(&c->conn_io, tcp_dial_cb, c); nni_mtx_lock(&d->mtx); @@ -209,12 +214,13 @@ nni_tcp_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) // same family, unless a different default was requested. if (d->srclen != 0) { len = (int) d->srclen; + memcpy(&sockname, &d->src, len); memcpy(&c->sockname, &d->src, len); } else { - ZeroMemory(&c->sockname, sizeof(c->sockname)); - c->sockname.ss_family = ss.ss_family; + ZeroMemory(&sockname, sizeof(sockname)); + sockname.ss_family = peername.ss_family; } - if (bind(s, (SOCKADDR *) &c->sockname, len) != 0) { + if (bind(s, (SOCKADDR *) &sockname, len) != 0) { rv = nni_win_error(GetLastError()); nni_mtx_unlock(&d->mtx); nng_stream_free(&c->ops); @@ -222,6 +228,8 @@ nni_tcp_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) return; } + nni_win_sockaddr2nn(&c->sockname, &sockname, sizeof(sockname)); + if (!nni_aio_start(aio, tcp_dial_cancel, d)) { nni_mtx_unlock(&d->mtx); nng_stream_free(&c->ops); @@ -234,7 +242,7 @@ nni_tcp_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) // dialing is concurrent. if (!nni_win_connectex( - s, (SOCKADDR *) &c->peername, len, &c->conn_io.olpd)) { + s, (SOCKADDR *) &peername, len, &c->conn_io.olpd)) { if ((rv = GetLastError()) != ERROR_IO_PENDING) { nni_aio_list_remove(aio); nni_mtx_unlock(&d->mtx); diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c index 563cbcf0..0b11104d 100644 --- a/src/platform/windows/win_tcplisten.c +++ b/src/platform/windows/win_tcplisten.c @@ -9,12 +9,10 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/nng_impl.h" - -#include #include #include +#include "../../core/nng_impl.h" #include "win_tcp.h" typedef struct tcp_listener { @@ -220,10 +218,12 @@ tcp_accept_cancel(nni_aio *aio, void *arg, nng_err rv) static void tcp_listener_accepted(tcp_listener *l) { - BOOL nd; - BOOL ka; - nni_tcp_conn *c; - nni_aio *aio; + BOOL nd; + BOOL ka; + nni_tcp_conn *c; + nni_aio *aio; + SOCKADDR_STORAGE sockname; + SOCKADDR_STORAGE peername; aio = nni_list_first(&l->aios); c = l->pend_conn; @@ -232,7 +232,9 @@ tcp_listener_accepted(tcp_listener *l) nd = l->nodelay; nni_aio_list_remove(aio); - nni_win_get_acceptex_sockaddrs(c->buf, &c->sockname, &c->peername); + nni_win_get_acceptex_sockaddrs(c->buf, &sockname, &peername); + nni_win_sockaddr2nn(&c->sockname, &sockname, sizeof(sockname)); + nni_win_sockaddr2nn(&c->peername, &peername, sizeof(peername)); (void) setsockopt(c->s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *) &l->s, sizeof(l->s)); diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 74472f50..ca13bd09 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -72,8 +72,8 @@ extern void nni_http_read_chunks( extern nni_http_req *nni_http_conn_req(nni_http_conn *); extern nni_http_res *nni_http_conn_res(nni_http_conn *); -extern nng_err nni_http_get_addr( - nni_http_conn *, const char *, nng_sockaddr *); +extern nng_err nni_http_peer_addr(nni_http_conn *, const nng_sockaddr **); +extern nng_err nni_http_self_addr(nni_http_conn *, const nng_sockaddr **); // Private to the server. (Used to support session hijacking.) extern void nni_http_conn_set_ctx(nni_http_conn *, void *); diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c index ac549649..bb3a0882 100644 --- a/src/supplemental/http/http_conn.c +++ b/src/supplemental/http/http_conn.c @@ -22,6 +22,7 @@ #include "http_api.h" #include "http_msg.h" +#include "nng/nng.h" // We insist that individual headers fit in 8K. // If you need more than that, you need something we can't do. @@ -160,13 +161,15 @@ nni_http_conn_close(nni_http_conn *conn) } nng_err -nni_http_get_addr(nni_http_conn *conn, const char *opt, nng_sockaddr *addrp) +nni_http_peer_addr(nni_http_conn *conn, const nng_sockaddr **sap) { - nng_err rv; - nni_mtx_lock(&conn->mtx); - rv = nng_stream_get_addr(conn->sock, opt, addrp); - nni_mtx_unlock(&conn->mtx); - return (rv); + return nng_stream_peer_addr(conn->sock, sap); +} + +nng_err +nni_http_self_addr(nni_http_conn *conn, const nng_sockaddr **sap) +{ + return nng_stream_self_addr(conn->sock, sap); } // http_buf_pull_up pulls the content of the read buffer back to the diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 8c225e5e..edf5e609 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -309,13 +309,23 @@ nng_http_read_response(nng_http *conn, nng_aio *aio) nng_err nng_http_remote_address(nng_http *conn, nng_sockaddr *addrp) { - return (nni_http_get_addr(conn, NNG_OPT_REMADDR, addrp)); + const nng_sockaddr *sap; + nng_err rv; + if ((rv = nni_http_peer_addr(conn, &sap)) == NNG_OK) { + *addrp = *sap; + } + return (rv); } nng_err nng_http_local_address(nng_http *conn, nng_sockaddr *addrp) { - return (nni_http_get_addr(conn, NNG_OPT_LOCADDR, addrp)); + const nng_sockaddr *sap; + nng_err rv; + if ((rv = nni_http_self_addr(conn, &sap)) == NNG_OK) { + *addrp = *sap; + } + return (rv); } nng_err diff --git a/src/supplemental/tls/tls_stream.c b/src/supplemental/tls/tls_stream.c index d3dd9497..169e8fb0 100644 --- a/src/supplemental/tls/tls_stream.c +++ b/src/supplemental/tls/tls_stream.c @@ -143,6 +143,8 @@ tls_stream_conn_cb(void *arg) static nng_err tls_stream_get( void *arg, const char *name, void *buf, size_t *szp, nni_type t); +static nng_err tls_stream_self_addr(void *arg, const nng_sockaddr **); +static nng_err tls_stream_peer_addr(void *arg, const nng_sockaddr **); static nng_err tls_stream_peer_cert(void *arg, nng_tls_cert **); int @@ -168,6 +170,8 @@ nni_tls_stream_alloc(tls_stream **tsp, nng_tls_config *cfg, nng_aio *user_aio) ts->stream.s_send = tls_stream_send; ts->stream.s_recv = tls_stream_recv; ts->stream.s_get = tls_stream_get; + ts->stream.s_self_addr = tls_stream_self_addr; + ts->stream.s_peer_addr = tls_stream_peer_addr; ts->stream.s_peer_cert = tls_stream_peer_cert; nni_aio_init(&ts->conn_aio, tls_stream_conn_cb, ts); @@ -236,3 +240,17 @@ tls_stream_get(void *arg, const char *name, void *buf, size_t *szp, nni_type t) } return (nni_getopt(tls_stream_options, name, ts, buf, szp, t)); } + +static nng_err +tls_stream_self_addr(void *arg, const nng_sockaddr **sap) +{ + tls_stream *ts = arg; + return (nng_stream_self_addr(ts->conn.bio, sap)); +} + +static nng_err +tls_stream_peer_addr(void *arg, const nng_sockaddr **sap) +{ + tls_stream *ts = arg; + return (nng_stream_peer_addr(ts->conn.bio, sap)); +} diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index d78c032b..2ff126e3 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -193,6 +193,8 @@ static void ws_str_send(void *, nng_aio *); static void ws_str_recv(void *, nng_aio *); static nng_err ws_str_get(void *, const char *, void *, size_t *, nni_type); static nng_err ws_str_peer_cert(void *, nng_tls_cert **); +static nng_err ws_str_self_addr(void *, const nng_sockaddr **); +static nng_err ws_str_peer_addr(void *, const nng_sockaddr **); static void ws_listener_close(void *); static void ws_listener_free(void *); @@ -1402,6 +1404,8 @@ ws_init(nni_ws **wsp) ws->ops.s_recv = ws_str_recv; ws->ops.s_get = ws_str_get; ws->ops.s_peer_cert = ws_str_peer_cert; + ws->ops.s_peer_addr = ws_str_peer_addr; + ws->ops.s_self_addr = ws_str_self_addr; ws->fragsize = 1 << 20; // we won't send a frame larger than this *wsp = ws; @@ -2841,3 +2845,17 @@ ws_str_peer_cert(void *arg, nng_tls_cert **certp) nni_mtx_unlock(&ws->mtx); return (nni_http_conn_peer_cert(ws->http, certp)); } + +static nng_err +ws_str_peer_addr(void *arg, const nng_sockaddr **sap) +{ + nni_ws *ws = arg; + return (nni_http_peer_addr(ws->http, sap)); +} + +static nng_err +ws_str_self_addr(void *arg, const nng_sockaddr **sap) +{ + nni_ws *ws = arg; + return (nni_http_self_addr(ws->http, sap)); +} diff --git a/src/supplemental/websocket/websocket_test.c b/src/supplemental/websocket/websocket_test.c index cb502ef4..66c9617e 100644 --- a/src/supplemental/websocket/websocket_test.c +++ b/src/supplemental/websocket/websocket_test.c @@ -131,6 +131,8 @@ test_websocket_conn_props(void) nng_stream_listener *l = NULL; nng_sockaddr sa1; nng_sockaddr sa2; + const nng_sockaddr *sap1; + const nng_sockaddr *sap2; size_t sz; nng_aio *daio = NULL; nng_aio *laio = NULL; @@ -182,11 +184,15 @@ test_websocket_conn_props(void) NUTS_TRUE(c2 != NULL); // Let's compare the peer addresses + NUTS_PASS(nng_stream_self_addr(c1, &sap1)); + NUTS_PASS(nng_stream_peer_addr(c2, &sap2)); NUTS_PASS(nng_stream_get_addr(c1, NNG_OPT_LOCADDR, &sa1)); NUTS_PASS(nng_stream_get_addr(c2, NNG_OPT_REMADDR, &sa2)); NUTS_TRUE(sa1.s_family == sa2.s_family); NUTS_TRUE(sa1.s_in.sa_addr == sa2.s_in.sa_addr); NUTS_TRUE(sa1.s_in.sa_port == sa2.s_in.sa_port); + NUTS_TRUE(memcmp(sap1, &sa1, sizeof(sa1)) == 0); + NUTS_TRUE(memcmp(sap2, &sa2, sizeof(sa2)) == 0); NUTS_PASS(nng_stream_get_addr(c1, NNG_OPT_REMADDR, &sa1)); NUTS_PASS(nng_stream_get_addr(c2, NNG_OPT_LOCADDR, &sa2)); -- cgit v1.2.3-70-g09d2