aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/aio.c4
-rw-r--r--src/core/aio.h3
-rw-r--r--src/core/platform.h13
-rw-r--r--src/platform/posix/posix_aio.h5
-rw-r--r--src/platform/posix/posix_epdesc.c62
-rw-r--r--src/platform/posix/posix_ipc.c38
-rw-r--r--src/platform/posix/posix_resolv_gai.c170
-rw-r--r--src/platform/posix/posix_sockaddr.c30
-rw-r--r--src/platform/posix/posix_tcp.c75
-rw-r--r--src/platform/posix/posix_udp.c12
-rw-r--r--src/platform/windows/win_ipc.c10
-rw-r--r--src/platform/windows/win_net.c85
-rw-r--r--src/platform/windows/win_resolv.c154
-rw-r--r--src/transport/ipc/ipc.c12
-rw-r--r--src/transport/tcp/tcp.c118
15 files changed, 334 insertions, 457 deletions
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 <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
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 <sys/uio.h>
#include <unistd.h>
-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);