diff options
Diffstat (limited to 'src/platform/posix')
| -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 |
4 files changed, 434 insertions, 58 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)); +} |
