aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-11-17 18:23:17 -0800
committerGarrett D'Amore <garrett@damore.org>2024-11-17 22:05:20 -0800
commit85aff44e00e836eda618d4f1cf013bce38b3fd44 (patch)
tree94b2dca800d6d254baae17932a017e031c17ce67 /src/core
parentef82d4792bf59b1fe8053d9bb5ac924b443d8a78 (diff)
downloadnng-85aff44e00e836eda618d4f1cf013bce38b3fd44.tar.gz
nng-85aff44e00e836eda618d4f1cf013bce38b3fd44.tar.bz2
nng-85aff44e00e836eda618d4f1cf013bce38b3fd44.zip
URL u_port should be a number not a string.
The idea here is to reduce the dynamic allocations used for URLs, and also the back and forth with parsing begin strings and port numbers. We always resolve to a port number, and this is easier for everyone. The real goal in the long term is to eliminate dynamic allocation of the URL fields altogether, but that requires a little more work. This is a step in the right direction.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/platform.h6
-rw-r--r--src/core/tcp.c24
-rw-r--r--src/core/url.c84
-rw-r--r--src/core/url.h16
-rw-r--r--src/core/url_test.c55
5 files changed, 104 insertions, 81 deletions
diff --git a/src/core/platform.h b/src/core/platform.h
index 62a321bf..783cc9fc 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -343,7 +343,7 @@ extern int nni_tcp_listener_get(
// Symbolic service names will be looked up assuming SOCK_STREAM, so
// they may not work with UDP.
extern void nni_resolv_ip(
- const char *, const char *, int, bool, nng_sockaddr *sa, nni_aio *);
+ const char *, uint16_t, int, bool, nng_sockaddr *sa, nni_aio *);
// nni_parse_ip parses an IP address, without a port.
extern int nni_parse_ip(const char *, nng_sockaddr *);
@@ -351,6 +351,10 @@ extern int nni_parse_ip(const char *, nng_sockaddr *);
// nni_parse_ip_port parses an IP address with an optional port appended.
extern int nni_parse_ip_port(const char *, nng_sockaddr *);
+// nni_get_port_by_name resolves a name (which may be an ASCII representation
+// of a number) to a port number (the value returned is in native byte order.)
+extern int nni_get_port_by_name(const char *, uint16_t *);
+
//
// IPC (UNIX Domain Sockets & Named Pipes) Support.
//
diff --git a/src/core/tcp.c b/src/core/tcp.c
index 7fb67228..5d324a13 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -1,5 +1,5 @@
//
-// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
//
@@ -10,6 +10,7 @@
//
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
#include <nng/nng.h>
@@ -20,8 +21,8 @@
typedef struct {
nng_stream_dialer ops;
- char *host;
- char *port;
+ char host[256];
+ uint16_t port;
int af; // address family
bool closed;
nng_sockaddr sa;
@@ -155,8 +156,6 @@ tcp_dialer_free(void *arg)
nni_tcp_dialer_fini(d->d);
}
nni_mtx_fini(&d->mtx);
- nni_strfree(d->host);
- nni_strfree(d->port);
NNI_FREE_STRUCT(d);
}
@@ -236,17 +235,13 @@ nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
{
tcp_dialer *d;
int rv;
- const char *p;
if ((rv = tcp_dialer_alloc(&d)) != 0) {
return (rv);
}
- if (((p = url->u_port) == NULL) || (strlen(p) == 0)) {
- p = nni_url_default_port(url->u_scheme);
- }
-
- if ((strlen(p) == 0) || (strlen(url->u_hostname) == 0)) {
+ if ((url->u_port == 0) || strlen(url->u_hostname) == 0 ||
+ strlen(url->u_hostname) >= sizeof(d->host)) {
// Dialer needs both a destination hostname and port.
tcp_dialer_free(d);
return (NNG_EADDRINVAL);
@@ -260,11 +255,8 @@ nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
d->af = NNG_AF_UNSPEC;
}
- if (((d->host = nng_strdup(url->u_hostname)) == NULL) ||
- ((d->port = nng_strdup(p)) == NULL)) {
- tcp_dialer_free(d);
- return (NNG_ENOMEM);
- }
+ snprintf(d->host, sizeof(d->host), "%s", url->u_hostname);
+ d->port = url->u_port;
*dp = (void *) d;
return (0);
diff --git a/src/core/url.c b/src/core/url.c
index c1318719..9bdcfd23 100644
--- a/src/core/url.c
+++ b/src/core/url.c
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
+#include "core/platform.h"
#include "url.h"
static uint8_t
@@ -234,22 +235,26 @@ url_canonify_uri(char **outp, const char *in)
static struct {
const char *scheme;
- const char *port;
+ uint16_t port;
} nni_url_default_ports[] = {
// This list is not exhaustive, but likely covers the main ones we
// care about. Feel free to add additional ones as use cases arise.
// Note also that we don't use "default" ports for SP protocols
// that have no "default" port, like tcp:// or tls+tcp://.
// clang-format off
- { "git", "9418" },
- { "gopher", "70" },
- { "http", "80" },
- { "https", "443" },
- { "ssh", "22" },
- { "telnet", "23" },
- { "ws", "80" },
- { "wss", "443" },
- { NULL, NULL },
+ { "git", 9418 },
+ { "gopher", 70 },
+ { "http", 80 },
+ { "https", 443 },
+ { "ssh", 22 },
+ { "telnet", 23 },
+ { "ws", 80 },
+ { "ws4", 80 },
+ { "ws6", 80 },
+ { "wss", 443 },
+ { "wss4", 443 },
+ { "wss6", 443 },
+ { NULL, 0 },
// clang-format on
};
@@ -274,6 +279,9 @@ static const char *nni_schemes[] = {
"wss",
"wss4",
"wss6",
+ "udp",
+ "udp4",
+ "udp6",
// we don't support these
"file",
"mailto",
@@ -284,10 +292,11 @@ static const char *nni_schemes[] = {
"telnet",
"irc",
"imap",
+ "imaps",
NULL,
};
-const char *
+uint16_t
nni_url_default_port(const char *scheme)
{
const char *s;
@@ -310,7 +319,7 @@ nni_url_default_port(const char *scheme)
break;
}
}
- return ("");
+ return (0);
}
// URLs usually follow the following format:
@@ -503,6 +512,11 @@ nni_url_parse(nni_url **urlp, const char *raw)
}
}
}
+ // hostname length check
+ if (len >= 256) {
+ rv = NNG_EADDRINVAL;
+ goto error;
+ }
if ((url->u_hostname = nni_alloc(len + 1)) == NULL) {
rv = NNG_ENOMEM;
goto error;
@@ -521,13 +535,12 @@ nni_url_parse(nni_url **urlp, const char *raw)
rv = NNG_EINVAL;
goto error;
}
- url->u_port = nni_strdup(s + 1);
+ rv = nni_get_port_by_name(s + 1, &url->u_port);
+ if (rv != 0) {
+ goto error;
+ }
} else {
- url->u_port = nni_strdup(nni_url_default_port(url->u_scheme));
- }
- if (url->u_port == NULL) {
- rv = NNG_ENOMEM;
- goto error;
+ url->u_port = nni_url_default_port(url->u_scheme);
}
*urlp = url;
@@ -546,7 +559,6 @@ nni_url_free(nni_url *url)
nni_strfree(url->u_userinfo);
nni_strfree(url->u_host);
nni_strfree(url->u_hostname);
- nni_strfree(url->u_port);
nni_strfree(url->u_path);
nni_strfree(url->u_query);
nni_strfree(url->u_fragment);
@@ -558,11 +570,11 @@ nni_url_free(nni_url *url)
int
nni_url_asprintf(char **str, const nni_url *url)
{
- const char *scheme = url->u_scheme;
- const char *port = url->u_port;
- const char *host = url->u_hostname;
- const char *hostob = "";
- const char *hostcb = "";
+ const char *scheme = url->u_scheme;
+ const char *host = url->u_hostname;
+ const char *hostob = "";
+ const char *hostcb = "";
+ bool do_port = true;
if ((strcmp(scheme, "ipc") == 0) || (strcmp(scheme, "inproc") == 0) ||
(strcmp(scheme, "unix") == 0) ||
@@ -570,11 +582,8 @@ nni_url_asprintf(char **str, const nni_url *url)
return (nni_asprintf(str, "%s://%s", scheme, url->u_path));
}
- if (port != NULL) {
- if ((strlen(port) == 0) ||
- (strcmp(nni_url_default_port(scheme), port) == 0)) {
- port = NULL;
- }
+ if (url->u_port == nni_url_default_port(scheme)) {
+ do_port = false;
}
if (strcmp(host, "*") == 0) {
host = "";
@@ -583,9 +592,14 @@ nni_url_asprintf(char **str, const nni_url *url)
hostob = "[";
hostcb = "]";
}
- return (nni_asprintf(str, "%s://%s%s%s%s%s%s", scheme, hostob, host,
- hostcb, port != NULL ? ":" : "", port != NULL ? port : "",
- url->u_requri != NULL ? url->u_requri : ""));
+ char portstr[8];
+ if (do_port) {
+ snprintf(portstr, sizeof(portstr), ":%u", url->u_port);
+ } else {
+ portstr[0] = 0;
+ }
+ return (nni_asprintf(str, "%s://%s%s%s%s%s", scheme, hostob, host,
+ hostcb, portstr, url->u_requri != NULL ? url->u_requri : ""));
}
// nni_url_asprintf_port is like nni_url_asprintf, but includes a port
@@ -594,12 +608,10 @@ nni_url_asprintf(char **str, const nni_url *url)
int
nni_url_asprintf_port(char **str, const nni_url *url, int port)
{
- char portstr[16];
nni_url myurl = *url;
if (port > 0) {
- (void) snprintf(portstr, sizeof(portstr), "%d", port);
- myurl.u_port = portstr;
+ myurl.u_port = (uint16_t) port;
}
return (nni_url_asprintf(str, &myurl));
}
@@ -618,7 +630,6 @@ nni_url_clone(nni_url **dstp, const nni_url *src)
URL_COPYSTR(dst->u_userinfo, src->u_userinfo) ||
URL_COPYSTR(dst->u_host, src->u_host) ||
URL_COPYSTR(dst->u_hostname, src->u_hostname) ||
- URL_COPYSTR(dst->u_port, src->u_port) ||
URL_COPYSTR(dst->u_requri, src->u_requri) ||
URL_COPYSTR(dst->u_path, src->u_path) ||
URL_COPYSTR(dst->u_query, src->u_query) ||
@@ -627,6 +638,7 @@ nni_url_clone(nni_url **dstp, const nni_url *src)
return (NNG_ENOMEM);
}
dst->u_scheme = src->u_scheme;
+ dst->u_port = src->u_port;
*dstp = dst;
return (0);
}
diff --git a/src/core/url.h b/src/core/url.h
index 1761f6fd..71a093d0 100644
--- a/src/core/url.h
+++ b/src/core/url.h
@@ -13,13 +13,13 @@
#include "core/defs.h"
-extern int nni_url_parse(nni_url **, const char *path);
-extern void nni_url_free(nni_url *);
-extern int nni_url_clone(nni_url **, const nni_url *);
-extern const char *nni_url_default_port(const char *);
-extern int nni_url_asprintf(char **, const nni_url *);
-extern int nni_url_asprintf_port(char **, const nni_url *, int);
-extern size_t nni_url_decode(uint8_t *, const char *, size_t);
-extern int nni_url_to_address(nng_sockaddr *, const nni_url *);
+extern int nni_url_parse(nni_url **, const char *path);
+extern void nni_url_free(nni_url *);
+extern int nni_url_clone(nni_url **, const nni_url *);
+extern uint16_t nni_url_default_port(const char *);
+extern int nni_url_asprintf(char **, const nni_url *);
+extern int nni_url_asprintf_port(char **, const nni_url *, int);
+extern size_t nni_url_decode(uint8_t *, const char *, size_t);
+extern int nni_url_to_address(nng_sockaddr *, const nni_url *);
#endif // CORE_URL_H
diff --git a/src/core/url_test.c b/src/core/url_test.c
index 232cabc8..b5114551 100644
--- a/src/core/url_test.c
+++ b/src/core/url_test.c
@@ -22,7 +22,7 @@ test_url_host(void)
NUTS_TRUE(strcmp(url->u_scheme, "http") == 0);
NUTS_TRUE(strcmp(url->u_host, "www.google.com") == 0);
NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0);
- NUTS_TRUE(strcmp(url->u_port, "80") == 0);
+ NUTS_TRUE(url->u_port == 80);
NUTS_TRUE(strcmp(url->u_path, "") == 0);
NUTS_TRUE(strcmp(url->u_requri, "") == 0);
NUTS_TRUE(url->u_query == NULL);
@@ -32,6 +32,20 @@ test_url_host(void)
}
void
+test_url_host_too_long(void)
+{
+ nng_url *url;
+ char buffer[512]; //
+
+ memset(buffer, 0, sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "http://");
+ for (size_t i = strlen(buffer); i < sizeof(buffer) - 1; i++) {
+ buffer[i] = 'a';
+ }
+ NUTS_FAIL(nng_url_parse(&url, buffer), NNG_EADDRINVAL);
+}
+
+void
test_url_host_port(void)
{
nng_url *url;
@@ -40,7 +54,7 @@ test_url_host_port(void)
NUTS_TRUE(strcmp(url->u_scheme, "http") == 0);
NUTS_TRUE(strcmp(url->u_host, "www.google.com:1234") == 0);
NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0);
- NUTS_TRUE(strcmp(url->u_port, "1234") == 0);
+ NUTS_TRUE(url->u_port == 1234);
NUTS_TRUE(strcmp(url->u_path, "") == 0);
NUTS_TRUE(strcmp(url->u_requri, "") == 0);
NUTS_TRUE(url->u_query == NULL);
@@ -59,7 +73,7 @@ test_url_host_port_path(void)
NUTS_TRUE(strcmp(url->u_scheme, "http") == 0);
NUTS_TRUE(strcmp(url->u_host, "www.google.com:1234") == 0);
NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0);
- NUTS_TRUE(strcmp(url->u_port, "1234") == 0);
+ NUTS_TRUE(url->u_port == 1234);
NUTS_TRUE(strcmp(url->u_path, "/somewhere") == 0);
NUTS_TRUE(strcmp(url->u_requri, "/somewhere") == 0);
NUTS_TRUE(url->u_userinfo == NULL);
@@ -79,7 +93,7 @@ test_url_user_info(void)
NUTS_MATCH(url->u_userinfo, "garrett");
NUTS_MATCH(url->u_host, "www.google.com:1234");
NUTS_MATCH(url->u_hostname, "www.google.com");
- NUTS_MATCH(url->u_port, "1234");
+ NUTS_TRUE(url->u_port == 1234);
NUTS_MATCH(url->u_path, "/somewhere");
NUTS_MATCH(url->u_requri, "/somewhere");
NUTS_NULL(url->u_query);
@@ -97,7 +111,7 @@ test_url_path_query_param(void)
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/somewhere");
NUTS_MATCH(url->u_query, "result=yes");
NUTS_MATCH(url->u_requri, "/somewhere?result=yes");
@@ -117,7 +131,7 @@ test_url_query_param_anchor(void)
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/somewhere");
NUTS_MATCH(url->u_query, "result=yes");
NUTS_MATCH(url->u_fragment, "chapter1");
@@ -136,7 +150,7 @@ test_url_path_anchor(void)
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/somewhere");
NUTS_MATCH(url->u_fragment, "chapter2");
NUTS_MATCH(url->u_requri, "/somewhere#chapter2");
@@ -155,7 +169,7 @@ test_url_anchor(void)
NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_fragment, "chapter3");
NUTS_MATCH(url->u_requri, "#chapter3");
NUTS_NULL(url->u_query);
@@ -173,7 +187,7 @@ test_url_query_param(void)
NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_query, "color=red");
NUTS_MATCH(url->u_requri, "?color=red");
NUTS_ASSERT(url != NULL);
@@ -191,7 +205,7 @@ test_url_v6_host(void)
NUTS_MATCH(url->u_host, "[::1]");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -208,7 +222,7 @@ test_url_v6_host_port(void)
NUTS_MATCH(url->u_host, "[::1]:29");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "29");
+ NUTS_TRUE(url->u_port == 29);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -225,7 +239,7 @@ test_url_v6_host_port_path(void)
NUTS_MATCH(url->u_host, "[::1]:29");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "/bottles");
- NUTS_MATCH(url->u_port, "29");
+ NUTS_TRUE(url->u_port == 29);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -242,7 +256,7 @@ test_url_tcp_port(void)
NUTS_MATCH(url->u_host, ":9876");
NUTS_MATCH(url->u_hostname, "");
NUTS_MATCH(url->u_path, "/");
- NUTS_MATCH(url->u_port, "9876");
+ NUTS_TRUE(url->u_port == 9876);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -260,7 +274,7 @@ test_url_bare_ws(void)
NUTS_MATCH(url->u_host, "");
NUTS_MATCH(url->u_hostname, "");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -277,7 +291,7 @@ test_url_ws_wildcard(void)
NUTS_MATCH(url->u_host, ":12345");
NUTS_MATCH(url->u_hostname, "");
NUTS_MATCH(url->u_path, "/foobar");
- NUTS_MATCH(url->u_port, "12345");
+ NUTS_TRUE(url->u_port == 12345);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_NULL(url->u_userinfo);
@@ -294,7 +308,7 @@ test_url_ssh(void)
NUTS_MATCH(url->u_host, "host.example.com");
NUTS_MATCH(url->u_hostname, "host.example.com");
NUTS_MATCH(url->u_path, "");
- NUTS_MATCH(url->u_port, "22");
+ NUTS_TRUE(url->u_port == 22);
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
NUTS_MATCH(url->u_userinfo, "user");
@@ -332,7 +346,7 @@ test_url_canonify(void)
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_hostname, "www.example.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/~garrett");
nng_url_free(url);
}
@@ -345,7 +359,7 @@ test_url_path_resolve(void)
nng_url_parse(&url, "http://www.x.com//abc/def/./x/..///./../y"));
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_hostname, "www.x.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/abc/y");
nng_url_free(url);
}
@@ -359,7 +373,7 @@ test_url_query_info_pass(void)
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_hostname, "www.x.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/");
NUTS_MATCH(url->u_query, "/abc/def/./x/.././../y");
nng_url_free(url);
@@ -383,7 +397,7 @@ test_url_good_utf8(void)
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_hostname, "www.x.com");
- NUTS_MATCH(url->u_port, "80");
+ NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_path, "/\xc2\xa2_cents");
nng_url_free(url);
}
@@ -446,6 +460,7 @@ test_url_decode(void)
NUTS_TESTS = {
{ "url host", test_url_host },
+ { "url host too long", test_url_host_too_long },
{ "url host port", test_url_host_port },
{ "url host port path", test_url_host_port_path },
{ "url user info", test_url_user_info },