Skip to content

Commit

Permalink
fixes nanomsg#5 Address properties
Browse files Browse the repository at this point in the history
Added TCP socket address properties on pipes.

This adds the plumbing for the various platform specifics, and
includes both v4 and v6 handling.

We've included a TCPv6 test as well.
  • Loading branch information
gdamore committed Oct 3, 2017
1 parent 6e945e1 commit 6fef4c1
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 16 deletions.
6 changes: 6 additions & 0 deletions src/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/core/strs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/platform/posix/posix_aio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions src/platform/posix/posix_pipedesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,30 @@ nni_posix_pipedesc_send(nni_posix_pipedesc *pd, nni_aio *aio)
nni_mtx_unlock(&pd->mtx);
}

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)
{
Expand Down
12 changes: 12 additions & 0 deletions src/platform/posix/posix_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/platform/windows/win_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
73 changes: 67 additions & 6 deletions src/platform/windows/win_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 *);
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
32 changes: 28 additions & 4 deletions src/transport/tcp/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,32 @@ nni_tcp_pipe_peer(void *arg)
return (p->peer);
}

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)
{
Expand Down Expand Up @@ -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 }
};
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
42 changes: 40 additions & 2 deletions tests/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 6fef4c1

Please sign in to comment.