diff options
| -rw-r--r-- | src/core/platform.h | 6 | ||||
| -rw-r--r-- | src/core/strs.c | 4 | ||||
| -rw-r--r-- | src/platform/posix/posix_aio.h | 2 | ||||
| -rw-r--r-- | src/platform/posix/posix_pipedesc.c | 24 | ||||
| -rw-r--r-- | src/platform/posix/posix_tcp.c | 12 | ||||
| -rw-r--r-- | src/platform/windows/win_debug.c | 1 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.c | 73 | ||||
| -rw-r--r-- | src/transport/tcp/tcp.c | 32 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/tcp.c | 42 | ||||
| -rw-r--r-- | tests/tcp6.c | 86 | ||||
| -rw-r--r-- | tests/trantest.h | 4 |
12 files changed, 271 insertions, 16 deletions
diff --git a/src/core/platform.h b/src/core/platform.h index 7bfb370a..10074677 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -233,6 +233,12 @@ extern void nni_plat_tcp_pipe_send(nni_plat_tcp_pipe *, nni_aio *); // The platform may modify the iovs. extern void nni_plat_tcp_pipe_recv(nni_plat_tcp_pipe *, nni_aio *); +// nni_plat_tcp_pipe_peername gets the peer name. +extern int nni_plat_tcp_pipe_peername(nni_plat_tcp_pipe *, nni_sockaddr *); + +// nni_plat_tcp_pipe_sockname gets the local name. +extern int nni_plat_tcp_pipe_sockname(nni_plat_tcp_pipe *, nni_sockaddr *); + // nni_plat_tcp_resolv resolves a TCP name asynchronously. The family // should be one of NNG_AF_INET, NNG_AF_INET6, or NNG_AF_UNSPEC. The // first two constrain the name to those families, while the third will diff --git a/src/core/strs.c b/src/core/strs.c index 08338499..6cee605b 100644 --- a/src/core/strs.c +++ b/src/core/strs.c @@ -21,7 +21,11 @@ char * nni_strdup(const char *src) { #ifdef NNG_HAVE_STRDUP +#ifdef _WIN32 + return (_strdup(src)); +#else return (strdup(src)); +#endif #else char * dst; size_t len = strlen(src); diff --git a/src/platform/posix/posix_aio.h b/src/platform/posix/posix_aio.h index 6c7db9e1..fe677591 100644 --- a/src/platform/posix/posix_aio.h +++ b/src/platform/posix/posix_aio.h @@ -28,6 +28,8 @@ extern void nni_posix_pipedesc_fini(nni_posix_pipedesc *); extern void nni_posix_pipedesc_recv(nni_posix_pipedesc *, nni_aio *); extern void nni_posix_pipedesc_send(nni_posix_pipedesc *, nni_aio *); extern void nni_posix_pipedesc_close(nni_posix_pipedesc *); +extern int nni_posix_pipedesc_peername(nni_posix_pipedesc *, nni_sockaddr *); +extern int nni_posix_pipedesc_sockname(nni_posix_pipedesc *, nni_sockaddr *); extern int nni_posix_epdesc_init(nni_posix_epdesc **); extern void nni_posix_epdesc_set_local(nni_posix_epdesc *, void *, int); diff --git a/src/platform/posix/posix_pipedesc.c b/src/platform/posix/posix_pipedesc.c index 8a087256..a025f83c 100644 --- a/src/platform/posix/posix_pipedesc.c +++ b/src/platform/posix/posix_pipedesc.c @@ -288,6 +288,30 @@ nni_posix_pipedesc_send(nni_posix_pipedesc *pd, nni_aio *aio) } int +nni_posix_pipedesc_peername(nni_posix_pipedesc *pd, nni_sockaddr *sa) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getpeername(pd->node.fd, (void *) &ss, &sslen) != 0) { + return (nni_plat_errno(errno)); + } + return (nni_posix_sockaddr2nn(sa, &ss)); +} + +int +nni_posix_pipedesc_sockname(nni_posix_pipedesc *pd, nni_sockaddr *sa) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getsockname(pd->node.fd, (void *) &ss, &sslen) != 0) { + return (nni_plat_errno(errno)); + } + return (nni_posix_sockaddr2nn(sa, &ss)); +} + +int nni_posix_pipedesc_init(nni_posix_pipedesc **pdp, int fd) { nni_posix_pipedesc *pd; diff --git a/src/platform/posix/posix_tcp.c b/src/platform/posix/posix_tcp.c index cc5466cb..e03f8056 100644 --- a/src/platform/posix/posix_tcp.c +++ b/src/platform/posix/posix_tcp.c @@ -105,4 +105,16 @@ nni_plat_tcp_pipe_recv(nni_plat_tcp_pipe *p, nni_aio *aio) nni_posix_pipedesc_recv((void *) p, aio); } +int +nni_plat_tcp_pipe_peername(nni_plat_tcp_pipe *p, nni_sockaddr *sa) +{ + return (nni_posix_pipedesc_peername((void *) p, sa)); +} + +int +nni_plat_tcp_pipe_sockname(nni_plat_tcp_pipe *p, nni_sockaddr *sa) +{ + return (nni_posix_pipedesc_sockname((void *) p, sa)); +} + #endif // NNG_PLATFORM_POSIX diff --git a/src/platform/windows/win_debug.c b/src/platform/windows/win_debug.c index c6ee3fed..5c6c3fb5 100644 --- a/src/platform/windows/win_debug.c +++ b/src/platform/windows/win_debug.c @@ -109,6 +109,7 @@ static struct { { WSAEWOULDBLOCK, NNG_EAGAIN }, { WSAEINPROGRESS, NNG_EAGAIN }, { WSAENOTSOCK, NNG_ECLOSED }, + { WSAEINVAL, NNG_EINVAL }, { WSAEMSGSIZE, NNG_EMSGSIZE }, { WSAENOPROTOOPT, NNG_ENOTSUP }, { WSAEPROTONOSUPPORT, NNG_ENOTSUP }, diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c index d34ef7a6..5e27d4ee 100644 --- a/src/platform/windows/win_tcp.c +++ b/src/platform/windows/win_tcp.c @@ -15,9 +15,11 @@ #include <stdio.h> struct nni_plat_tcp_pipe { - SOCKET s; - nni_win_event rcv_ev; - nni_win_event snd_ev; + SOCKET s; + nni_win_event rcv_ev; + nni_win_event snd_ev; + SOCKADDR_STORAGE sockname; + SOCKADDR_STORAGE peername; }; struct nni_plat_tcp_ep { @@ -36,9 +38,11 @@ struct nni_plat_tcp_ep { char buf[512]; // to hold acceptex results // We have to lookup some function pointers using ioctls. Winsock, - // gotta love it. - LPFN_CONNECTEX connectex; - LPFN_ACCEPTEX acceptex; + // gotta love it. Especially I love that asynch accept means that + // getsockname and getpeername don't work. + LPFN_CONNECTEX connectex; + LPFN_ACCEPTEX acceptex; + LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs; }; static int nni_win_tcp_pipe_start(nni_win_event *, nni_aio *); @@ -248,6 +252,24 @@ nni_plat_tcp_pipe_close(nni_plat_tcp_pipe *pipe) } } +int +nni_plat_tcp_pipe_peername(nni_plat_tcp_pipe *pipe, nni_sockaddr *sa) +{ + if (nni_win_sockaddr2nn(sa, &pipe->peername) < 0) { + return (NNG_EADDRINVAL); + } + return (0); +} + +int +nni_plat_tcp_pipe_sockname(nni_plat_tcp_pipe *pipe, nni_sockaddr *sa) +{ + if (nni_win_sockaddr2nn(sa, &pipe->sockname) < 0) { + return (NNG_EADDRINVAL); + } + return (0); +} + void nni_plat_tcp_pipe_fini(nni_plat_tcp_pipe *pipe) { @@ -268,6 +290,7 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, DWORD nbytes; GUID guid1 = WSAID_CONNECTEX; GUID guid2 = WSAID_ACCEPTEX; + GUID guid3 = WSAID_GETACCEPTEXSOCKADDRS; if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); @@ -303,6 +326,14 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, rv = nni_win_error(GetLastError()); goto fail; } + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid3, + sizeof(guid3), &ep->getacceptexsockaddrs, + sizeof(ep->getacceptexsockaddrs), &nbytes, NULL, + NULL) == SOCKET_ERROR) { + rv = nni_win_error(GetLastError()); + goto fail; + } + closesocket(s); s = INVALID_SOCKET; @@ -432,6 +463,10 @@ nni_win_tcp_acc_finish(nni_win_event *evt, nni_aio *aio) nni_plat_tcp_pipe *pipe; SOCKET s; int rv; + int len1; + int len2; + SOCKADDR * sa1; + SOCKADDR * sa2; s = ep->acc_s; ep->acc_s = INVALID_SOCKET; @@ -448,6 +483,19 @@ nni_win_tcp_acc_finish(nni_win_event *evt, nni_aio *aio) return; } + // Collect the local and peer addresses, because normal getsockname + // and getpeername don't work with AcceptEx. + len1 = sizeof(pipe->sockname); + len2 = sizeof(pipe->peername); + ep->getacceptexsockaddrs( + ep->buf, 0, 256, 256, &sa1, &len1, &sa2, &len2); + NNI_ASSERT(len1 > 0); + NNI_ASSERT(len1 < sizeof(SOCKADDR_STORAGE)); + NNI_ASSERT(len2 > 0); + NNI_ASSERT(len2 < sizeof(SOCKADDR_STORAGE)); + memcpy(&pipe->sockname, sa1, len1); + memcpy(&pipe->peername, sa2, len2); + nni_aio_finish_pipe(aio, pipe); } @@ -513,6 +561,8 @@ nni_win_tcp_con_finish(nni_win_event *evt, nni_aio *aio) nni_plat_tcp_pipe *pipe; SOCKET s; int rv; + DWORD yes = 1; + int len; s = ep->s; ep->s = INVALID_SOCKET; @@ -528,6 +578,17 @@ nni_win_tcp_con_finish(nni_win_event *evt, nni_aio *aio) return; } + (void) setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, + (char *) &yes, sizeof(yes)); + + // Windows seems to be unable to get peernames for sockets on + // connect - perhaps because we supplied it already with connectex. + // Rather than debugging it, just steal the address from the endpoint. + memcpy(&pipe->peername, &ep->remaddr, ep->remlen); + + len = sizeof(pipe->sockname); + (void) getsockname(s, (SOCKADDR *) &pipe->sockname, &len); + aio->a_pipe = pipe; nni_aio_finish(aio, 0, 0); } diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c index 413d8fa5..37bd49c7 100644 --- a/src/transport/tcp/tcp.c +++ b/src/transport/tcp/tcp.c @@ -407,6 +407,32 @@ nni_tcp_pipe_peer(void *arg) } static int +nni_tcp_pipe_getopt_locaddr(void *arg, void *v, size_t *szp) +{ + nni_tcp_pipe *p = arg; + int rv; + nng_sockaddr sa; + + if ((rv = nni_plat_tcp_pipe_sockname(p->tpp, &sa)) == 0) { + rv = nni_getopt_sockaddr(&sa, v, szp); + } + return (rv); +} + +static int +nni_tcp_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) +{ + nni_tcp_pipe *p = arg; + int rv; + nng_sockaddr sa; + + if ((rv = nni_plat_tcp_pipe_peername(p->tpp, &sa)) == 0) { + rv = nni_getopt_sockaddr(&sa, v, szp); + } + return (rv); +} + +static int nni_tcp_parse_pair(char *pair, char **hostp, char **servp) { char *host, *serv, *end; @@ -785,10 +811,8 @@ nni_tcp_ep_getopt_linger(void *arg, void *v, size_t *szp) } static nni_tran_pipe_option nni_tcp_pipe_options[] = { -#if 0 - { NNG_OPT_LOCADDR, nni_tcp_pipe_get_locaddr }, - { NNG_OPT_REMADDR, nni_tcp_pipe_get_remaddr }, -#endif + { NNG_OPT_LOCADDR, nni_tcp_pipe_getopt_locaddr }, + { NNG_OPT_REMADDR, nni_tcp_pipe_getopt_remaddr }, // terminate list { NULL, NULL } }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 70c9de3a..b34c5275 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -122,6 +122,7 @@ add_nng_test(survey 5) add_nng_test(synch 5) add_nng_test(transport 5) add_nng_test(tcp 5) +add_nng_test(tcp6 5) add_nng_test(scalability 20) add_nng_test(message 5) add_nng_test(device 5) diff --git a/tests/tcp.c b/tests/tcp.c index 324c167e..92e50a8b 100644 --- a/tests/tcp.c +++ b/tests/tcp.c @@ -11,11 +11,49 @@ #include "convey.h" #include "trantest.h" -// Inproc tests. +// TCP tests. + +#ifndef _WIN32 +#include <arpa/inet.h> +#endif + +static int +check_props_v4(nng_msg *msg, nng_listener l, nng_dialer d) +{ + nng_pipe p; + size_t z; + p = nng_msg_get_pipe(msg); + So(p > 0); + + Convey("Local address property works", { + nng_sockaddr la; + z = sizeof(nng_sockaddr); + So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0); + So(z == sizeof(la)); + So(la.s_un.s_family == NNG_AF_INET); + // So(la.s_un.s_in.sa_port == (trantest_port - 1)); + So(la.s_un.s_in.sa_port != 0); + So(la.s_un.s_in.sa_addr == htonl(0x7f000001)); + }); + + Convey("Remote address property works", { + nng_sockaddr ra; + z = sizeof(nng_sockaddr); + So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0); + So(z == sizeof(ra)); + So(ra.s_un.s_family == NNG_AF_INET); + So(ra.s_un.s_in.sa_port != 0); + So(ra.s_un.s_in.sa_addr == htonl(0x7f000001)); + + So(nng_dialer_getopt(d, NNG_OPT_REMADDR, &ra, &z) != 0); + }); + + return (0); +} TestMain("TCP Transport", { - trantest_test_all("tcp://127.0.0.1:%u"); + trantest_test_extended("tcp://127.0.0.1:%u", check_props_v4); Convey("We cannot connect to wild cards", { nng_socket s; diff --git a/tests/tcp6.c b/tests/tcp6.c new file mode 100644 index 00000000..6f84d282 --- /dev/null +++ b/tests/tcp6.c @@ -0,0 +1,86 @@ +// +// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include "convey.h" +#include "trantest.h" + +#include "core/nng_impl.h" +// TCP tests for IPv6. + +static int +has_v6(void) +{ + nng_sockaddr sa; + nni_plat_udp *u; + int rv; + + sa.s_un.s_in6.sa_family = NNG_AF_INET6; + sa.s_un.s_in6.sa_port = 0; + memset(sa.s_un.s_in6.sa_addr, 0, 16); + sa.s_un.s_in6.sa_addr[15] = 1; + + rv = nni_plat_udp_open(&u, &sa); + if (rv == 0) { + nni_plat_udp_close(u); + } + return (rv == 0 ? 1 : 0); +} + +static int +check_props_v6(nng_msg *msg, nng_listener l, nng_dialer d) +{ + nng_pipe p; + size_t z; + uint8_t loopback[16]; + + memset(loopback, 0, sizeof(loopback)); + loopback[15] = 1; + Convey("IPv6 Local address property works", { + nng_sockaddr la; + z = sizeof(nng_sockaddr); + p = nng_msg_get_pipe(msg); + So(p > 0); + So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0); + So(z == sizeof(la)); + So(la.s_un.s_family == NNG_AF_INET6); + // So(la.s_un.s_in.sa_port == (trantest_port - 1)); + So(la.s_un.s_in6.sa_port != 0); + So(memcmp(la.s_un.s_in6.sa_addr, loopback, 16) == 0); + }); + + Convey("IPv6 Remote address property works", { + nng_sockaddr ra; + z = sizeof(nng_sockaddr); + p = nng_msg_get_pipe(msg); + So(p > 0); + So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0); + So(z == sizeof(ra)); + So(ra.s_un.s_family == NNG_AF_INET6); + So(ra.s_un.s_in6.sa_port != 0); + So(memcmp(ra.s_un.s_in6.sa_addr, loopback, 16) == 0); + + So(nng_dialer_getopt(d, NNG_OPT_REMADDR, &ra, &z) != 0); + }); + + return (0); +} + +TestMain("TCP (IPv6) Transport", { + + nni_init(); + + if (has_v6()) { + trantest_test_extended("tcp://[::1]:%u", check_props_v6); + } else { + SkipSo("IPv6 not available"); + } + + nng_fini(); +}) diff --git a/tests/trantest.h b/tests/trantest.h index 542cff32..52b6b2ea 100644 --- a/tests/trantest.h +++ b/tests/trantest.h @@ -179,10 +179,6 @@ trantest_check_properties(trantest *tt, trantest_proptest_t f) nng_dialer d; nng_msg * send; nng_msg * recv; - size_t len; - nng_pipe p; - char url[NNG_MAXADDRLEN]; - size_t sz; int rv; So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0); |
