diff options
| author | Garrett D'Amore <garrett@damore.org> | 2019-02-16 12:40:41 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2019-02-16 19:22:27 -0800 |
| commit | 60231f0600461a9593a8f876518874866df3387a (patch) | |
| tree | 1a91f0b65b1ad2d5b995a3db21639f4bf7032066 | |
| parent | 5cf750697624d4fd63cfe26921209d7c30e1a2d2 (diff) | |
| download | nng-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.adoc | 32 | ||||
| -rw-r--r-- | include/nng/nng.h | 11 | ||||
| -rw-r--r-- | src/core/url.c | 49 | ||||
| -rw-r--r-- | src/core/url.h | 2 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.h | 16 | ||||
| -rw-r--r-- | src/platform/windows/win_tcpconn.c | 2 | ||||
| -rw-r--r-- | src/platform/windows/win_tcpdial.c | 2 | ||||
| -rw-r--r-- | src/platform/windows/win_tcplisten.c | 16 | ||||
| -rw-r--r-- | src/supplemental/tcp/tcp.c | 41 | ||||
| -rw-r--r-- | src/transport/tcp/tcp.c | 38 | ||||
| -rw-r--r-- | src/transport/tls/tls.c | 36 |
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[] = { |
