From 75adda86be49e6839e50443f0bae5875d9910897 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 20 Aug 2017 10:45:27 -0700 Subject: fixes #41 Move DNS out of tcp transport This moves the DNS related functionality into common code, and also removes all the URL parsing stuff out of the platform specific code and into the transports. Now the transports just take sockaddr's on initialization. (We may want to move this until later.) We also add UDP resolution as another separate API. --- src/core/aio.c | 4 - src/core/aio.h | 3 +- src/core/platform.h | 13 ++- src/platform/posix/posix_aio.h | 5 +- src/platform/posix/posix_epdesc.c | 62 +------------ src/platform/posix/posix_ipc.c | 38 +++----- src/platform/posix/posix_resolv_gai.c | 170 ++++++++++++++++------------------ src/platform/posix/posix_sockaddr.c | 30 +++++- src/platform/posix/posix_tcp.c | 75 ++------------- src/platform/posix/posix_udp.c | 12 +-- src/platform/windows/win_ipc.c | 10 +- src/platform/windows/win_net.c | 85 ++++------------- src/platform/windows/win_resolv.c | 154 +++++++++++++----------------- src/transport/ipc/ipc.c | 12 ++- src/transport/tcp/tcp.c | 118 +++++++++++++++++------ 15 files changed, 334 insertions(+), 457 deletions(-) (limited to 'src') diff --git a/src/core/aio.c b/src/core/aio.c index fe9bcde8..5b8c7970 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -73,10 +73,6 @@ nni_aio_fini(nni_aio *aio) // At this point the AIO is done. nni_cv_fini(&aio->a_cv); - - if ((aio->a_naddrs != 0) && (aio->a_addrs != NULL)) { - NNI_FREE_STRUCTS(aio->a_addrs, aio->a_naddrs); - } } // nni_aio_stop cancels any oustanding operation, and waits for the diff --git a/src/core/aio.h b/src/core/aio.h index aabb3fa9..9114c9fe 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -50,8 +50,7 @@ struct nni_aio { void *a_pipe; // opaque pipe handle // Resolver operations. - nni_sockaddr *a_addrs; - int a_naddrs; + nni_sockaddr *a_addr; // Provider-use fields. nni_aio_cancelfn a_prov_cancel; diff --git a/src/core/platform.h b/src/core/platform.h index 6e049bb3..02ea9a11 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -192,8 +192,10 @@ extern void nni_plat_fini(void); typedef struct nni_plat_tcp_ep nni_plat_tcp_ep; typedef struct nni_plat_tcp_pipe nni_plat_tcp_pipe; -// nni_plat_tcp_ep_init creates a new endpoint associated with the url. -extern int nni_plat_tcp_ep_init(nni_plat_tcp_ep **, const char *, int); +// nni_plat_tcp_ep_init creates a new endpoint associated with the local +// and remote addresses. +extern int nni_plat_tcp_ep_init( + nni_plat_tcp_ep **, const nni_sockaddr *, const nni_sockaddr *, int); // nni_plat_tcp_ep_fini closes the endpoint and releases resources. extern void nni_plat_tcp_ep_fini(nni_plat_tcp_ep *); @@ -240,6 +242,11 @@ extern void nni_plat_tcp_pipe_recv(nni_plat_tcp_pipe *, nni_aio *); extern void nni_plat_tcp_resolv( const char *, const char *, int, int, nni_aio *); +// nni_plat_udp_resolve is just like nni_plat_tcp_resolve, but looks up +// service names using UDP. +extern void nni_plat_udp_resolv( + const char *, const char *, int, int, nni_aio *); + // // IPC (UNIX Domain Sockets & Named Pipes) Support. // @@ -248,7 +255,7 @@ typedef struct nni_plat_ipc_ep nni_plat_ipc_ep; typedef struct nni_plat_ipc_pipe nni_plat_ipc_pipe; // nni_plat_ipc_ep_init creates a new endpoint associated with the url. -extern int nni_plat_ipc_ep_init(nni_plat_ipc_ep **, const char *, int); +extern int nni_plat_ipc_ep_init(nni_plat_ipc_ep **, const nni_sockaddr *, int); // nni_plat_ipc_ep_fini closes the endpoint and releases resources. extern void nni_plat_ipc_ep_fini(nni_plat_ipc_ep *); diff --git a/src/platform/posix/posix_aio.h b/src/platform/posix/posix_aio.h index 60594152..6c7db9e1 100644 --- a/src/platform/posix/posix_aio.h +++ b/src/platform/posix/posix_aio.h @@ -29,9 +29,8 @@ 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_epdesc_init(nni_posix_epdesc **, const char *); -extern const char *nni_posix_epdesc_url(nni_posix_epdesc *); -extern void nni_posix_epdesc_set_local(nni_posix_epdesc *, void *, int); +extern int nni_posix_epdesc_init(nni_posix_epdesc **); +extern void nni_posix_epdesc_set_local(nni_posix_epdesc *, void *, int); extern void nni_posix_epdesc_set_remote(nni_posix_epdesc *, void *, int); extern void nni_posix_epdesc_fini(nni_posix_epdesc *); extern void nni_posix_epdesc_close(nni_posix_epdesc *); diff --git a/src/platform/posix/posix_epdesc.c b/src/platform/posix/posix_epdesc.c index 867f57a7..0524fe30 100644 --- a/src/platform/posix/posix_epdesc.c +++ b/src/platform/posix/posix_epdesc.c @@ -41,7 +41,6 @@ struct nni_posix_epdesc { struct sockaddr_storage remaddr; socklen_t loclen; socklen_t remlen; - const char * url; nni_mtx mtx; }; @@ -261,57 +260,6 @@ nni_posix_epdesc_close(nni_posix_epdesc *ed) nni_mtx_unlock(&ed->mtx); } -static int -nni_posix_epdesc_parseaddr(char *pair, char **hostp, uint16_t *portp) -{ - char *host, *port, *end; - char c; - int val; - - if (pair[0] == '[') { - host = pair + 1; - // IP address enclosed ... for IPv6 usually. - if ((end = strchr(host, ']')) == NULL) { - return (NNG_EADDRINVAL); - } - *end = '\0'; - port = end + 1; - if (*port == ':') { - port++; - } else if (*port != '\0') { - return (NNG_EADDRINVAL); - } - } else { - host = pair; - port = strchr(host, ':'); - if (port != NULL) { - *port = '\0'; - port++; - } - } - val = 0; - while ((c = *port) != '\0') { - val *= 10; - if ((c >= '0') && (c <= '9')) { - val += (c - '0'); - } else { - return (NNG_EADDRINVAL); - } - if (val > 65535) { - return (NNG_EADDRINVAL); - } - port++; - } - if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) { - *hostp = NULL; - } else { - *hostp = host; - } - // Stash the port in big endian (network) byte order. - NNI_PUT16((uint8_t *) portp, val); - return (0); -} - int nni_posix_epdesc_listen(nni_posix_epdesc *ed) { @@ -326,6 +274,7 @@ nni_posix_epdesc_listen(nni_posix_epdesc *ed) len = ed->loclen; if ((fd = socket(ss->ss_family, NNI_STREAM_SOCKTYPE, 0)) < 0) { + nni_mtx_unlock(&ed->mtx); return (nni_plat_errno(errno)); } (void) fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -444,7 +393,7 @@ nni_posix_epdesc_connect(nni_posix_epdesc *ed, nni_aio *aio) } int -nni_posix_epdesc_init(nni_posix_epdesc **edp, const char *url) +nni_posix_epdesc_init(nni_posix_epdesc **edp) { nni_posix_epdesc *ed; nni_posix_pollq * pq; @@ -464,7 +413,6 @@ nni_posix_epdesc_init(nni_posix_epdesc **edp, const char *url) ed->node.index = 0; ed->node.cb = nni_posix_epdesc_cb; ed->node.data = ed; - ed->url = url; nni_aio_list_init(&ed->connectq); nni_aio_list_init(&ed->acceptq); @@ -479,12 +427,6 @@ nni_posix_epdesc_init(nni_posix_epdesc **edp, const char *url) return (0); } -const char * -nni_posix_epdesc_url(nni_posix_epdesc *ed) -{ - return (ed->url); -} - void nni_posix_epdesc_set_local(nni_posix_epdesc *ed, void *sa, int len) { diff --git a/src/platform/posix/posix_ipc.c b/src/platform/posix/posix_ipc.c index 3aa9bda3..2daec4ea 100644 --- a/src/platform/posix/posix_ipc.c +++ b/src/platform/posix/posix_ipc.c @@ -36,37 +36,34 @@ #undef sun #endif +static int nni_plat_ipc_remove_stale(const char *path); + // We alias nni_posix_pipedesc to nni_plat_ipc_pipe. // We alias nni_posix_epdesc to nni_plat_ipc_ep. int -nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const char *url, int mode) +nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const nni_sockaddr *sa, int mode) { nni_posix_epdesc * ed; int rv; struct sockaddr_un sun; - const char * path; - - if (strncmp(url, "ipc://", strlen("ipc://")) != 0) { - return (NNG_EADDRINVAL); - } - path = url + strlen("ipc://"); // skip the prefix. - - // prepare the sockaddr_un - sun.sun_family = AF_UNIX; - if (strlen(url) >= sizeof(sun.sun_path)) { - return (NNG_EADDRINVAL); - } - snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", path); - if ((rv = nni_posix_epdesc_init(&ed, url)) != 0) { + if ((rv = nni_posix_epdesc_init(&ed)) != 0) { return (rv); } switch (mode) { case NNI_EP_MODE_DIAL: + nni_posix_nn2sockaddr(&sun, sa); nni_posix_epdesc_set_remote(ed, &sun, sizeof(sun)); break; case NNI_EP_MODE_LISTEN: + + if ((rv = nni_plat_ipc_remove_stale( + sa->s_un.s_path.sa_path)) != 0) { + return (rv); + } + + nni_posix_nn2sockaddr(&sun, sa); nni_posix_epdesc_set_local(ed, &sun, sizeof(sun)); break; default: @@ -127,17 +124,8 @@ nni_plat_ipc_remove_stale(const char *path) int nni_plat_ipc_ep_listen(nni_plat_ipc_ep *ep) { - const char * path; - nni_posix_epdesc * ed = (void *) ep; - struct sockaddr_un sun; - int rv; + nni_posix_epdesc *ed = (void *) ep; - path = nni_posix_epdesc_url(ed); - path += strlen("ipc://"); - - if ((rv = nni_plat_ipc_remove_stale(path)) != 0) { - return (rv); - } return (nni_posix_epdesc_listen(ed)); } diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c index 27c22c4a..be1d2c6b 100644 --- a/src/platform/posix/posix_resolv_gai.c +++ b/src/platform/posix/posix_resolv_gai.c @@ -114,104 +114,80 @@ nni_posix_resolv_task(void *arg) struct addrinfo hints; struct addrinfo * results; struct addrinfo * probe; - int i, rv; + int rv; results = NULL; - switch (item->family) { - case AF_INET: - case AF_INET6: - case AF_UNSPEC: - // We treat these all as IP addresses. The service and the - // host part are split. - memset(&hints, 0, sizeof(hints)); - if (item->passive) { - hints.ai_flags |= AI_PASSIVE; - } + // We treat these all as IP addresses. The service and the + // host part are split. + memset(&hints, 0, sizeof(hints)); + if (item->passive) { + hints.ai_flags |= AI_PASSIVE; + } #ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_flags |= AI_ADDRCONFIG; #endif - hints.ai_protocol = item->proto; - hints.ai_family = item->family; - if (item->family == AF_INET6) { -// We prefer to have v4mapped addresses if a remote -// v4 address isn't avaiable. And we prefer to only -// do this if we actually support v6. + hints.ai_protocol = item->proto; + hints.ai_family = item->family; + + // We prefer to have v4mapped addresses if a remote + // v4 address isn't available. And we prefer to only + // do this if we actually support v6. + if (item->family == AF_INET6) { #if defined(AI_V4MAPPED_CFG) - hints.ai_flags |= AI_V4MAPPED_CFG; + hints.ai_flags |= AI_V4MAPPED_CFG; #elif defined(AI_V4MAPPED) - hints.ai_flags |= AI_V4MAPPED; + hints.ai_flags |= AI_V4MAPPED; #endif - } + } - rv = getaddrinfo(item->name, item->serv, &hints, &results); - if (rv != 0) { - rv = nni_posix_gai_errno(rv); + rv = getaddrinfo(item->name, item->serv, &hints, &results); + if (rv != 0) { + rv = nni_posix_gai_errno(rv); + goto done; + } + + // We only take the first matching address. Presumably + // DNS load balancing is done by the resolver/server. + + rv = NNG_EADDRINVAL; + for (probe = results; probe != NULL; probe = probe->ai_next) { + if ((probe->ai_addr->sa_family == AF_INET) || + (probe->ai_addr->sa_family == AF_INET6)) { break; } + } - // Count the total number of results. - aio->a_naddrs = 0; - for (probe = results; probe != NULL; probe = probe->ai_next) { - // Only count v4 and v6 addresses. - switch (probe->ai_addr->sa_family) { - case AF_INET: - case AF_INET6: - aio->a_naddrs++; - break; - } - } - // If the only results were not IPv4 or IPv6... - if (aio->a_naddrs == 0) { - rv = NNG_EADDRINVAL; + if (probe != NULL) { + struct sockaddr_in * sin; + struct sockaddr_in6 *sin6; + nng_sockaddr * sa = aio->a_addr; + + switch (probe->ai_addr->sa_family) { + case AF_INET: + rv = 0; + sin = (void *) probe->ai_addr; + sa->s_un.s_in.sa_family = NNG_AF_INET; + sa->s_un.s_in.sa_port = sin->sin_port; + sa->s_un.s_in.sa_addr = sin->sin_addr.s_addr; break; - } - aio->a_addrs = NNI_ALLOC_STRUCTS(aio->a_addrs, aio->a_naddrs); - if (aio->a_addrs == NULL) { - aio->a_naddrs = 0; - rv = NNG_ENOMEM; + case AF_INET6: + rv = 0; + sin6 = (void *) probe->ai_addr; + sa->s_un.s_in6.sa_family = NNG_AF_INET6; + sa->s_un.s_in6.sa_port = sin6->sin6_port; + memcpy(sa->s_un.s_in6.sa_addr, sin6->sin6_addr.s6_addr, + 16); break; } - i = 0; - for (probe = results; probe != NULL; probe = probe->ai_next) { - struct sockaddr_in * sin; - struct sockaddr_in6 *sin6; - nng_sockaddr * sa = &aio->a_addrs[i]; - - switch (probe->ai_addr->sa_family) { - case AF_INET: - sin = (void *) probe->ai_addr; - sa->s_un.s_in.sa_family = NNG_AF_INET; - sa->s_un.s_in.sa_port = sin->sin_port; - sa->s_un.s_in.sa_addr = sin->sin_addr.s_addr; - i++; - break; - case AF_INET6: - sin6 = (void *) probe->ai_addr; - sa->s_un.s_in6.sa_family = NNG_AF_INET6; - sa->s_un.s_in6.sa_port = sin6->sin6_port; - memcpy(sa->s_un.s_in6.sa_addr, - sin6->sin6_addr.s6_addr, 16); - i++; - break; - default: - // Other address types are ignored. - break; - } - } - // Resolution complete! - rv = 0; - break; - - default: - // Some other family requested we don't understand. - rv = NNG_ENOTSUP; - break; } +done: + if (results != NULL) { freeaddrinfo(results); } + nni_mtx_lock(&nni_posix_resolv_mtx); nni_posix_resolv_finish(item, rv); nni_mtx_unlock(&nni_posix_resolv_mtx); @@ -223,35 +199,38 @@ nni_posix_resolv_ip(const char *host, const char *serv, int passive, { nni_posix_resolv_item *item; int rv; - - if ((aio->a_naddrs != 0) && (aio->a_addrs != NULL)) { - NNI_FREE_STRUCTS(aio->a_addrs, aio->a_naddrs); - } - if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { - nni_aio_finish(aio, NNG_ENOMEM, 0); - return; - } - - nni_task_init( - nni_posix_resolv_tq, &item->task, nni_posix_resolv_task, item); + sa_family_t fam; switch (family) { case NNG_AF_INET: - item->family = AF_INET; + fam = AF_INET; break; case NNG_AF_INET6: - item->family = AF_INET6; + fam = AF_INET6; break; case NNG_AF_UNSPEC: - item->family = AF_UNSPEC; + fam = AF_UNSPEC; break; + default: + nni_aio_finish_error(aio, NNG_ENOTSUP); + return; } + + if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { + nni_aio_finish_error(aio, NNG_ENOMEM); + return; + } + + nni_task_init( + nni_posix_resolv_tq, &item->task, nni_posix_resolv_task, item); + // NB: host and serv must remain valid until this is completed. item->passive = passive; item->name = host; item->serv = serv; item->proto = proto; item->aio = aio; + item->family = fam; nni_mtx_lock(&nni_posix_resolv_mtx); // If we were stopped, we're done... @@ -271,6 +250,13 @@ nni_plat_tcp_resolv( nni_posix_resolv_ip(host, serv, passive, family, IPPROTO_TCP, aio); } +void +nni_plat_udp_resolv( + const char *host, const char *serv, int family, int passive, nni_aio *aio) +{ + nni_posix_resolv_ip(host, serv, passive, family, IPPROTO_UDP, aio); +} + int nni_posix_resolv_sysinit(void) { diff --git a/src/platform/posix/posix_sockaddr.c b/src/platform/posix/posix_sockaddr.c index 2514ea73..59e1ebee 100644 --- a/src/platform/posix/posix_sockaddr.c +++ b/src/platform/posix/posix_sockaddr.c @@ -15,18 +15,22 @@ #include #include #include +#include #include #include #include #include +#include int nni_posix_nn2sockaddr(void *sa, const nni_sockaddr *na) { - struct sockaddr_in * sin; - struct sockaddr_in6 * sin6; - const nng_sockaddr_in * nsin; - const nng_sockaddr_in6 *nsin6; + struct sockaddr_in * sin; + struct sockaddr_in6 * sin6; + struct sockaddr_un * spath; + const nng_sockaddr_in * nsin; + const nng_sockaddr_in6 * nsin6; + const nng_sockaddr_path *nspath; switch (na->s_un.s_family) { case NNG_AF_INET: @@ -49,6 +53,15 @@ nni_posix_nn2sockaddr(void *sa, const nni_sockaddr *na) sin6->sin6_port = nsin6->sa_port; memcpy(sin6->sin6_addr.s6_addr, nsin6->sa_addr, 16); return (sizeof(*sin6)); + + case NNG_AF_IPC: + spath = (void *) sa; + nspath = &na->s_un.s_path; + memset(spath, 0, sizeof(*spath)); + spath->sun_family = PF_UNIX; + snprintf(spath->sun_path, sizeof(spath->sun_path), "%s", + nspath->sa_path); + return (sizeof(*spath)); } return (-1); } @@ -58,8 +71,10 @@ nni_posix_sockaddr2nn(nni_sockaddr *na, const void *sa) { const struct sockaddr_in * sin; const struct sockaddr_in6 *sin6; + const struct sockaddr_un * spath; nng_sockaddr_in * nsin; nng_sockaddr_in6 * nsin6; + nng_sockaddr_path * nspath; switch (((struct sockaddr *) sa)->sa_family) { case AF_INET: @@ -76,6 +91,13 @@ nni_posix_sockaddr2nn(nni_sockaddr *na, const void *sa) nsin6->sa_port = sin6->sin6_port; memcpy(nsin6->sa_addr, sin6->sin6_addr.s6_addr, 16); break; + case AF_UNIX: + spath = (void *) sa; + nspath = &na->s_un.s_path; + nspath->sa_family = NNG_AF_IPC; + (void) snprintf(nspath->sa_path, sizeof(nspath->sa_path), "%s", + spath->sun_path); + break; default: // We should never see this - the OS should always be // specific about giving us either AF_INET or AF_INET6. diff --git a/src/platform/posix/posix_tcp.c b/src/platform/posix/posix_tcp.c index 185c4e2c..cc5466cb 100644 --- a/src/platform/posix/posix_tcp.c +++ b/src/platform/posix/posix_tcp.c @@ -23,87 +23,32 @@ #include #include -extern int nni_tcp_parse_url(char *, char **, char **, char **, char **); - int -nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const char *url, int mode) +nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, + const nni_sockaddr *rsa, int mode) { nni_posix_epdesc * ed; - char buf[NNG_MAXADDRLEN]; int rv; - char * lhost, *rhost; - char * lserv, *rserv; - char * sep; struct sockaddr_storage ss; int len; - int passive; - nni_aio aio; - if ((rv = nni_posix_epdesc_init(&ed, url)) != 0) { - return (rv); - } + NNI_ARG_UNUSED(mode); - // Make a local copy. - snprintf(buf, sizeof(buf), "%s", url); - nni_aio_init(&aio, NULL, NULL); - - if (mode == NNI_EP_MODE_DIAL) { - rv = nni_tcp_parse_url(buf, &rhost, &rserv, &lhost, &lserv); - if (rv != 0) { - goto done; - } - - // We have to have a remote destination! - if ((rhost == NULL) || (rserv == NULL)) { - rv = NNG_EADDRINVAL; - goto done; - } - } else { - rv = nni_tcp_parse_url(buf, &lhost, &lserv, &rhost, &rserv); - if (rv != 0) { - goto done; - } - if ((rhost != NULL) || (rserv != NULL)) { - // remotes are nonsensical here. - rv = NNG_EADDRINVAL; - goto done; - } - if (lserv == NULL) { - // missing port to listen on! - rv = NNG_EADDRINVAL; - goto done; - } + if ((rv = nni_posix_epdesc_init(&ed)) != 0) { + return (rv); } - if ((rserv != NULL) || (rhost != NULL)) { - nni_plat_tcp_resolv(rhost, rserv, NNG_AF_UNSPEC, 0, &aio); - nni_aio_wait(&aio); - if ((rv = nni_aio_result(&aio)) != 0) { - goto done; - } - len = nni_posix_nn2sockaddr((void *) &ss, &aio.a_addrs[0]); + if (rsa->s_un.s_family != NNG_AF_UNSPEC) { + len = nni_posix_nn2sockaddr((void *) &ss, rsa); nni_posix_epdesc_set_remote(ed, &ss, len); } - - if ((lserv != NULL) || (lhost != NULL)) { - nni_plat_tcp_resolv(lhost, lserv, NNG_AF_UNSPEC, 1, &aio); - nni_aio_wait(&aio); - if ((rv = nni_aio_result(&aio)) != 0) { - goto done; - } - len = nni_posix_nn2sockaddr((void *) &ss, &aio.a_addrs[0]); + if (lsa->s_un.s_family != NNG_AF_UNSPEC) { + len = nni_posix_nn2sockaddr((void *) &ss, lsa); nni_posix_epdesc_set_local(ed, &ss, len); } - nni_aio_fini(&aio); + *epp = (void *) ed; return (0); - -done: - if (rv != 0) { - nni_posix_epdesc_fini(ed); - } - nni_aio_fini(&aio); - return (rv); } void diff --git a/src/platform/posix/posix_udp.c b/src/platform/posix/posix_udp.c index 7bad2db4..59389a64 100644 --- a/src/platform/posix/posix_udp.c +++ b/src/platform/posix/posix_udp.c @@ -97,8 +97,8 @@ nni_posix_udp_dorecv(nni_plat_udp *udp) // We need to store the address information. // It is incumbent on the AIO submitter to supply // storage for the address. - if (aio->a_naddrs > 0) { - nni_posix_sockaddr2nn(&aio->a_addrs[0], (void *) &ss); + if (aio->a_addr != NULL) { + nni_posix_sockaddr2nn(aio->a_addr, (void *) &ss); } nni_aio_finish(aio, 0, rv); @@ -117,16 +117,16 @@ nni_posix_udp_dosend(nni_plat_udp *udp) int len; nni_list * q = &udp->udp_sendq; - // While we're able to recv, do so. + // While we're able to send, do so. while ((aio = nni_list_first(q)) != NULL) { nni_list_remove(q, aio); - if (aio->a_naddrs < 1) { - // No incoming address? + if (aio->a_addr == NULL) { + // No outgoing address? nni_aio_finish_error(aio, NNG_EADDRINVAL); return; } - len = nni_posix_nn2sockaddr(&ss, &aio->a_addrs[0]); + len = nni_posix_nn2sockaddr(&ss, aio->a_addr); if (len < 0) { nni_aio_finish_error(aio, NNG_EADDRINVAL); return; diff --git a/src/platform/windows/win_ipc.c b/src/platform/windows/win_ipc.c index 20ae81b5..bca579cf 100644 --- a/src/platform/windows/win_ipc.c +++ b/src/platform/windows/win_ipc.c @@ -22,6 +22,7 @@ struct nni_plat_ipc_pipe { struct nni_plat_ipc_ep { char path[256]; + nni_sockaddr addr; int mode; int started; HANDLE p; // accept side only @@ -205,15 +206,13 @@ nni_plat_ipc_pipe_fini(nni_plat_ipc_pipe *pipe) } int -nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const char *url, int mode) +nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const nni_sockaddr *sa, int mode) { const char * path; nni_plat_ipc_ep *ep; - if (strncmp(url, "ipc://", strlen("ipc://")) != 0) { - return (NNG_EADDRINVAL); - } - path = url + strlen("ipc://"); + path = sa->s_un.s_path.sa_path; + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } @@ -222,6 +221,7 @@ nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const char *url, int mode) ep->mode = mode; NNI_LIST_NODE_INIT(&ep->node); + ep->addr = *sa; (void) snprintf(ep->path, sizeof(ep->path), "\\\\.\\pipe\\%s", path); *epp = ep; diff --git a/src/platform/windows/win_net.c b/src/platform/windows/win_net.c index dee9b745..07c30e11 100644 --- a/src/platform/windows/win_net.c +++ b/src/platform/windows/win_net.c @@ -25,7 +25,6 @@ struct nni_plat_tcp_ep { SOCKET acc_s; nni_win_event con_ev; nni_win_event acc_ev; - int mode; int started; int bound; @@ -285,19 +284,12 @@ nni_plat_tcp_pipe_fini(nni_plat_tcp_pipe *pipe) NNI_FREE_STRUCT(pipe); } -extern int nni_tcp_parse_url(char *, char **, char **, char **, char **); - int -nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const char *url, int mode) +nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, + const nni_sockaddr *rsa, int mode) { - char buf[NNG_MAXADDRLEN]; nni_plat_tcp_ep *ep; - char * rhost; - char * rserv; - char * lhost; - char * lserv; int rv; - nni_aio aio; SOCKET s; DWORD nbytes; GUID guid1 = WSAID_CONNECTEX; @@ -308,55 +300,13 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const char *url, int mode) } ZeroMemory(ep, sizeof(ep)); - ep->mode = mode; - ep->s = INVALID_SOCKET; - - nni_aio_init(&aio, NULL, NULL); + ep->s = INVALID_SOCKET; - snprintf(buf, sizeof(buf), "%s", url); - if (mode == NNI_EP_MODE_DIAL) { - rv = nni_tcp_parse_url(buf, &rhost, &rserv, &lhost, &lserv); - if (rv != 0) { - goto fail; - } - // Have to ahve a remote destination. - if ((rhost == NULL) || (rserv == NULL)) { - rv = NNG_EADDRINVAL; - goto fail; - } - } else { - rv = nni_tcp_parse_url(buf, &lhost, &lserv, &rhost, &rserv); - if (rv != 0) { - goto fail; - } - // Remote destination makes no sense when listening. - if ((rhost != NULL) || (rserv != NULL)) { - rv = NNG_EADDRINVAL; - goto fail; - } - if (lserv == NULL) { - // missing port to listen on! - rv = NNG_EADDRINVAL; - goto fail; - } + if (rsa->s_un.s_family != NNG_AF_UNSPEC) { + ep->remlen = nni_win_tcp_addr(&ep->remaddr, rsa); } - - if ((rserv != NULL) || (rhost != NULL)) { - nni_plat_tcp_resolv(rhost, rserv, NNG_AF_INET6, 0, &aio); - nni_aio_wait(&aio); - if ((rv = nni_aio_result(&aio)) != 0) { - goto fail; - } - ep->remlen = nni_win_tcp_addr(&ep->remaddr, &aio.a_addrs[0]); - } - - if ((lserv != NULL) || (lhost != NULL)) { - nni_plat_tcp_resolv(lhost, lserv, NNG_AF_INET6, 1, &aio); - nni_aio_wait(&aio); - if ((rv = nni_aio_result(&aio)) != 0) { - goto fail; - } - ep->loclen = nni_win_tcp_addr(&ep->locaddr, &aio.a_addrs[0]); + if (lsa->s_un.s_family != NNG_AF_UNSPEC) { + ep->loclen = nni_win_tcp_addr(&ep->locaddr, lsa); } // Create a scratch socket for use with ioctl. @@ -392,7 +342,6 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const char *url, int mode) goto fail; } - nni_aio_fini(&aio); *epp = ep; return (0); @@ -401,7 +350,6 @@ fail: closesocket(s); } nni_plat_tcp_ep_fini(ep); - nni_aio_fini(&aio); return (rv); } @@ -433,14 +381,11 @@ nni_win_tcp_listen(nni_plat_tcp_ep *ep) BOOL yes; SOCKET s; - if (ep->mode != NNI_EP_MODE_LISTEN) { - return (NNG_EINVAL); - } if (ep->started) { return (NNG_EBUSY); } - s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + s = socket(ep->locaddr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { rv = nni_win_error(GetLastError()); goto fail; @@ -598,7 +543,7 @@ nni_win_tcp_con_finish(nni_win_event *evt, nni_aio *aio) s = ep->s; ep->s = INVALID_SOCKET; - // The socket was already registere with the IOCP. + // The socket was already registered with the IOCP. if (((rv = evt->status) != 0) || ((rv = nni_win_tcp_pipe_init(&pipe, s)) != 0)) { @@ -621,8 +566,15 @@ nni_win_tcp_con_start(nni_win_event *evt, nni_aio *aio) SOCKADDR_STORAGE bss; int len; int rv; + int family; - s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (ep->loclen > 0) { + family = ep->locaddr.ss_family; + } else { + family = ep->remaddr.ss_family; + } + + s = socket(family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { evt->status = nni_win_error(GetLastError()); evt->count = 0; @@ -632,7 +584,7 @@ nni_win_tcp_con_start(nni_win_event *evt, nni_aio *aio) nni_win_tcp_sockinit(s); // Windows ConnectEx requires the socket to be bound first. - if (ep->loclen != 0) { + if (ep->loclen > 0) { bss = ep->locaddr; len = ep->loclen; } else { @@ -644,6 +596,7 @@ nni_win_tcp_con_start(nni_win_event *evt, nni_aio *aio) evt->status = nni_win_error(GetLastError()); evt->count = 0; closesocket(s); + return (1); } // Register with the I/O completion port so we can get the diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c index d157cf0f..331a2a56 100644 --- a/src/platform/windows/win_resolv.c +++ b/src/platform/windows/win_resolv.c @@ -104,92 +104,66 @@ nni_win_resolv_task(void *arg) struct addrinfo hints; struct addrinfo * results; struct addrinfo * probe; - int i, rv; + int rv; results = NULL; - switch (item->family) { - case AF_INET: - case AF_INET6: - case AF_UNSPEC: - // We treat these all as IP addresses. The service and the - // host part are split. - memset(&hints, 0, sizeof(hints)); - if (item->passive) { - hints.ai_flags |= AI_PASSIVE; - } - hints.ai_flags |= AI_ADDRCONFIG; - hints.ai_protocol = item->proto; - hints.ai_family = item->family; - if (item->family == AF_INET6) { - hints.ai_flags |= AI_V4MAPPED; - } + // We treat these all as IP addresses. The service and the + // host part are split. + memset(&hints, 0, sizeof(hints)); + if (item->passive) { + hints.ai_flags |= AI_PASSIVE; + } + hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_protocol = item->proto; + hints.ai_family = item->family; + if (item->family == AF_INET6) { + hints.ai_flags |= AI_V4MAPPED; + } - rv = getaddrinfo(item->name, item->serv, &hints, &results); - if (rv != 0) { - rv = nni_win_gai_errno(rv); + rv = getaddrinfo(item->name, item->serv, &hints, &results); + if (rv != 0) { + rv = nni_win_gai_errno(rv); + goto done; + } + + // We only take the first matching address. Presumably + // DNS load balancing is done by the resolver/server. + + rv = NNG_EADDRINVAL; + for (probe = results; probe != NULL; probe = probe->ai_next) { + if ((probe->ai_addr->sa_family == AF_INET) || + (probe->ai_addr->sa_family == AF_INET6)) { break; } + } - // Count the total number of results. - aio->a_naddrs = 0; - for (probe = results; probe != NULL; probe = probe->ai_next) { - // Only count v4 and v6 addresses. - switch (probe->ai_addr->sa_family) { - case AF_INET: - case AF_INET6: - aio->a_naddrs++; - break; - } - } - // If the only results were not IPv4 or IPv6... - if (aio->a_naddrs == 0) { - rv = NNG_EADDRINVAL; + if (probe != NULL) { + struct sockaddr_in * sin; + struct sockaddr_in6 *sin6; + nng_sockaddr * sa = aio->a_addr; + + switch (probe->ai_addr->sa_family) { + case AF_INET: + rv = 0; + sin = (void *) probe->ai_addr; + sa->s_un.s_in.sa_family = NNG_AF_INET; + sa->s_un.s_in.sa_port = sin->sin_port; + sa->s_un.s_in.sa_addr = sin->sin_addr.s_addr; break; - } - aio->a_addrs = NNI_ALLOC_STRUCTS(aio->a_addrs, aio->a_naddrs); - if (aio->a_addrs == NULL) { - aio->a_naddrs = 0; - rv = NNG_ENOMEM; + case AF_INET6: + rv = 0; + sin6 = (void *) probe->ai_addr; + sa->s_un.s_in6.sa_family = NNG_AF_INET6; + sa->s_un.s_in6.sa_port = sin6->sin6_port; + memcpy(sa->s_un.s_in6.sa_addr, sin6->sin6_addr.s6_addr, + 16); break; } - i = 0; - for (probe = results; probe != NULL; probe = probe->ai_next) { - struct sockaddr_in * sin; - struct sockaddr_in6 *sin6; - nng_sockaddr * sa = &aio->a_addrs[i]; - - switch (probe->ai_addr->sa_family) { - case AF_INET: - sin = (void *) probe->ai_addr; - sa->s_un.s_in.sa_family = NNG_AF_INET; - sa->s_un.s_in.sa_port = sin->sin_port; - sa->s_un.s_in.sa_addr = sin->sin_addr.s_addr; - i++; - break; - case AF_INET6: - sin6 = (void *) probe->ai_addr; - sa->s_un.s_in6.sa_family = NNG_AF_INET6; - sa->s_un.s_in6.sa_port = sin6->sin6_port; - memcpy(sa->s_un.s_in6.sa_addr, - sin6->sin6_addr.s6_addr, 16); - i++; - break; - default: - // Other address types are ignored. - break; - } - } - // Resolution complete! - rv = 0; - break; - - default: - // Some other family requested we don't understand. - rv = NNG_ENOTSUP; - break; } +done: + if (results != NULL) { freeaddrinfo(results); } @@ -204,35 +178,37 @@ nni_win_resolv_ip(const char *host, const char *serv, int passive, int family, { nni_win_resolv_item *item; int rv; - - if ((aio->a_naddrs != 0) && (aio->a_addrs != NULL)) { - NNI_FREE_STRUCTS(aio->a_addrs, aio->a_naddrs); - } - if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { - nni_aio_finish(aio, NNG_ENOMEM, 0); - return; - } - - nni_task_init( - nni_win_resolv_tq, &item->task, nni_win_resolv_task, item); + int fam; switch (family) { case NNG_AF_INET: - item->family = AF_INET; + fam = AF_INET; break; case NNG_AF_INET6: - item->family = AF_INET6; + fam = AF_INET6; break; case NNG_AF_UNSPEC: - item->family = AF_UNSPEC; + fam = AF_UNSPEC; break; + default: + nni_aio_finish_error(aio, NNG_ENOTSUP); + return; } - // NB: host and serv must remain valid until this is completed. + + if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { + nni_aio_finish_error(aio, NNG_ENOMEM); + return; + } + + nni_task_init( + nni_win_resolv_tq, &item->task, nni_win_resolv_task, item); + item->passive = passive; item->name = host; item->serv = serv; item->proto = proto; item->aio = aio; + item->family = fam; nni_mtx_lock(&nni_win_resolv_mtx); // If we were stopped, we're done... diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c index 11bfceb9..3430ceb3 100644 --- a/src/transport/ipc/ipc.c +++ b/src/transport/ipc/ipc.c @@ -485,18 +485,24 @@ nni_ipc_ep_fini(void *arg) static int nni_ipc_ep_init(void **epp, const char *url, nni_sock *sock, int mode) { - nni_ipc_ep *ep; - int rv; + nni_ipc_ep * ep; + int rv; + nni_sockaddr sa; if ((strlen(url) > NNG_MAXADDRLEN - 1) || (strncmp(url, "ipc://", strlen("ipc://")) != 0)) { return (NNG_EADDRINVAL); } + sa.s_un.s_path.sa_family = NNG_AF_IPC; + (void) snprintf(sa.s_un.s_path.sa_path, sizeof(sa.s_un.s_path.sa_path), + "%s", url + strlen("ipc://")); + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - if ((rv = nni_plat_ipc_ep_init(&ep->iep, url, mode)) != 0) { + url += strlen("ipc://"); + if ((rv = nni_plat_ipc_ep_init(&ep->iep, &sa, mode)) != 0) { NNI_FREE_STRUCT(ep); return (rv); } diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c index 99e59302..24362fcd 100644 --- a/src/transport/tcp/tcp.c +++ b/src/transport/tcp/tcp.c @@ -458,19 +458,15 @@ nni_tcp_parse_pair(char *pair, char **hostp, char **servp) serv++; } } - if (hostp != NULL) { - if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) { - *hostp = NULL; - } else { - *hostp = host; - } + if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) { + *hostp = NULL; + } else { + *hostp = host; } - if (servp != NULL) { - if (strlen(serv) == 0) { - *servp = NULL; - } else { - *servp = serv; - } + if (strlen(serv) == 0) { + *servp = NULL; + } else { + *servp = serv; } // Stash the port in big endian (network) byte order. return (0); @@ -478,8 +474,8 @@ nni_tcp_parse_pair(char *pair, char **hostp, char **servp) // Note that the url *must* be in a modifiable buffer. int -nni_tcp_parse_url( - char *url, char **host1, char **serv1, char **host2, char **serv2) +nni_tcp_parse_url(char *url, char **lhost, char **lserv, char **rhost, + char **rserv, int mode) { char *h1; int rv; @@ -488,27 +484,40 @@ nni_tcp_parse_url( return (NNG_EADDRINVAL); } url += strlen("tcp://"); - if ((h1 = strchr(url, ';')) != 0) { - // For these we want the second part first, because - // the "primary" address is the remote address, and the - // "secondary" is the local (bind) address. This is only - // used for dial side. + if ((mode == NNI_EP_MODE_DIAL) && ((h1 = strchr(url, ';')) != 0)) { + // The local address is the first part, the remote address + // is the second part. *h1 = '\0'; h1++; - if (((rv = nni_tcp_parse_pair(h1, host1, serv1)) != 0) || - ((rv = nni_tcp_parse_pair(url, host2, serv2)) != 0)) { + if (((rv = nni_tcp_parse_pair(h1, rhost, rserv)) != 0) || + ((rv = nni_tcp_parse_pair(url, lhost, lserv)) != 0)) { return (rv); } - } else { - if (host2 != NULL) { - *host2 = NULL; + if ((*rserv == NULL) || (*rhost == NULL)) { + // We have to know where to connect to! + return (NNG_EADDRINVAL); } - if (serv2 != NULL) { - *serv2 = NULL; + } else if (mode == NNI_EP_MODE_DIAL) { + *lhost = NULL; + *lserv = NULL; + if ((rv = nni_tcp_parse_pair(url, rhost, rserv)) != 0) { + return (rv); + } + if ((*rserv == NULL) || (*rhost == NULL)) { + // We have to know where to connect to! + return (NNG_EADDRINVAL); } - if ((rv = nni_tcp_parse_pair(url, host1, serv1)) != 0) { + } else { + NNI_ASSERT(mode == NNI_EP_MODE_LISTEN); + *rhost = NULL; + *rserv = NULL; + if ((rv = nni_tcp_parse_pair(url, lhost, lserv)) != 0) { return (rv); } + // We have to have a port to listen on! + if (*lserv == NULL) { + return (NNG_EADDRINVAL); + } } return (0); } @@ -559,16 +568,65 @@ nni_tcp_ep_fini(void *arg) static int nni_tcp_ep_init(void **epp, const char *url, nni_sock *sock, int mode) { - nni_tcp_ep *ep; - int rv; + nni_tcp_ep * ep; + int rv; + char buf[NNG_MAXADDRLEN + 1]; + char * rhost; + char * rserv; + char * lhost; + char * lserv; + nni_sockaddr rsa, lsa; + nni_aio aio; + int passive; + + // Make a copy of the url (to allow for destructive operations) + snprintf(buf, sizeof(buf), "%s", url); + + // Parse the URLs first. + rv = nni_tcp_parse_url(buf, &lhost, &lserv, &rhost, &rserv, mode); + if (rv != 0) { + return (rv); + } + passive = (mode == NNI_EP_MODE_DIAL ? 0 : 1); + + nni_aio_init(&aio, NULL, NULL); + + // XXX: arguably we could defer this part to the point we do a bind + // or connect! + + if ((rhost != NULL) || (rserv != NULL)) { + aio.a_addr = &rsa; + nni_plat_tcp_resolv( + rhost, rserv, NNG_AF_UNSPEC, passive, &aio); + nni_aio_wait(&aio); + if ((rv = nni_aio_result(&aio)) != 0) { + return (rv); + } + } else { + rsa.s_un.s_family = NNG_AF_UNSPEC; + } + + if ((lhost != NULL) || (lserv != NULL)) { + aio.a_addr = &lsa; + nni_plat_tcp_resolv( + lhost, lserv, NNG_AF_UNSPEC, passive, &aio); + nni_aio_wait(&aio); + if ((rv = nni_aio_result(&aio)) != 0) { + return (rv); + } + } else { + lsa.s_un.s_family = NNG_AF_UNSPEC; + } if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - if ((rv = nni_plat_tcp_ep_init(&ep->tep, url, mode)) != 0) { + + if ((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) { NNI_FREE_STRUCT(ep); return (rv); } + nni_mtx_init(&ep->mtx); nni_aio_init(&ep->aio, nni_tcp_ep_cb, ep); -- cgit v1.2.3-70-g09d2