diff options
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/posix/posix_tcp.h | 10 | ||||
| -rw-r--r-- | src/platform/posix/posix_tcpconn.c | 159 | ||||
| -rw-r--r-- | src/platform/posix/posix_tcpdial.c | 207 | ||||
| -rw-r--r-- | src/platform/posix/posix_tcplisten.c | 116 | ||||
| -rw-r--r-- | src/platform/windows/win_impl.h | 4 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.h | 13 | ||||
| -rw-r--r-- | src/platform/windows/win_tcpconn.c | 140 | ||||
| -rw-r--r-- | src/platform/windows/win_tcpdial.c | 205 | ||||
| -rw-r--r-- | src/platform/windows/win_tcplisten.c | 122 |
9 files changed, 851 insertions, 125 deletions
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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <nng/transport/tcp/tcp.h> 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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <malloc.h> #include <stdio.h> @@ -293,14 +292,6 @@ nni_win_tcp_conn_init(nni_tcp_conn **connp, SOCKET s) } 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) { nni_mtx_lock(&c->mtx); @@ -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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <malloc.h> @@ -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. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Devolutions <info@devolutions.net> // // 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 <malloc.h> #include <stdbool.h> #include <stdio.h> @@ -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)); +} |
