aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-01-05 14:44:10 -0800
committerGarrett D'Amore <garrett@damore.org>2018-01-05 15:17:27 -0800
commit1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f (patch)
tree95fc90338cbe38a46e561511604cf8ed079934fd
parent224dae56a379aa309fca261d61e7e356b14a536f (diff)
downloadnng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.tar.gz
nng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.tar.bz2
nng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.zip
Convert existing websocket and http code to use new URL framework.
This also fixes a use-after-free bug in the HTTP framework, where the handler could be deleted why callbacks were still using it. (We now reference count the handlers.)
-rw-r--r--src/core/transport.c70
-rw-r--r--src/core/transport.h8
-rw-r--r--src/core/url.c13
-rw-r--r--src/core/url.h3
-rw-r--r--src/supplemental/http/server.c43
-rw-r--r--src/supplemental/websocket/websocket.c185
-rw-r--r--src/transport/tcp/tcp.c178
-rw-r--r--tests/tcp.c48
-rw-r--r--tests/url.c10
-rw-r--r--tests/ws.c4
-rw-r--r--tests/wss.c4
11 files changed, 182 insertions, 384 deletions
diff --git a/src/core/transport.c b/src/core/transport.c
index 9c129a72..0891ec8c 100644
--- a/src/core/transport.c
+++ b/src/core/transport.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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
@@ -106,72 +106,6 @@ nni_tran_find(const char *addr)
return (NULL);
}
-// nni_tran_parse_host_port is a convenience routine to parse the host portion
-// of a URL (which includes a DNS name or IP address and an optional service
-// name or port, separated by a colon) into its host and port name parts. It
-// understands IPv6 address literals when surrounded by brackets ([]).
-// If either component is empty, then NULL is passed back for the value,
-// otherwise a string suitable for freeing with nni_strfree is supplied.
-int
-nni_tran_parse_host_port(const char *pair, char **hostp, char **portp)
-{
- const char *hstart;
- const char *pstart;
- char * host;
- char * port;
- size_t hlen, plen;
-
- if (pair[0] == '[') {
- hstart = pair + 1;
- hlen = 0;
- while (hstart[hlen] != ']') {
- if (hstart[hlen] == '\0') {
- return (NNG_EADDRINVAL);
- }
- hlen++;
- }
- pstart = hstart + hlen + 1; // skip over the trailing ']'
- } else {
- // Normal thing.
- hstart = pair;
- hlen = 0;
- while ((hstart[hlen] != ':') && (hstart[hlen] != '\0')) {
- hlen++;
- }
- pstart = hstart + hlen;
- }
- if (pstart[0] == ':') {
- pstart++;
- }
- plen = strlen(pstart);
-
- host = NULL;
- if (hostp) {
- if ((hlen > 1) || ((hlen == 1) && (*hstart != '*'))) {
- if ((host = nni_alloc(hlen + 1)) == NULL) {
- return (NNG_ENOMEM);
- }
- memcpy(host, hstart, hlen);
- host[hlen] = '\0';
- }
- }
-
- port = NULL;
- if ((plen != 0) && (portp)) {
- if ((port = nni_strdup(pstart)) == NULL) {
- nni_strfree(host);
- return (NNG_ENOMEM);
- }
- }
- if (hostp) {
- *hostp = host;
- }
- if (portp) {
- *portp = port;
- }
- return (0);
-}
-
int
nni_tran_chkopt(const char *name, const void *v, size_t sz)
{
diff --git a/src/core/transport.h b/src/core/transport.h
index 3098bd1a..9a6dc31d 100644
--- a/src/core/transport.h
+++ b/src/core/transport.h
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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
@@ -162,10 +162,6 @@ struct nni_tran_pipe {
nni_tran_pipe_option *p_options;
};
-// Utility for transports.
-
-extern int nni_tran_parse_host_port(const char *, char **, char **);
-
// These APIs are used by the framework internally, and not for use by
// transport implementations.
extern nni_tran *nni_tran_find(const char *);
diff --git a/src/core/url.c b/src/core/url.c
index 8dee5219..8cb5a2e7 100644
--- a/src/core/url.c
+++ b/src/core/url.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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
@@ -250,13 +250,17 @@ nni_url_parse(nni_url **urlp, const char *raw)
}
if ((url->u_host = nni_alloc(len + 1)) == NULL) {
- nni_url_free(url);
- return (NNG_ENOMEM);
+ rv = NNG_ENOMEM;
+ goto error;
}
memcpy(url->u_host, s, len);
url->u_host[len] = '\0';
s += len;
+ if ((url->u_rawpath = nni_strdup(s)) == NULL) {
+ rv = NNG_ENOMEM;
+ goto error;
+ }
for (len = 0; (c = s[len]) != '\0'; len++) {
if ((c == '?') || (c == '#')) {
break;
@@ -363,5 +367,6 @@ nni_url_free(nni_url *url)
nni_strfree(url->u_path);
nni_strfree(url->u_query);
nni_strfree(url->u_fragment);
+ nni_strfree(url->u_rawpath);
NNI_FREE_STRUCT(url);
} \ No newline at end of file
diff --git a/src/core/url.h b/src/core/url.h
index ee336b1d..91054dcb 100644
--- a/src/core/url.h
+++ b/src/core/url.h
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Garrett D'Amore <garrett@damore.org>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -23,6 +23,7 @@ struct nni_url {
char *u_path; // path, will be "" if not specified
char *u_query; // without '?', will be NULL if not specified
char *u_fragment; // without '#', will be NULL if not specified
+ char *u_rawpath; // includes query and fragment, "" if not specified
};
extern int nni_url_parse(nni_url **, const char *path);
diff --git a/src/supplemental/http/server.c b/src/supplemental/http/server.c
index cce73765..01f1230d 100644
--- a/src/supplemental/http/server.c
+++ b/src/supplemental/http/server.c
@@ -35,6 +35,7 @@ typedef struct http_handler {
char * h_host;
bool h_is_upgrader;
bool h_is_dir;
+ int h_refcnt;
void (*h_cb)(nni_aio *);
void (*h_free)(void *);
} http_handler;
@@ -72,6 +73,7 @@ struct nni_http_server {
static nni_list http_servers;
static nni_mtx http_servers_lk;
+static void http_handler_fini(http_handler *);
static void
http_sconn_reap(void *arg)
@@ -372,6 +374,7 @@ http_sconn_rxdone(void *arg)
strncpy(uri, val, urisz);
path = http_uri_canonify(uri);
+ nni_mtx_lock(&s->mtx);
NNI_LIST_FOREACH (&s->handlers, h) {
size_t len;
if (h->h_host != NULL) {
@@ -438,6 +441,7 @@ http_sconn_rxdone(void *arg)
nni_free(uri, urisz);
if (h == NULL) {
+ nni_mtx_unlock(&s->mtx);
if (badmeth) {
http_sconn_error(
sc, NNI_HTTP_STATUS_METHOD_NOT_ALLOWED);
@@ -450,23 +454,27 @@ http_sconn_rxdone(void *arg)
nni_aio_set_input(sc->cbaio, 0, sc->http);
nni_aio_set_input(sc->cbaio, 1, sc->req);
nni_aio_set_input(sc->cbaio, 2, h->h_arg);
- nni_aio_set_data(sc->cbaio, 1, h);
// Technically, probably callback should initialize this with
// start, but we do it instead.
if (nni_aio_start(sc->cbaio, NULL, NULL) == 0) {
+ nni_aio_set_data(sc->cbaio, 1, h);
+ h->h_refcnt++;
h->h_cb(sc->cbaio);
}
+ nni_mtx_unlock(&s->mtx);
}
static void
http_sconn_cbdone(void *arg)
{
- http_sconn * sc = arg;
- nni_aio * aio = sc->cbaio;
- nni_http_res *res;
- http_handler *h;
+ http_sconn * sc = arg;
+ nni_aio * aio = sc->cbaio;
+ nni_http_res * res;
+ http_handler * h;
+ nni_http_server *s = sc->server;
+ bool upgrader;
if (nni_aio_result(aio) != 0) {
// Hard close, no further feedback.
@@ -477,10 +485,18 @@ http_sconn_cbdone(void *arg)
h = nni_aio_get_data(aio, 1);
res = nni_aio_get_output(aio, 0);
+ nni_mtx_lock(&s->mtx);
+ upgrader = h->h_is_upgrader;
+ h->h_refcnt--;
+ if (h->h_refcnt == 0) {
+ http_handler_fini(h);
+ }
+ nni_mtx_unlock(&s->mtx);
+
// If its an upgrader, and they didn't give us back a response, it
// means that they took over, and we should just discard this session,
// without closing the underlying channel.
- if ((h->h_is_upgrader) && (res == NULL)) {
+ if (upgrader && (res == NULL)) {
sc->http = NULL; // the underlying HTTP is not closed
sc->req = NULL;
sc->res = NULL;
@@ -795,13 +811,11 @@ http_server_add_handler(void **hp, nni_http_server *s, nni_http_handler *hh,
h->h_is_upgrader = hh->h_is_upgrader;
h->h_free = freeit;
- // Ignore the port part of the host.
+ // When registering the handler, only register *host*, not port.
if (hh->h_host != NULL) {
- int rv;
- rv = nni_tran_parse_host_port(hh->h_host, &h->h_host, NULL);
- if (rv != 0) {
+ if ((h->h_host = nni_strdup(hh->h_host)) == NULL) {
http_handler_fini(h);
- return (rv);
+ return (NNG_ENOMEM);
}
}
@@ -847,6 +861,7 @@ http_server_add_handler(void **hp, nni_http_server *s, nni_http_handler *hh,
return (NNG_EADDRINUSE);
}
}
+ h->h_refcnt = 1;
nni_list_append(&s->handlers, h);
nni_mtx_unlock(&s->mtx);
if (hp != NULL) {
@@ -869,9 +884,11 @@ nni_http_server_del_handler(nni_http_server *s, void *harg)
nni_mtx_lock(&s->mtx);
nni_list_node_remove(&h->node);
+ h->h_refcnt--;
+ if (h->h_refcnt == 0) {
+ http_handler_fini(h);
+ }
nni_mtx_unlock(&s->mtx);
-
- http_handler_fini(h);
}
// Very limited MIME type map. Used only if the handler does not
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index effba8d7..c350a3c7 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.c
@@ -57,15 +57,12 @@ struct nni_ws {
struct nni_ws_listener {
nni_http_server * server;
char * proto;
- char * url;
- char * host;
- char * serv;
- char * path;
nni_mtx mtx;
nni_cv cv;
nni_list pend;
nni_list reply;
nni_list aios;
+ nni_url * url;
bool started;
bool closed;
void * hp; // handler pointer
@@ -88,12 +85,7 @@ struct nni_ws_dialer {
nni_mtx mtx;
nni_aio * conaio;
char * proto;
- char * host;
- char * serv;
- char * path;
- char * qinfo;
- char * addr; // full address (a URL really)
- char * uri; // path + query
+ nni_url * url;
nni_list conaios; // user aios waiting for connect.
nni_list httpaios; // user aios waiting for HTTP nego.
bool started;
@@ -1280,7 +1272,7 @@ ws_init(nni_ws **wsp, nni_http *http, nni_http_req *req, nni_http_res *res)
}
nni_aio_set_timeout(ws->closeaio, 100);
- nni_aio_set_timeout(ws->httpaio, 1000);
+ nni_aio_set_timeout(ws->httpaio, 2000);
ws->fragsize = 1 << 20; // we won't send a frame larger than this
ws->maxframe = (1 << 20) * 10; // default limit on incoming frame size
@@ -1311,17 +1303,16 @@ nni_ws_listener_fini(nni_ws_listener *l)
nni_cv_fini(&l->cv);
nni_mtx_fini(&l->mtx);
- nni_strfree(l->url);
nni_strfree(l->proto);
- nni_strfree(l->host);
- nni_strfree(l->serv);
- nni_strfree(l->path);
while ((hdr = nni_list_first(&l->headers)) != NULL) {
nni_list_remove(&l->headers, hdr);
nni_strfree(hdr->name);
nni_strfree(hdr->value);
NNI_FREE_STRUCT(hdr);
}
+ if (l->url) {
+ nni_url_free(l->url);
+ }
NNI_FREE_STRUCT(l);
}
@@ -1479,103 +1470,15 @@ err:
}
}
-static int
-ws_parse_url(const char *url, char **schemep, char **hostp, char **servp,
- char **pathp, char **queryp)
-{
- size_t scrlen;
- char * scr;
- char * pair;
- char * scheme = NULL;
- char * path = NULL;
- char * query = NULL;
- char * host = NULL;
- char * serv = NULL;
- int rv;
-
- // We need a scratch copy of the url to parse.
- scrlen = strlen(url) + 1;
- if ((scr = nni_alloc(scrlen)) == NULL) {
- return (NNG_ENOMEM);
- }
- nni_strlcpy(scr, url, scrlen);
- scheme = scr;
- pair = strchr(scr, ':');
- if ((pair == NULL) || (pair[1] != '/') || (pair[2] != '/')) {
- nni_free(scr, scrlen);
- return (NNG_EADDRINVAL);
- }
-
- *pair = '\0';
- pair += 3;
-
- path = strchr(pair, '/');
- if (path != NULL) {
- *path = '\0'; // We will restore it shortly.
- }
- if ((rv = nni_tran_parse_host_port(pair, hostp, servp)) != 0) {
- nni_free(scr, scrlen);
- return (rv);
- }
-
- // If service was missing, assume normal defaults.
- if (*servp == NULL) {
- if (strcmp(scheme, "wss")) {
- *servp = nni_strdup("443");
- } else {
- *servp = nni_strdup("80");
- }
- }
-
- if (path) {
- // Restore the path, and trim off the query parameter.
- *path = '/';
- if ((query = strchr(path, '?')) != NULL) {
- *query = '\0';
- query++;
- } else {
- query = "";
- }
- } else {
- path = "/";
- query = "";
- }
-
- if (schemep) {
- *schemep = nni_strdup(scheme);
- }
- if (pathp) {
- *pathp = nni_strdup(path);
- }
- if (queryp) {
- *queryp = nni_strdup(query);
- }
- nni_free(scr, scrlen);
-
- if ((schemep && (*schemep == NULL)) || (*pathp == NULL) ||
- (*servp == NULL) || (queryp && (*queryp == NULL))) {
- nni_strfree(*hostp);
- nni_strfree(*servp);
- nni_strfree(*pathp);
- if (schemep) {
- nni_strfree(*schemep);
- }
- if (queryp) {
- nni_strfree(*queryp);
- }
- return (NNG_ENOMEM);
- }
-
- return (0);
-}
-
int
-nni_ws_listener_init(nni_ws_listener **wslp, const char *url)
+nni_ws_listener_init(nni_ws_listener **wslp, const char *addr)
{
nni_ws_listener *l;
int rv;
nni_aio * aio;
nni_sockaddr sa;
+ char * host;
+ char * serv;
if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
return (NNG_ENOMEM);
@@ -1587,16 +1490,25 @@ nni_ws_listener_init(nni_ws_listener **wslp, const char *url)
NNI_LIST_INIT(&l->pend, nni_ws, node);
NNI_LIST_INIT(&l->reply, nni_ws, node);
- rv = ws_parse_url(url, NULL, &l->host, &l->serv, &l->path, NULL);
- if (rv != 0) {
+ if ((rv = nni_url_parse(&l->url, addr)) != 0) {
nni_ws_listener_fini(l);
return (rv);
}
+
+ host = l->url->u_hostname;
+ if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) {
+ host = NULL;
+ }
+ serv = l->url->u_port;
+ if (strlen(serv) == 0) {
+ serv = (strcmp(l->url->u_scheme, "wss") == 0) ? "443" : "80";
+ }
+
l->handler.h_is_dir = false;
l->handler.h_is_upgrader = true;
l->handler.h_method = "GET";
- l->handler.h_path = l->path;
- l->handler.h_host = l->host;
+ l->handler.h_path = l->url->u_path;
+ l->handler.h_host = host; // ignore the port
l->handler.h_cb = ws_handler;
if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
@@ -1604,7 +1516,7 @@ nni_ws_listener_init(nni_ws_listener **wslp, const char *url)
return (rv);
}
aio->a_addr = &sa;
- nni_plat_tcp_resolv(l->host, l->serv, NNG_AF_UNSPEC, true, aio);
+ nni_plat_tcp_resolv(host, serv, NNG_AF_UNSPEC, true, aio);
nni_aio_wait(aio);
rv = nni_aio_result(aio);
nni_aio_fini(aio);
@@ -1813,18 +1725,12 @@ ws_conn_cb(void *arg)
nni_base64_encode(raw, 16, wskey, 24);
wskey[24] = '\0';
- if (d->qinfo && d->qinfo[0] != '\0') {
- rv = nni_asprintf(&d->uri, "%s?%s", d->path, d->qinfo);
- } else if ((d->uri = nni_strdup(d->path)) == NULL) {
- rv = NNG_ENOMEM;
- }
-
#define SETH(h, v) nni_http_req_set_header(req, h, v)
if ((rv != 0) || ((rv = nni_http_req_init(&req)) != 0) ||
- ((rv = nni_http_req_set_uri(req, d->uri)) != 0) ||
+ ((rv = nni_http_req_set_uri(req, d->url->u_rawpath)) != 0) ||
((rv = nni_http_req_set_version(req, "HTTP/1.1")) != 0) ||
((rv = nni_http_req_set_method(req, "GET")) != 0) ||
- ((rv = SETH("Host", d->host)) != 0) ||
+ ((rv = SETH("Host", d->url->u_host)) != 0) ||
((rv = SETH("Upgrade", "websocket")) != 0) ||
((rv = SETH("Connection", "Upgrade")) != 0) ||
((rv = SETH("Sec-WebSocket-Key", wskey)) != 0) ||
@@ -1879,12 +1785,6 @@ nni_ws_dialer_fini(nni_ws_dialer *d)
nni_aio_fini(d->conaio);
nni_strfree(d->proto);
- nni_strfree(d->addr);
- nni_strfree(d->uri);
- nni_strfree(d->host);
- nni_strfree(d->serv);
- nni_strfree(d->path);
- nni_strfree(d->qinfo);
while ((hdr = nni_list_first(&d->headers)) != NULL) {
nni_list_remove(&d->headers, hdr);
nni_strfree(hdr->name);
@@ -1894,16 +1794,22 @@ nni_ws_dialer_fini(nni_ws_dialer *d)
if (d->client) {
nni_http_client_fini(d->client);
}
+ if (d->url) {
+ nni_url_free(d->url);
+ }
nni_mtx_fini(&d->mtx);
NNI_FREE_STRUCT(d);
}
int
-nni_ws_dialer_init(nni_ws_dialer **dp, const char *url)
+nni_ws_dialer_init(nni_ws_dialer **dp, const char *addr)
{
nni_ws_dialer *d;
int rv;
nni_aio * aio;
+ nni_url * url;
+ char * host;
+ char * serv;
if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
return (NNG_ENOMEM);
@@ -1913,15 +1819,29 @@ nni_ws_dialer_init(nni_ws_dialer **dp, const char *url)
nni_aio_list_init(&d->conaios);
nni_aio_list_init(&d->httpaios);
- if ((d->addr = nni_strdup(url)) == NULL) {
+ if ((rv = nni_url_parse(&d->url, addr)) != 0) {
nni_ws_dialer_fini(d);
- return (NNG_ENOMEM);
+ return (rv);
}
- if ((rv = ws_parse_url(
- url, NULL, &d->host, &d->serv, &d->path, &d->qinfo)) != 0) {
+
+ // Dialer requires a valid host.
+ if ((strlen(d->url->u_hostname) == 0) ||
+ (strcmp(d->url->u_hostname, "*") == 0)) {
nni_ws_dialer_fini(d);
- return (rv);
+ return (NNG_EADDRINVAL);
}
+
+ // Default port is 80 for ws, and 443 for wss.
+ if ((d->url->u_port == NULL) || (strlen(d->url->u_port) == 0)) {
+ if (strcmp(d->url->u_scheme, "wss") == 0) {
+ serv = "443";
+ } else {
+ serv = "80";
+ }
+ } else {
+ serv = d->url->u_port;
+ }
+
if ((rv = nni_aio_init(&d->conaio, ws_conn_cb, d)) != 0) {
nni_ws_dialer_fini(d);
return (rv);
@@ -1933,7 +1853,8 @@ nni_ws_dialer_init(nni_ws_dialer **dp, const char *url)
}
// XXX: this is synchronous. We should fix this in the HTTP layer.
aio->a_addr = &d->sa;
- nni_plat_tcp_resolv(d->host, d->serv, NNG_AF_UNSPEC, false, aio);
+ nni_plat_tcp_resolv(
+ d->url->u_hostname, serv, NNG_AF_UNSPEC, false, aio);
nni_aio_wait(aio);
rv = nni_aio_result(aio);
nni_aio_fini(aio);
diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c
index 538833c2..a361da53 100644
--- a/src/transport/tcp/tcp.c
+++ b/src/transport/tcp/tcp.c
@@ -22,7 +22,6 @@ typedef struct nni_tcp_ep nni_tcp_ep;
// nni_tcp_pipe is one end of a TCP connection.
struct nni_tcp_pipe {
- const char * addr;
nni_plat_tcp_pipe *tpp;
uint16_t peer;
uint16_t proto;
@@ -46,7 +45,6 @@ struct nni_tcp_pipe {
};
struct nni_tcp_ep {
- char addr[NNG_MAXADDRLEN + 1];
nni_plat_tcp_ep *tep;
uint16_t proto;
size_t rcvmax;
@@ -54,6 +52,7 @@ struct nni_tcp_ep {
int ipv4only;
nni_aio * aio;
nni_aio * user_aio;
+ nni_url * url;
nni_mtx mtx;
};
@@ -123,7 +122,6 @@ nni_tcp_pipe_init(nni_tcp_pipe **pipep, nni_tcp_ep *ep, void *tpp)
p->proto = ep->proto;
p->rcvmax = ep->rcvmax;
p->tpp = tpp;
- p->addr = ep->addr;
*pipep = p;
return (0);
@@ -488,96 +486,7 @@ nni_tcp_pipe_getopt_remaddr(void *arg, void *v, size_t *szp)
return (rv);
}
-static int
-nni_tcp_parse_pair(char *pair, char **hostp, char **servp)
-{
- char *host, *serv, *end;
-
- if (pair[0] == '[') {
- host = pair + 1;
- // IP address enclosed ... for IPv6 usually.
- if ((end = strchr(host, ']')) == NULL) {
- return (NNG_EADDRINVAL);
- }
- *end = '\0';
- serv = end + 1;
- if (*serv == ':') {
- serv++;
- } else if (*serv != '\0') {
- return (NNG_EADDRINVAL);
- }
- } else {
- host = pair;
- serv = strchr(host, ':');
- if (serv != NULL) {
- *serv = '\0';
- serv++;
- }
- }
- if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) {
- *hostp = NULL;
- } else {
- *hostp = host;
- }
- if ((serv == NULL) || (strlen(serv) == 0)) {
- *servp = NULL;
- } else {
- *servp = serv;
- }
- // Stash the port in big endian (network) byte order.
- return (0);
-}
-
// Note that the url *must* be in a modifiable buffer.
-int
-nni_tcp_parse_url(char *url, char **lhost, char **lserv, char **rhost,
- char **rserv, int mode)
-{
- char *h1;
- int rv;
-
- if (strncmp(url, "tcp://", strlen("tcp://")) != 0) {
- return (NNG_EADDRINVAL);
- }
- url += strlen("tcp://");
- 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, rhost, rserv)) != 0) ||
- ((rv = nni_tcp_parse_pair(url, lhost, lserv)) != 0)) {
- return (rv);
- }
- if ((*rserv == NULL) || (*rhost == NULL)) {
- // We have to know where to connect to!
- return (NNG_EADDRINVAL);
- }
- } 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);
- }
- } 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);
-}
-
static void
nni_tcp_pipe_start(void *arg, nni_aio *aio)
{
@@ -618,83 +527,94 @@ nni_tcp_ep_fini(void *arg)
if (ep->tep != NULL) {
nni_plat_tcp_ep_fini(ep->tep);
}
+ nni_url_free(ep->url);
nni_aio_fini(ep->aio);
nni_mtx_fini(&ep->mtx);
NNI_FREE_STRUCT(ep);
}
static int
-nni_tcp_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
+nni_tcp_ep_init(void **epp, const char *addr, nni_sock *sock, int mode)
{
nni_tcp_ep * ep;
int rv;
- char buf[NNG_MAXADDRLEN + 1];
- char * rhost;
- char * rserv;
- char * lhost;
- char * lserv;
+ char * host;
+ char * serv;
nni_sockaddr rsa, lsa;
nni_aio * aio;
int passive;
+ nni_url * url;
- // Make a copy of the url (to allow for destructive operations)
- if (nni_strlcpy(buf, url, sizeof(buf)) >= sizeof(buf)) {
+ if ((rv = nni_url_parse(&url, addr)) != 0) {
+ return (rv);
+ }
+ // Check for invalid URL components.
+ if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) {
+ nni_url_free(url);
return (NNG_EADDRINVAL);
}
-
- // Parse the URLs first.
- rv = nni_tcp_parse_url(buf, &lhost, &lserv, &rhost, &rserv, mode);
- if (rv != 0) {
- return (rv);
+ if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) ||
+ (url->u_query != NULL)) {
+ nni_url_free(url);
+ return (NNG_EADDRINVAL);
}
- passive = (mode == NNI_EP_MODE_DIAL ? 0 : 1);
if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
+ nni_url_free(url);
return (rv);
}
+ if ((strlen(url->u_hostname) == 0) ||
+ (strcmp(url->u_hostname, "*") == 0)) {
+ host = NULL;
+ } else {
+ host = url->u_hostname;
+ }
+
+ if (strlen(url->u_port) == 0) {
+ serv = NULL;
+ } else {
+ serv = url->u_port;
+ }
// 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) {
+ if (mode == NNI_EP_MODE_DIAL) {
+ passive = 0;
+ lsa.s_un.s_family = NNG_AF_UNSPEC;
+ aio->a_addr = &rsa;
+ if ((host == NULL) || (serv == NULL)) {
+ nni_url_free(url);
nni_aio_fini(aio);
- return (rv);
+ return (NNG_EADDRINVAL);
}
} else {
+ passive = 1;
rsa.s_un.s_family = NNG_AF_UNSPEC;
+ aio->a_addr = &lsa;
}
- 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) {
- nni_aio_fini(aio);
- return (rv);
- }
- } else {
- lsa.s_un.s_family = NNG_AF_UNSPEC;
+ nni_plat_tcp_resolv(host, serv, NNG_AF_UNSPEC, passive, aio);
+ nni_aio_wait(aio);
+ if ((rv = nni_aio_result(aio)) != 0) {
+ nni_url_free(url);
+ nni_aio_fini(aio);
+ return (rv);
}
+
nni_aio_fini(aio);
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
+ nni_url_free(url);
return (NNG_ENOMEM);
}
- if (nni_strlcpy(ep->addr, url, sizeof(ep->addr)) >= sizeof(ep->addr)) {
- NNI_FREE_STRUCT(ep);
- return (NNG_EADDRINVAL);
- }
+ nni_mtx_init(&ep->mtx);
+ ep->url = url;
if ((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) {
- NNI_FREE_STRUCT(ep);
+ nni_tcp_ep_fini(ep);
return (rv);
}
- nni_mtx_init(&ep->mtx);
if ((rv = nni_aio_init(&ep->aio, nni_tcp_ep_cb, ep)) != 0) {
nni_tcp_ep_fini(ep);
return (rv);
diff --git a/tests/tcp.c b/tests/tcp.c
index fdcf458c..5860eb03 100644
--- a/tests/tcp.c
+++ b/tests/tcp.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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
@@ -23,31 +23,27 @@
static int
check_props_v4(nng_msg *msg, nng_listener l, nng_dialer d)
{
- nng_pipe p;
- size_t z;
+ nng_pipe p;
+ size_t z;
+ nng_sockaddr la;
+ nng_sockaddr ra;
+
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 == htons(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));
- });
+ 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 == htons(trantest_port - 1));
+ So(la.s_un.s_in.sa_port != 0);
+ So(la.s_un.s_in.sa_addr == htonl(0x7f000001));
+
+ 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));
return (0);
}
@@ -94,8 +90,6 @@ TestMain("TCP Transport", {
NNG_EADDRINVAL);
So(nng_dial(s1, "tcp://127.0.x.1.32", NULL, 0) ==
NNG_EADDRINVAL);
- So(nng_listen(s1, "tcp://127.0.0.1", NULL, 0) ==
- NNG_EADDRINVAL);
So(nng_listen(s1, "tcp://127.0.0.1.32", NULL, 0) ==
NNG_EADDRINVAL);
So(nng_listen(s1, "tcp://127.0.x.1.32", NULL, 0) ==
diff --git a/tests/url.c b/tests/url.c
index 019a1519..6fb35596 100644
--- a/tests/url.c
+++ b/tests/url.c
@@ -29,6 +29,7 @@ TestMain("URLs", {
So(strcmp(url->u_hostname, "www.google.com") == 0);
So(strcmp(url->u_port, "") == 0);
So(strcmp(url->u_path, "") == 0);
+ So(strcmp(url->u_rawpath, "") == 0);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
@@ -43,6 +44,7 @@ TestMain("URLs", {
So(strcmp(url->u_hostname, "www.google.com") == 0);
So(strcmp(url->u_port, "1234") == 0);
So(strcmp(url->u_path, "") == 0);
+ So(strcmp(url->u_rawpath, "") == 0);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
@@ -58,6 +60,7 @@ TestMain("URLs", {
So(strcmp(url->u_hostname, "www.google.com") == 0);
So(strcmp(url->u_port, "1234") == 0);
So(strcmp(url->u_path, "/somewhere") == 0);
+ So(strcmp(url->u_rawpath, "/somewhere") == 0);
So(url->u_userinfo == NULL);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
@@ -73,6 +76,7 @@ TestMain("URLs", {
So(strcmp(url->u_hostname, "www.google.com") == 0);
So(strcmp(url->u_port, "1234") == 0);
So(strcmp(url->u_path, "/somewhere") == 0);
+ So(strcmp(url->u_rawpath, "/somewhere") == 0);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
nni_url_free(url);
@@ -87,6 +91,7 @@ TestMain("URLs", {
So(strcmp(url->u_port, "") == 0);
So(strcmp(url->u_path, "/somewhere") == 0);
So(strcmp(url->u_query, "result=yes") == 0);
+ So(strcmp(url->u_rawpath, "/somewhere?result=yes") == 0);
So(url->u_userinfo == NULL);
So(url->u_fragment == NULL);
nni_url_free(url);
@@ -103,6 +108,8 @@ TestMain("URLs", {
So(strcmp(url->u_path, "/somewhere") == 0);
So(strcmp(url->u_query, "result=yes") == 0);
So(strcmp(url->u_fragment, "chapter1") == 0);
+ So(strcmp(url->u_rawpath, "/somewhere?result=yes#chapter1") ==
+ 0);
So(url->u_userinfo == NULL);
nni_url_free(url);
});
@@ -116,6 +123,7 @@ TestMain("URLs", {
So(strcmp(url->u_port, "") == 0);
So(strcmp(url->u_path, "/somewhere") == 0);
So(strcmp(url->u_fragment, "chapter2") == 0);
+ So(strcmp(url->u_rawpath, "/somewhere#chapter2") == 0);
So(url->u_query == NULL);
So(url->u_userinfo == NULL);
nni_url_free(url);
@@ -129,6 +137,7 @@ TestMain("URLs", {
So(strcmp(url->u_path, "") == 0);
So(strcmp(url->u_port, "") == 0);
So(strcmp(url->u_fragment, "chapter3") == 0);
+ So(strcmp(url->u_rawpath, "#chapter3") == 0);
So(url->u_query == NULL);
So(url->u_userinfo == NULL);
nni_url_free(url);
@@ -143,6 +152,7 @@ TestMain("URLs", {
So(strcmp(url->u_path, "") == 0);
So(strcmp(url->u_port, "") == 0);
So(strcmp(url->u_query, "color=red") == 0);
+ So(strcmp(url->u_rawpath, "?color=red") == 0);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
nni_url_free(url);
diff --git a/tests/ws.c b/tests/ws.c
index 386c0690..38db4738 100644
--- a/tests/ws.c
+++ b/tests/ws.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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
diff --git a/tests/wss.c b/tests/wss.c
index 38b333b9..5394ad59 100644
--- a/tests/wss.c
+++ b/tests/wss.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 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