aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2019-02-16 12:40:41 -0800
committerGarrett D'Amore <garrett@damore.org>2019-02-16 19:22:27 -0800
commit60231f0600461a9593a8f876518874866df3387a (patch)
tree1a91f0b65b1ad2d5b995a3db21639f4bf7032066
parent5cf750697624d4fd63cfe26921209d7c30e1a2d2 (diff)
downloadnng-60231f0600461a9593a8f876518874866df3387a.tar.gz
nng-60231f0600461a9593a8f876518874866df3387a.tar.bz2
nng-60231f0600461a9593a8f876518874866df3387a.zip
fixes #879 Desire NNG_OPT_TCP_BOUND_PORT
We also have made some support changes, including new APIs for printing URLs, and some improvements to the NNG_OPT_URL to make use of this new property.
-rw-r--r--docs/man/nng_tcp_options.5.adoc32
-rw-r--r--include/nng/nng.h11
-rw-r--r--src/core/url.c49
-rw-r--r--src/core/url.h2
-rw-r--r--src/platform/windows/win_tcp.h16
-rw-r--r--src/platform/windows/win_tcpconn.c2
-rw-r--r--src/platform/windows/win_tcpdial.c2
-rw-r--r--src/platform/windows/win_tcplisten.c16
-rw-r--r--src/supplemental/tcp/tcp.c41
-rw-r--r--src/transport/tcp/tcp.c38
-rw-r--r--src/transport/tls/tls.c36
11 files changed, 170 insertions, 75 deletions
diff --git a/docs/man/nng_tcp_options.5.adoc b/docs/man/nng_tcp_options.5.adoc
index f16af5ea..862128ec 100644
--- a/docs/man/nng_tcp_options.5.adoc
+++ b/docs/man/nng_tcp_options.5.adoc
@@ -45,6 +45,18 @@ TCP/IP communications.
=== TCP Options
+[[NNG_OPT_TCP_BOUND_PORT]]
+((`NNG_OPT_TCP_BOUND_PORT`))::
+(`int`)
+This option is available on listeners, after the listern has bound to
+a port, and provides the port bound to in native byte order.
+This is most useful when using a listener with an ephemeral port
+(configured by using port 0 at configuration time), as it allows
+the caller to determine the actual ephemeral port that was chosen by the
+system.
+While the value is of type `int`, it will be a legal TCP port number, that
+is a value between 1 and 65535, inclusive.
+
[[NNG_OPT_TCP_NODELAY]]
((`NNG_OPT_TCP_NODELAY`))::
(`bool`)
@@ -94,17 +106,17 @@ middleware from being expiring due to lack of activity.
Generally, the following option values are also available for TCP objects,
when appropriate for the context:
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>>
+* xref:nng_options.5.adoc#NNG_OPT_LOCADDR[`NNG_OPT_LOCADDR`]
+* xref:nng_options.5.adoc#NNG_OPT_REMADDR[`NNG_OPT_REMADDR`]
== SEE ALSO
[.text-left]
-<<nng_tcp_dialer_getopt.3tcp#,nng_tcp_dialer_getopt(3tcp)>>,
-<<nng_tcp_dialer_setopt.3tcp#,nng_tcp_dialer_setopt(3tcp)>>,
-<<nng_tcp_getopt.3tcp#,nng_tcp_getopt(3tcp)>>,
-<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt(3tcp)>>,
-<<nng_tcp_listener_setopt.3tcp#,nng_tcp_listener_setopt(3tcp)>>,
-<<nng_tcp_setopt.3tcp#,nng_tcp_setopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>
-<<nng.7#,nng(7)>>
+xref:nng_tcp_dialer_getopt.3tcp.adoc[nng_tcp_dialer_getopt(3tcp)],
+xref:nng_tcp_dialer_setopt.3tcp.adoc[nng_tcp_dialer_setopt(3tcp)],
+xref:nng_tcp_getopt.3tcp.adoc[nng_tcp_getopt(3tcp)],
+xref:nng_tcp_listener_getopt.3tcp.adoc[nng_tcp_listener_getopt(3tcp)],
+xref:nng_tcp_listener_setopt.3tcp.adoc[nng_tcp_listener_setopt(3tcp)],
+xref:nng_tcp_setopt.3tcp.adoc[nng_tcp_setopt(3tcp)],
+xref:nng_options.5.adoc[nng_options(5)]
+xref:nng.7.adoc[nng(7)]
diff --git a/include/nng/nng.h b/include/nng/nng.h
index eb50599a..4c29e476 100644
--- a/include/nng/nng.h
+++ b/include/nng/nng.h
@@ -754,6 +754,14 @@ enum nng_flag_enum {
// state current). This is a boolean.
#define NNG_OPT_TCP_KEEPALIVE "tcp-keepalive"
+// Local TCP port number. This is used on a listener, and is intended
+// to be used after starting the listener in combination with a wildcard
+// (0) local port. This determines the actual ephemeral port that was
+// selected and bound. The value is provied as an int, but only the
+// low order 16 bits will be set. This is provided in native byte order,
+// which makes it more convienent than using the NNG_OPT_LOCADDR option.
+#define NNG_OPT_TCP_BOUND_PORT "tcp-bound-port"
+
// IPC options. These will largely vary depending on the platform,
// as POSIX systems have very different options than Windows.
@@ -1115,7 +1123,8 @@ NNG_DECL int nng_stream_listener_get_addr(
nng_stream_listener *, const char *, nng_sockaddr *);
NNG_DECL int nng_stream_listener_set_bool(
nng_stream_listener *, const char *, bool);
-NNG_DECL int nng_stream_listener_set_int(nng_stream_listener *, const char *, int);
+NNG_DECL int nng_stream_listener_set_int(
+ nng_stream_listener *, const char *, int);
NNG_DECL int nng_stream_listener_set_ms(
nng_stream_listener *, const char *, nng_duration);
NNG_DECL int nng_stream_listener_set_size(
diff --git a/src/core/url.c b/src/core/url.c
index b2cf77f8..2f1e3a78 100644
--- a/src/core/url.c
+++ b/src/core/url.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 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
@@ -491,6 +491,53 @@ 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 = "";
+
+ if ((strcmp(scheme, "ipc") == 0) || (strcmp(scheme, "inproc") == 0)) {
+ 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 (strcmp(host, "*") == 0) {
+ host = "";
+ }
+ if (strchr(host, ':') != 0) {
+ 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 : ""));
+}
+
+// nni_url_asprintf_port is like nni_url_asprintf, but includes a port
+// override. If non-zero, this port number replaces the port number
+// in the port string.
+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;
+ }
+ return (nni_url_asprintf(str, &myurl));
+}
+
#define URL_COPYSTR(d, s) ((s != NULL) && ((d = nni_strdup(s)) == NULL))
int
diff --git a/src/core/url.h b/src/core/url.h
index 2358f6ba..afb8a882 100644
--- a/src/core/url.h
+++ b/src/core/url.h
@@ -17,5 +17,7 @@ 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);
#endif // CORE_URL_H
diff --git a/src/platform/windows/win_tcp.h b/src/platform/windows/win_tcp.h
index b37b2353..e54f853c 100644
--- a/src/platform/windows/win_tcp.h
+++ b/src/platform/windows/win_tcp.h
@@ -38,20 +38,6 @@ struct nni_tcp_conn {
nni_cv cv;
};
-struct nni_tcp_listener {
- SOCKET s;
- nni_list aios;
- bool closed;
- bool started;
- bool nodelay; // initial value for child conns
- bool keepalive; // initial value for child conns
- LPFN_ACCEPTEX acceptex;
- LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs;
- SOCKADDR_STORAGE ss;
- nni_mtx mtx;
- nni_reap_item reap;
-};
-
-extern int nni_win_tcp_conn_init(nni_tcp_conn **, SOCKET);
+extern int nni_win_tcp_init(nni_tcp_conn **, SOCKET);
#endif // NNG_PLATFORM_WIN_WINTCP_H
diff --git a/src/platform/windows/win_tcpconn.c b/src/platform/windows/win_tcpconn.c
index c77bbc72..429c5a5d 100644
--- a/src/platform/windows/win_tcpconn.c
+++ b/src/platform/windows/win_tcpconn.c
@@ -425,7 +425,7 @@ tcp_free(void *arg)
}
int
-nni_win_tcp_conn_init(nni_tcp_conn **connp, SOCKET s)
+nni_win_tcp_init(nni_tcp_conn **connp, SOCKET s)
{
nni_tcp_conn *c;
int rv;
diff --git a/src/platform/windows/win_tcpdial.c b/src/platform/windows/win_tcpdial.c
index 6bb3d92a..e295bd8d 100644
--- a/src/platform/windows/win_tcpdial.c
+++ b/src/platform/windows/win_tcpdial.c
@@ -193,7 +193,7 @@ nni_tcp_dial(nni_tcp_dialer *d, nni_aio *aio)
return;
}
- if ((rv = nni_win_tcp_conn_init(&c, s)) != 0) {
+ if ((rv = nni_win_tcp_init(&c, s)) != 0) {
nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c
index e98a0c37..18e552a6 100644
--- a/src/platform/windows/win_tcplisten.c
+++ b/src/platform/windows/win_tcplisten.c
@@ -17,6 +17,20 @@
#include "win_tcp.h"
+struct nni_tcp_listener {
+ SOCKET s;
+ nni_list aios;
+ bool closed;
+ bool started;
+ bool nodelay; // initial value for child conns
+ bool keepalive; // initial value for child conns
+ LPFN_ACCEPTEX acceptex;
+ LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs;
+ SOCKADDR_STORAGE ss;
+ nni_mtx mtx;
+ nni_reap_item reap;
+};
+
// tcp_listener_funcs looks up function pointers we need for advanced accept
// functionality on Windows. Windows is weird.
static int
@@ -296,7 +310,7 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio)
nni_aio_finish_error(aio, rv);
return;
}
- if ((rv = nni_win_tcp_conn_init(&c, s)) != 0) {
+ if ((rv = nni_win_tcp_init(&c, s)) != 0) {
nni_mtx_unlock(&l->mtx);
closesocket(s);
nni_aio_finish_error(aio, rv);
diff --git a/src/supplemental/tcp/tcp.c b/src/supplemental/tcp/tcp.c
index 3ec396b8..21922ef6 100644
--- a/src/supplemental/tcp/tcp.c
+++ b/src/supplemental/tcp/tcp.c
@@ -327,10 +327,51 @@ tcp_listener_accept(void *arg, nng_aio *aio)
}
static int
+tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ tcp_listener *l = arg;
+ int rv;
+ nng_sockaddr sa;
+ size_t sz;
+ int port;
+ uint8_t * paddr;
+
+ sz = sizeof(sa);
+ rv = nni_tcp_listener_getopt(
+ l->l, NNG_OPT_LOCADDR, &sa, &sz, NNI_TYPE_SOCKADDR);
+ if (rv != 0) {
+ return (rv);
+ }
+
+ switch (sa.s_family) {
+ case NNG_AF_INET:
+ paddr = (void *) &sa.s_in.sa_port;
+ break;
+
+ case NNG_AF_INET6:
+ paddr = (void *) &sa.s_in.sa_port;
+ break;
+ default:
+ paddr = NULL;
+ break;
+ }
+
+ if (paddr == NULL) {
+ return (NNG_ESTATE);
+ }
+
+ NNI_GET16(paddr, port);
+ return (nni_copyout_int(port, buf, szp, t));
+}
+
+static int
tcp_listener_getx(
void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
tcp_listener *l = arg;
+ if (strcmp(name, NNG_OPT_TCP_BOUND_PORT) == 0) {
+ return (tcp_listener_get_port(l, buf, szp, t));
+ }
return (nni_tcp_listener_getopt(l->l, name, buf, szp, t));
}
diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c
index 3d757ee7..f8b1ce54 100644
--- a/src/transport/tcp/tcp.c
+++ b/src/transport/tcp/tcp.c
@@ -57,7 +57,7 @@ struct tcptran_ep {
uint16_t proto;
size_t rcvmax;
bool fini;
- nni_url * url;
+ nng_url * url;
const char * host; // for dialers
nng_sockaddr src;
nni_list pipes;
@@ -680,7 +680,7 @@ tcptran_ep_close(void *arg)
// The special handling of this URL format is quite honestly an historical
// mistake, which we would remove if we could.
static int
-tcptran_url_parse_source(nni_url *url, nng_sockaddr *sa, const nni_url *surl)
+tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl)
{
int af;
char * semi;
@@ -736,13 +736,13 @@ tcptran_url_parse_source(nni_url *url, nng_sockaddr *sa, const nni_url *surl)
}
static int
-tcptran_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
+tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer)
{
tcptran_ep * ep;
int rv;
nng_sockaddr srcsa;
nni_sock * sock = nni_dialer_sock(ndialer);
- nni_url myurl;
+ nng_url myurl;
// Check for invalid URL components.
if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) {
@@ -783,7 +783,7 @@ tcptran_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
return (0);
}
static int
-tcptran_listener_init(void **lp, nni_url *url, nni_listener *nlistener)
+tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener)
{
tcptran_ep *ep;
int rv;
@@ -847,28 +847,20 @@ static int
tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t)
{
tcptran_ep *ep = arg;
+ char * s;
+ int rv;
+ int port = 0;
if (ep->listener != NULL) {
- char ustr[128];
- char ipstr[48]; // max for IPv6 addresses including []
- char portstr[6]; // max for 16-bit port
- nng_sockaddr sa;
- int rv;
- rv = nng_stream_listener_get_addr(
- ep->listener, NNG_OPT_LOCADDR, &sa);
- if (rv != 0) {
- return (rv);
- }
-
- nni_ntop(&sa, ipstr, portstr);
- snprintf(ustr, sizeof(ustr),
- sa.s_family == NNG_AF_INET6 ? "tcp://[%s]:%s"
- : "tcp://%s:%s",
- ipstr, portstr);
- return (nni_copyout_str(ustr, v, szp, t));
+ (void) nng_stream_listener_get_int(
+ ep->listener, NNG_OPT_TCP_BOUND_PORT, &port);
}
- return (nni_copyout_str(ep->url->u_rawurl, v, szp, t));
+ if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) {
+ rv = nni_copyout_str(s, v, szp, t);
+ nni_strfree(s);
+ }
+ return (rv);
}
static int
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c
index d68cb8b1..8b02702f 100644
--- a/src/transport/tls/tls.c
+++ b/src/transport/tls/tls.c
@@ -907,7 +907,7 @@ tlstran_ep_accept(void *arg, nni_aio *aio)
}
static int
-tlstran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t)
+tlstran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_type t)
{
tlstran_ep *ep = arg;
size_t val;
@@ -921,7 +921,7 @@ tlstran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t)
}
static int
-tlstran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t)
+tlstran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_type t)
{
tlstran_ep *ep = arg;
int rv;
@@ -932,30 +932,22 @@ tlstran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t)
}
static int
-tlstran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t)
+tlstran_ep_get_url(void *arg, void *v, size_t *szp, nni_type t)
{
- tlstran_ep * ep = arg;
- char ustr[128];
- char ipstr[48]; // max for IPv6 addresses including []
- char portstr[6]; // max for 16-bit port
- nng_sockaddr sa;
- size_t sz = sizeof(sa);
- int rv;
+ tlstran_ep *ep = arg;
+ char * s;
+ int rv;
+ int port = 0;
- if (ep->dialer != NULL) {
- return (nni_copyout_str(ep->url->u_rawurl, v, szp, t));
+ if (ep->listener != NULL) {
+ (void) nng_stream_listener_get_int(
+ ep->listener, NNG_OPT_TCP_BOUND_PORT, &port);
}
- rv = nni_stream_listener_getx(
- ep->listener, NNG_OPT_LOCADDR, &sa, &sz, NNI_TYPE_SOCKADDR);
- if (rv != 0) {
- return (rv);
+ if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) {
+ rv = nni_copyout_str(s, v, szp, t);
+ nni_strfree(s);
}
-
- nni_mtx_lock(&ep->mtx);
- nni_ntop(&sa, ipstr, portstr);
- nni_mtx_unlock(&ep->mtx);
- snprintf(ustr, sizeof(ustr), "tls+tcp://%s:%s", ipstr, portstr);
- return (nni_copyout_str(ustr, v, szp, t));
+ return (rv);
}
static const nni_option tlstran_pipe_opts[] = {