From a73ff5363eae228009413872b05aff758a46c5ca Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 29 Dec 2018 21:28:49 -0800 Subject: fixes #825 TCP public API should use generic setopt/getopt This changes much of the internal API for TCP option handling, and includes hooks for some of this in various consumers. Note that the consumers still need to have additional work done to complete them, which will be part of providing public "raw" TLS and WebSocket APIs. We would also like to finish addressing the call sites of nni_tcp_listener_start() that assume the sockaddr is modified -- it would be superior to use the NNG_OPT_LOCADDR option. Thaat will be addressed in a follow up PR. --- src/platform/posix/posix_tcp.h | 10 +- src/platform/posix/posix_tcpconn.c | 159 ++++++++++++++++++++++++++- src/platform/posix/posix_tcpdial.c | 207 +++++++++++++++++++++++++++-------- src/platform/posix/posix_tcplisten.c | 116 +++++++++++++++++++- src/platform/windows/win_impl.h | 4 +- src/platform/windows/win_tcp.h | 13 ++- src/platform/windows/win_tcpconn.c | 140 +++++++++++++++++++++-- src/platform/windows/win_tcpdial.c | 205 ++++++++++++++++++++++++++-------- src/platform/windows/win_tcplisten.c | 122 ++++++++++++++++++++- 9 files changed, 851 insertions(+), 125 deletions(-) (limited to 'src/platform') diff --git a/src/platform/posix/posix_tcp.h b/src/platform/posix/posix_tcp.h index 633a63b5..788fcbf8 100644 --- a/src/platform/posix/posix_tcp.h +++ b/src/platform/posix/posix_tcp.h @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,7 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_POSIX #include "platform/posix/posix_aio.h" struct nni_tcp_conn { @@ -27,6 +27,8 @@ struct nni_tcp_conn { struct nni_tcp_dialer { nni_list connq; // pending connections bool closed; + bool nodelay; + bool keepalive; struct sockaddr_storage src; size_t srclen; nni_mtx mtx; @@ -37,10 +39,10 @@ struct nni_tcp_listener { nni_list acceptq; bool started; bool closed; + bool nodelay; + bool keepalive; nni_mtx mtx; }; extern int nni_posix_tcp_conn_init(nni_tcp_conn **, nni_posix_pfd *); -extern void nni_posix_tcp_conn_start(nni_tcp_conn *); - -#endif // NNG_PLATFORM_POSIX +extern void nni_posix_tcp_conn_start(nni_tcp_conn *, int, int); diff --git a/src/platform/posix/posix_tcpconn.c b/src/platform/posix/posix_tcpconn.c index 788c4e9f..a10e102f 100644 --- a/src/platform/posix/posix_tcpconn.c +++ b/src/platform/posix/posix_tcpconn.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,8 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_POSIX - #include #include #include @@ -369,6 +368,152 @@ nni_tcp_conn_set_nodelay(nni_tcp_conn *c, bool nodelay) return (0); } +static int +tcp_conn_get_peername(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn * c = arg; + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + int fd = nni_posix_pfd_fd(c->pfd); + int rv; + nng_sockaddr sa; + + if (getpeername(fd, (void *) &ss, &sslen) != 0) { + return (nni_plat_errno(errno)); + } + if ((rv = nni_posix_sockaddr2nn(&sa, &ss)) == 0) { + rv = nni_copyout_sockaddr(&sa, buf, szp, t); + } + return (rv); +} + +static int +tcp_conn_get_sockname(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn * c = arg; + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + int fd = nni_posix_pfd_fd(c->pfd); + int rv; + nng_sockaddr sa; + + if (getsockname(fd, (void *) &ss, &sslen) != 0) { + return (nni_plat_errno(errno)); + } + if ((rv = nni_posix_sockaddr2nn(&sa, &ss)) == 0) { + rv = nni_copyout_sockaddr(&sa, buf, szp, t); + } + return (rv); +} + +static int +tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_conn *c = arg; + int fd; + bool b; + int val; + int rv; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (c == NULL)) { + return (rv); + } + val = b ? 1 : 0; + fd = nni_posix_pfd_fd(c->pfd); + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != 0) { + return (nni_plat_errno(errno)); + } + return (0); +} + +static int +tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_conn *c = arg; + int fd; + bool b; + int val; + int rv; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (c == NULL)) { + return (rv); + } + val = b ? 1 : 0; + fd = nni_posix_pfd_fd(c->pfd); + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0) { + return (nni_plat_errno(errno)); + } + return (0); +} + +static int +tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn *c = arg; + int fd = nni_posix_pfd_fd(c->pfd); + int val = 0; + socklen_t valsz = sizeof(val); + + if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, &valsz) != 0) { + return (nni_plat_errno(errno)); + } + + return (nni_copyout_bool(val, buf, szp, t)); +} + +static int +tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn *c = arg; + int fd = nni_posix_pfd_fd(c->pfd); + int val = 0; + socklen_t valsz = sizeof(val); + + if (getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, &valsz) != 0) { + return (nni_plat_errno(errno)); + } + + return (nni_copyout_bool(val, buf, szp, t)); +} + +static const nni_option tcp_conn_options[] = { + { + .o_name = NNG_OPT_REMADDR, + .o_get = tcp_conn_get_peername, + }, + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_conn_get_sockname, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_get = tcp_conn_get_nodelay, + .o_set = tcp_conn_set_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_get = tcp_conn_get_keepalive, + .o_set = tcp_conn_set_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_conn_getopt( + nni_tcp_conn *c, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_conn_options, name, c, buf, szp, t)); +} + +int +nni_tcp_conn_setopt( + nni_tcp_conn *c, const char *name, const void *buf, size_t sz, nni_type t) +{ + return (nni_setopt(tcp_conn_options, name, c, buf, sz, t)); +} + int nni_posix_tcp_conn_init(nni_tcp_conn **cp, nni_posix_pfd *pfd) { @@ -390,8 +535,14 @@ nni_posix_tcp_conn_init(nni_tcp_conn **cp, nni_posix_pfd *pfd) } void -nni_posix_tcp_conn_start(nni_tcp_conn *c) +nni_posix_tcp_conn_start(nni_tcp_conn *c, int nodelay, int keepalive) { + // COnfigure the initial socket options. + (void) setsockopt( + c->pfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(int)); + (void) setsockopt( + c->pfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(int)); + nni_posix_pfd_set_cb(c->pfd, tcp_conn_cb, c); } @@ -407,5 +558,3 @@ nni_tcp_conn_fini(nni_tcp_conn *c) NNI_FREE_STRUCT(c); } - -#endif // NNG_PLATFORM_POSIX diff --git a/src/platform/posix/posix_tcpdial.c b/src/platform/posix/posix_tcpdial.c index 918ee9ba..cfb3482c 100644 --- a/src/platform/posix/posix_tcpdial.c +++ b/src/platform/posix/posix_tcpdial.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,8 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_POSIX - #include #include #include @@ -105,6 +104,8 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg) nni_tcp_dialer *d = c->dialer; nni_aio * aio; int rv; + int ka; + int nd; nni_mtx_lock(&d->mtx); aio = c->dial_aio; @@ -135,6 +136,9 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg) c->dial_aio = NULL; nni_aio_list_remove(aio); nni_aio_set_prov_extra(aio, 0, NULL); + nd = d->nodelay ? 1 : 0; + ka = d->keepalive ? 1 : 0; + nni_mtx_unlock(&d->mtx); if (rv != 0) { @@ -144,51 +148,11 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg) return; } - nni_posix_tcp_conn_start(c); + nni_posix_tcp_conn_start(c, nd, ka); nni_aio_set_output(aio, 0, c); nni_aio_finish(aio, 0, 0); } -int -nni_tcp_dialer_set_src_addr(nni_tcp_dialer *d, const nni_sockaddr *sa) -{ - struct sockaddr_storage ss; - struct sockaddr_in * sin; - struct sockaddr_in6 * sin6; - size_t sslen; - - if ((sslen = nni_posix_nn2sockaddr(&ss, sa)) == 0) { - return (NNG_EADDRINVAL); - } - // Ensure we are either IPv4 or IPv6, and port is not set. (We - // do not allow binding to a specific port.) - switch (ss.ss_family) { - case AF_INET: - sin = (void *) &ss; - if (sin->sin_port != 0) { - return (NNG_EADDRINVAL); - } - break; - case AF_INET6: - sin6 = (void *) &ss; - if (sin6->sin6_port != 0) { - return (NNG_EADDRINVAL); - } - break; - default: - return (NNG_EADDRINVAL); - } - nni_mtx_lock(&d->mtx); - if (d->closed) { - nni_mtx_unlock(&d->mtx); - return (NNG_ECLOSED); - } - d->src = ss; - d->srclen = sslen; - nni_mtx_unlock(&d->mtx); - return (0); -} - // We don't give local address binding support. Outbound dialers always // get an ephemeral port. void @@ -200,6 +164,8 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) size_t sslen; int fd; int rv; + int ka; + int nd; if (nni_aio_begin(aio) != 0) { return; @@ -263,8 +229,10 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) // Immediate connect, cool! This probably only happens // on loopback, and probably not on every platform. nni_aio_set_prov_extra(aio, 0, NULL); + nd = d->nodelay ? 1 : 0; + ka = d->keepalive ? 1 : 0; nni_mtx_unlock(&d->mtx); - nni_posix_tcp_conn_start(c); + nni_posix_tcp_conn_start(c, nd, ka); nni_aio_set_output(aio, 0, c); nni_aio_finish(aio, 0, 0); return; @@ -276,4 +244,153 @@ error: nni_aio_finish_error(aio, rv); } -#endif // NNG_PLATFORM_POSIX +static int +tcp_dialer_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer *d = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (d == NULL)) { + return (rv); + } + nni_mtx_lock(&d->mtx); + d->nodelay = b; + nni_mtx_unlock(&d->mtx); + return (0); +} + +static int +tcp_dialer_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_dialer *d = arg; + nni_mtx_lock(&d->mtx); + b = d->nodelay; + nni_mtx_unlock(&d->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_dialer_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer *d = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (d == NULL)) { + return (rv); + } + nni_mtx_lock(&d->mtx); + d->keepalive = b; + nni_mtx_unlock(&d->mtx); + return (0); +} + +static int +tcp_dialer_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_dialer *d = arg; + nni_mtx_lock(&d->mtx); + b = d->keepalive; + nni_mtx_unlock(&d->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_dialer_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_dialer *d = arg; + nng_sockaddr sa; + + nni_mtx_lock(&d->mtx); + if (nni_posix_sockaddr2nn(&sa, &d->src) != 0) { + sa.s_family = NNG_AF_UNSPEC; + } + nni_mtx_unlock(&d->mtx); + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_dialer_set_locaddr(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer * d = arg; + nng_sockaddr sa; + struct sockaddr_storage ss; + struct sockaddr_in * sin; + struct sockaddr_in6 * sin6; + size_t sslen; + int rv; + + if ((rv = nni_copyin_sockaddr(&sa, buf, sz, t)) != 0) { + return (rv); + } + if ((sslen = nni_posix_nn2sockaddr(&ss, &sa)) == 0) { + return (NNG_EADDRINVAL); + } + // Ensure we are either IPv4 or IPv6, and port is not set. (We + // do not allow binding to a specific port.) + switch (ss.ss_family) { + case AF_INET: + sin = (void *) &ss; + if (sin->sin_port != 0) { + return (NNG_EADDRINVAL); + } + break; + case AF_INET6: + sin6 = (void *) &ss; + if (sin6->sin6_port != 0) { + return (NNG_EADDRINVAL); + } + break; + default: + return (NNG_EADDRINVAL); + } + if (d != NULL) { + nni_mtx_lock(&d->mtx); + if (d->closed) { + nni_mtx_unlock(&d->mtx); + return (NNG_ECLOSED); + } + d->src = ss; + d->srclen = sslen; + nni_mtx_unlock(&d->mtx); + } + return (0); +} + +static const nni_option tcp_dialer_options[] = { + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_dialer_get_locaddr, + .o_set = tcp_dialer_set_locaddr, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_get = tcp_dialer_get_nodelay, + .o_set = tcp_dialer_set_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_get = tcp_dialer_get_keepalive, + .o_set = tcp_dialer_set_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_dialer_getopt( + nni_tcp_dialer *d, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_dialer_options, name, d, buf, szp, t)); +} + +int +nni_tcp_dialer_setopt(nni_tcp_dialer *d, const char *name, const void *buf, + size_t sz, nni_type t) +{ + return (nni_setopt(tcp_dialer_options, name, d, buf, sz, t)); +} diff --git a/src/platform/posix/posix_tcplisten.c b/src/platform/posix/posix_tcplisten.c index bc414cd0..82334431 100644 --- a/src/platform/posix/posix_tcplisten.c +++ b/src/platform/posix/posix_tcplisten.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,8 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_POSIX - #include #include #include @@ -82,6 +81,8 @@ tcp_listener_doaccept(nni_tcp_listener *l) int newfd; int fd; int rv; + int nd; + int ka; nni_posix_pfd *pfd; nni_tcp_conn * c; @@ -139,8 +140,10 @@ tcp_listener_doaccept(nni_tcp_listener *l) continue; } + ka = l->keepalive ? 1 : 0; + nd = l->nodelay ? 1 : 0; nni_aio_list_remove(aio); - nni_posix_tcp_conn_start(c); + nni_posix_tcp_conn_start(c, nd, ka); nni_aio_set_output(aio, 0, c); nni_aio_finish(aio, 0, 0); } @@ -315,4 +318,109 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) nni_mtx_unlock(&l->mtx); } -#endif // NNG_PLATFORM_POSIX +static int +tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_listener *l = arg; + nng_sockaddr sa; + nni_mtx_lock(&l->mtx); + if (l->started) { + struct sockaddr_storage ss; + socklen_t len = sizeof(ss); + (void) getsockname( + nni_posix_pfd_fd(l->pfd), (void *) &ss, &len); + (void) nni_posix_sockaddr2nn(&sa, &ss); + } else { + sa.s_family = NNG_AF_UNSPEC; + } + nni_mtx_unlock(&l->mtx); + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_listener *l = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { + return (rv); + } + nni_mtx_lock(&l->mtx); + l->nodelay = b; + nni_mtx_unlock(&l->mtx); + return (0); +} + +static int +tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); + b = l->nodelay; + nni_mtx_unlock(&l->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_listener *l = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { + return (rv); + } + nni_mtx_lock(&l->mtx); + l->keepalive = b; + nni_mtx_unlock(&l->mtx); + return (0); +} + +static int +tcp_listener_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); + b = l->keepalive; + nni_mtx_unlock(&l->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static const nni_option tcp_listener_options[] = { + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_listener_get_locaddr, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_set = tcp_listener_set_nodelay, + .o_get = tcp_listener_get_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_set = tcp_listener_set_keepalive, + .o_get = tcp_listener_get_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_listener_getopt( + nni_tcp_listener *l, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_listener_options, name, l, buf, szp, t)); +} + +int +nni_tcp_listener_setopt(nni_tcp_listener *l, const char *name, const void *buf, + size_t sz, nni_type t) +{ + return (nni_setopt(tcp_listener_options, name, l, buf, sz, t)); +} diff --git a/src/platform/windows/win_impl.h b/src/platform/windows/win_impl.h index fd4c9343..cd15804a 100644 --- a/src/platform/windows/win_impl.h +++ b/src/platform/windows/win_impl.h @@ -75,9 +75,7 @@ struct nni_plat_flock { extern int nni_win_error(int); -extern int nni_win_tcp_conn_init(nni_tcp_conn **, SOCKET); -extern void nni_win_tcp_conn_set_addrs( - nni_tcp_conn *, const SOCKADDR_STORAGE *, const SOCKADDR_STORAGE *); +extern int nni_win_tcp_conn_init(nni_tcp_conn **, SOCKET); extern int nni_win_io_sysinit(void); extern void nni_win_io_sysfini(void); diff --git a/src/platform/windows/win_tcp.h b/src/platform/windows/win_tcp.h index 9c7a4d0e..96854ac1 100644 --- a/src/platform/windows/win_tcp.h +++ b/src/platform/windows/win_tcp.h @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -15,7 +16,7 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_WINDOWS +#include struct nni_tcp_conn { SOCKET s; @@ -42,6 +43,8 @@ struct nni_tcp_dialer { LPFN_CONNECTEX connectex; // looked up name via ioctl nni_list aios; // in flight connections bool closed; + bool nodelay; // initial value for child conns + bool keepalive; // initial value for child conns SOCKADDR_STORAGE src; size_t srclen; nni_mtx mtx; @@ -53,6 +56,8 @@ struct nni_tcp_listener { nni_list aios; bool closed; bool started; + bool nodelay; // initial value for child conns + bool keepalive; // initial value for child conns LPFN_ACCEPTEX acceptex; LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs; SOCKADDR_STORAGE ss; @@ -60,10 +65,6 @@ struct nni_tcp_listener { nni_reap_item reap; }; -extern int nni_win_tcp_conn_init(nni_tcp_conn **, SOCKET); -extern void nni_win_tcp_conn_set_addrs( - nni_tcp_conn *, const SOCKADDR_STORAGE *, const SOCKADDR_STORAGE *); - -#endif // NNG_PLATFORM_WINDOWS +extern int nni_win_tcp_conn_init(nni_tcp_conn **, SOCKET); #endif // NNG_PLATFORM_WIN_WINTCP_H diff --git a/src/platform/windows/win_tcpconn.c b/src/platform/windows/win_tcpconn.c index 68c72b9b..54d22dea 100644 --- a/src/platform/windows/win_tcpconn.c +++ b/src/platform/windows/win_tcpconn.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -12,8 +13,6 @@ #include "win_tcp.h" -#ifdef NNG_PLATFORM_WINDOWS - #include #include @@ -292,14 +291,6 @@ nni_win_tcp_conn_init(nni_tcp_conn **connp, SOCKET s) return (0); } -void -nni_win_tcp_conn_set_addrs( - nni_tcp_conn *c, const SOCKADDR_STORAGE *loc, const SOCKADDR_STORAGE *rem) -{ - memcpy(&c->sockname, loc, sizeof(*loc)); - memcpy(&c->peername, rem, sizeof(*rem)); -} - void nni_tcp_conn_close(nni_tcp_conn *c) { @@ -361,6 +352,133 @@ nni_tcp_conn_set_keepalive(nni_tcp_conn *c, bool val) return (0); } +static int +tcp_conn_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) < 0) { + return (NNG_EADDRINVAL); + } + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_conn_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) < 0) { + return (NNG_EADDRINVAL); + } + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_conn *c = arg; + bool val; + BOOL b; + int rv; + if ((rv = nni_copyin_bool(&val, buf, sz, t)) != 0) { + return (rv); + } + b = val ? TRUE : FALSE; + if (setsockopt( + c->s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)) != 0) { + return (nni_win_error(WSAGetLastError())); + } + return (0); +} + +static int +tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_conn *c = arg; + bool val; + BOOL b; + int rv; + + if ((rv = nni_copyin_bool(&val, buf, sz, t)) != 0) { + return (rv); + } + b = val ? TRUE : FALSE; + if (setsockopt( + c->s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)) != 0) { + return (nni_win_error(WSAGetLastError())); + } + return (0); +} + +static int +tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn *c = arg; + BOOL b = 0; + int bsz = sizeof(b); + + if ((getsockopt(c->s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, &bsz)) != + 0) { + return (nni_win_error(WSAGetLastError())); + } + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_conn *c = arg; + BOOL b = 0; + int bsz = sizeof(b); + + if ((getsockopt(c->s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, &bsz)) != + 0) { + return (nni_win_error(WSAGetLastError())); + } + return (nni_copyout_bool(b, buf, szp, t)); +} + +static const nni_option tcp_conn_options[] = { + { + .o_name = NNG_OPT_REMADDR, + .o_get = tcp_conn_get_peername, + }, + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_conn_get_sockname, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_get = tcp_conn_get_nodelay, + .o_set = tcp_conn_set_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_get = tcp_conn_get_keepalive, + .o_set = tcp_conn_set_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_conn_getopt( + nni_tcp_conn *c, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_conn_options, name, c, buf, szp, t)); +} + +int +nni_tcp_conn_setopt( + nni_tcp_conn *c, const char *name, const void *buf, size_t sz, nni_type t) +{ + return (nni_setopt(tcp_conn_options, name, c, buf, sz, t)); +} + void nni_tcp_conn_fini(nni_tcp_conn *c) { @@ -384,5 +502,3 @@ nni_tcp_conn_fini(nni_tcp_conn *c) nni_mtx_fini(&c->mtx); NNI_FREE_STRUCT(c); } - -#endif // NNG_PLATFORM_WINDOWS diff --git a/src/platform/windows/win_tcpdial.c b/src/platform/windows/win_tcpdial.c index 1225b560..64b4e800 100644 --- a/src/platform/windows/win_tcpdial.c +++ b/src/platform/windows/win_tcpdial.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,8 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_WINDOWS - #include "win_tcp.h" #include @@ -115,6 +114,8 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt) nni_tcp_conn * c = io->ptr; nni_tcp_dialer *d = c->dialer; nni_aio * aio = c->conn_aio; + BOOL ka; + BOOL nd; NNI_ARG_UNUSED(cnt); @@ -131,6 +132,8 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt) if (c->conn_rv != 0) { rv = c->conn_rv; } + nd = d->nodelay ? TRUE : FALSE; + ka = d->keepalive ? TRUE : FALSE; nni_mtx_unlock(&d->mtx); if (rv != 0) { @@ -140,49 +143,16 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt) DWORD yes = 1; (void) setsockopt(c->s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, (char *) &yes, sizeof(yes)); - nni_aio_set_output(aio, 0, c); - nni_aio_finish(aio, 0, 0); - } -} -int -nni_tcp_dialer_set_src_addr(nni_tcp_dialer *d, const nni_sockaddr *sa) -{ - SOCKADDR_STORAGE ss; - struct sockaddr_in * sin; - struct sockaddr_in6 *sin6; - size_t sslen; + (void) setsockopt( + c->s, SOL_SOCKET, SO_KEEPALIVE, (char *) &ka, sizeof(ka)); - if ((sslen = nni_win_nn2sockaddr(&ss, sa)) == 0) { - return (NNG_EADDRINVAL); - } - // Ensure we are either IPv4 or IPv6, and port is not set. (We - // do not allow binding to a specific port.) - switch (ss.ss_family) { - case AF_INET: - sin = (void *) &ss; - if (sin->sin_port != 0) { - return (NNG_EADDRINVAL); - } - break; - case AF_INET6: - sin6 = (void *) &ss; - if (sin6->sin6_port != 0) { - return (NNG_EADDRINVAL); - } - break; - default: - return (NNG_EADDRINVAL); - } - nni_mtx_lock(&d->mtx); - if (d->closed) { - nni_mtx_unlock(&d->mtx); - return (NNG_ECLOSED); + (void) setsockopt( + c->s, IPPROTO_TCP, TCP_NODELAY, (char *) &nd, sizeof(nd)); + + nni_aio_set_output(aio, 0, c); + nni_aio_finish(aio, 0, 0); } - d->src = ss; - d->srclen = sslen; - nni_mtx_unlock(&d->mtx); - return (0); } void @@ -273,4 +243,153 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio) nni_mtx_unlock(&d->mtx); } -#endif // NNG_PLATFORM_WINDOWS +static int +tcp_dialer_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer *d = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (d == NULL)) { + return (rv); + } + nni_mtx_lock(&d->mtx); + d->nodelay = b; + nni_mtx_unlock(&d->mtx); + return (0); +} + +static int +tcp_dialer_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_dialer *d = arg; + nni_mtx_lock(&d->mtx); + b = d->nodelay; + nni_mtx_unlock(&d->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_dialer_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer *d = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (d == NULL)) { + return (rv); + } + nni_mtx_lock(&d->mtx); + d->keepalive = b; + nni_mtx_unlock(&d->mtx); + return (0); +} + +static int +tcp_dialer_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_dialer *d = arg; + nni_mtx_lock(&d->mtx); + b = d->keepalive; + nni_mtx_unlock(&d->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_dialer_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_dialer *d = arg; + nng_sockaddr sa; + + nni_mtx_lock(&d->mtx); + if (nni_win_sockaddr2nn(&sa, &d->src) != 0) { + sa.s_family = NNG_AF_UNSPEC; + } + nni_mtx_unlock(&d->mtx); + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_dialer_set_locaddr(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_dialer * d = arg; + nng_sockaddr sa; + SOCKADDR_STORAGE ss; + struct sockaddr_in * sin; + struct sockaddr_in6 *sin6; + size_t sslen; + int rv; + + if ((rv = nni_copyin_sockaddr(&sa, buf, sz, t)) != 0) { + return (rv); + } + if ((sslen = nni_win_nn2sockaddr(&ss, &sa)) == 0) { + return (NNG_EADDRINVAL); + } + // Ensure we are either IPv4 or IPv6, and port is not set. (We + // do not allow binding to a specific port.) + switch (ss.ss_family) { + case AF_INET: + sin = (void *) &ss; + if (sin->sin_port != 0) { + return (NNG_EADDRINVAL); + } + break; + case AF_INET6: + sin6 = (void *) &ss; + if (sin6->sin6_port != 0) { + return (NNG_EADDRINVAL); + } + break; + default: + return (NNG_EADDRINVAL); + } + if (d != NULL) { + nni_mtx_lock(&d->mtx); + if (d->closed) { + nni_mtx_unlock(&d->mtx); + return (NNG_ECLOSED); + } + d->src = ss; + d->srclen = sslen; + nni_mtx_unlock(&d->mtx); + } + return (0); +} + +static const nni_option tcp_dialer_options[] = { + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_dialer_get_locaddr, + .o_set = tcp_dialer_set_locaddr, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_get = tcp_dialer_get_nodelay, + .o_set = tcp_dialer_set_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_get = tcp_dialer_get_keepalive, + .o_set = tcp_dialer_set_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_dialer_getopt( + nni_tcp_dialer *d, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_dialer_options, name, d, buf, szp, t)); +} + +int +nni_tcp_dialer_setopt(nni_tcp_dialer *d, const char *name, const void *buf, + size_t sz, nni_type t) +{ + return (nni_setopt(tcp_dialer_options, name, d, buf, sz, t)); +} diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c index f0e195be..750de13b 100644 --- a/src/platform/windows/win_tcplisten.c +++ b/src/platform/windows/win_tcplisten.c @@ -1,6 +1,7 @@ // // Copyright 2018 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -10,8 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_PLATFORM_WINDOWS - #include #include #include @@ -76,6 +75,8 @@ tcp_accept_cb(nni_win_io *io, int rv, size_t cnt) SOCKADDR * sa1; SOCKADDR * sa2; DWORD yes; + BOOL nd; + BOOL ka; NNI_ARG_UNUSED(cnt); @@ -92,6 +93,8 @@ tcp_accept_cb(nni_win_io *io, int rv, size_t cnt) if (c->conn_rv != 0) { rv = c->conn_rv; } + nd = l->nodelay ? TRUE : FALSE; + ka = l->keepalive ? TRUE : FALSE; nni_mtx_unlock(&l->mtx); if (rv != 0) { @@ -109,6 +112,13 @@ tcp_accept_cb(nni_win_io *io, int rv, size_t cnt) yes = 1; (void) setsockopt(c->s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *) &yes, sizeof(yes)); + + (void) setsockopt( + c->s, SOL_SOCKET, SO_KEEPALIVE, (char *) &ka, sizeof(ka)); + + (void) setsockopt( + c->s, IPPROTO_TCP, TCP_NODELAY, (char *) &nd, sizeof(nd)); + nni_aio_set_output(aio, 0, c); nni_aio_finish(aio, 0, 0); } @@ -130,6 +140,11 @@ nni_tcp_listener_init(nni_tcp_listener **lp) return (rv); } + // We assume these defaults -- not everyone will agree, but anyone + // can change them. + l->keepalive = false; + l->nodelay = true; + *lp = l; return (0); } @@ -313,4 +328,105 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) nni_mtx_unlock(&l->mtx); } -#endif // NNG_PLATFORM_WINDOWS +static int +tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) +{ + nni_tcp_listener *l = arg; + nng_sockaddr sa; + nni_mtx_lock(&l->mtx); + if (l->started) { + nni_win_sockaddr2nn(&sa, &l->ss); + } else { + sa.s_family = NNG_AF_UNSPEC; + } + nni_mtx_unlock(&l->mtx); + return (nni_copyout_sockaddr(&sa, buf, szp, t)); +} + +static int +tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_listener *l = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { + return (rv); + } + nni_mtx_lock(&l->mtx); + l->nodelay = b; + nni_mtx_unlock(&l->mtx); + return (0); +} + +static int +tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); + b = l->nodelay; + nni_mtx_unlock(&l->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static int +tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) +{ + nni_tcp_listener *l = arg; + int rv; + bool b; + + if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { + return (rv); + } + nni_mtx_lock(&l->mtx); + l->keepalive = b; + nni_mtx_unlock(&l->mtx); + return (0); +} + +static int +tcp_listener_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) +{ + bool b; + nni_tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); + b = l->keepalive; + nni_mtx_unlock(&l->mtx); + return (nni_copyout_bool(b, buf, szp, t)); +} + +static const nni_option tcp_listener_options[] = { + { + .o_name = NNG_OPT_LOCADDR, + .o_get = tcp_listener_get_locaddr, + }, + { + .o_name = NNG_OPT_TCP_NODELAY, + .o_set = tcp_listener_set_nodelay, + .o_get = tcp_listener_get_nodelay, + }, + { + .o_name = NNG_OPT_TCP_KEEPALIVE, + .o_set = tcp_listener_set_keepalive, + .o_get = tcp_listener_get_keepalive, + }, + { + .o_name = NULL, + }, +}; + +int +nni_tcp_listener_getopt( + nni_tcp_listener *l, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_listener_options, name, l, buf, szp, t)); +} + +int +nni_tcp_listener_setopt(nni_tcp_listener *l, const char *name, const void *buf, + size_t sz, nni_type t) +{ + return (nni_setopt(tcp_listener_options, name, l, buf, sz, t)); +} -- cgit v1.2.3-70-g09d2