diff --git a/docs/ref/api/url.md b/docs/ref/api/url.md index db9f3be23..62cf66fd3 100644 --- a/docs/ref/api/url.md +++ b/docs/ref/api/url.md @@ -20,28 +20,52 @@ typedef struct nng_url { char *u_query; char *u_fragment; } nng_url; + +const char *nng_url_scheme(const nng_url *url); +const char *nng_url_userinfo(const nng_url *url); +const char *nng_url_hostname(const nng_url *url); +uint16_t nng_url_port(const nng_url *url); +const char *nng_url_path(const nng_url *url); +const char *nng_url_query(const nng_url *url); +const char *nng_url_fragment(const nng_url *url): ``` ### URL Fields -Applications may access individual fields, but must not free or -alter them, as the underlying memory is managed by the library. +The {{i:`nng_url_scheme`}} function returns the scheme, +without any colons or slashes. Values are lower case +strings, like "http" or "inproc" or "tls+tcp4". + +The {{i:`nng_url_userinfo`}} function returns a string corresponding +to the user component of a URL (the part before any `@` sign) if such +a component is present, otherwise it returns `NULL`. + +The {{i:`nng_url_hostname`}} function returns a hostname (which might +actually be an IP address) from the URL, if the URL corresponds to a scheme +that uses hostnames (like "http" or "tcp"). If the URL does not (for example +"inproc" or "ipc" URLs) then it returns `NULL`. -Additionally applications must not depend on the size of this structure. -Obtain one using `nng_parse_url`. +The {{i:`nng_url_port`}} function returns the TCP or UDP port number if the URL +corresponds to a protocol based on TCP or UDP. It returns zero otherwise. +Note that the port number might not have been explicitly specified in the URL. +For example, the port number associated with "http://www.example.com" is 80, +which is the standard port number for HTTP. + +> [!TIP] +> The port number returned by this is in the native machine byte order. +> Be careful when using this with other network-oriented APIs. -The fields of an `nng_url` object are as follows: +The {{i:`nng_url_path`}} function returns the path component of the URL. +This will always be non-`NULL`, but it may be empty. -- `u_scheme`: The URL scheme, such as "http" or "inproc". Always lower case. This will never be `NULL`. -- `u_userinfo`: This username and password if supplied in the URL string. Will be `NULL` when not present. -- `u_hostname`: The name of the host, and may be the empty string in some cases. -- `u_port`: The port. May be zero if irrelevant or not specified. -- `u_path`: The path, typically used with HTTP or WebSockets. Will be empty string if not specified. -- `u_query`: The query info (typically following `?` in the URL.) Will be `NULL` if not present. -- `u_fragment`: This is used for specifying an anchor, the part after `#` in a URL. Will be `NULL` if not present. +The {{i:`nng_url_query`}} and {{i:`nng_url_fragment`}} functions return +the query-information (the part following a '?') and fragment +(the part following a '#') if those components are present, or `NULL` +if they are not. The returned string will not include the leading '?' or '#' +characters. -> [!NOTE] -> Other fields may also be present, but only those documented here are safe for application use. +Note that any strings returned by these functions are only valid until +_url_ is freed with [`nng_url_free`]. ## Format a URL diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index ddad9ff72..1d9032152 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -166,14 +166,21 @@ The use of `*` to act as a wild card meaning all local interface addresses is removed. The empty string already performs this function, and unlike `*` is RFC compliant. -## URL Structure Members - -The details of [`nng_url`] have changed as follows: - -- `u_port` is no longer a string, but a `uint16_t` -- `u_scheme` is a `const char *` +## URL Structure Changes + +The details of [`nng_url`] have changed significantly, and direct +access of the structure is no longer permitted. Intead new +accessors functions are provided: + +- `u_scheme` is replaced by [`nng_url_scheme`]. +- `u_port` is replaced by [`nng_url_port`], but this returns a `uint16_t`. +- `u_hostname` is replaced by [`nng_url_hostname`]. +- `u_path` is replaced by [`nng_url_path`]. +- `u_query` is replaced by [`nng_url_query`]. +- `u_fragment` is replaced by [`nng_url_fragment`]. +- `u_userinfo` is replaced by [`nng_url_userinfo`]. - `u_requri` is removed - it can be easily formulated from the other fields. -- `u_host` is removed - use `u_hostname` and `u_port` to construct if needed +- `u_host` is removed - use [`nng_url_hostname`] and [`nng_url_port`] to construct if needed - `u_rawurl` is removed - a "cooked" URL can be obtained from the new [`nng_url_sprintf`] function. {{#include ../xref.md}} diff --git a/docs/ref/xref.md b/docs/ref/xref.md index 728628a48..d36f96e8c 100644 --- a/docs/ref/xref.md +++ b/docs/ref/xref.md @@ -96,6 +96,8 @@ [`nng_aio_set_output`]: /TODO.md [`nng_send`]: /TODO.md [`nng_recv`]: /TODO.md +[`nng_listener_get_url`]: /TODO.md +[`nng_dialer_get_url`]: /TODO.md diff --git a/include/nng/nng.h b/include/nng/nng.h index 47260b8d8..bd6b526d6 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -113,6 +113,9 @@ typedef struct nng_msg nng_msg; typedef struct nng_stat nng_stat; typedef struct nng_aio nng_aio; +// URL structure. +typedef struct nng_url nng_url; + // For some transports, we need TLS configuration, including certificates // and so forth. A TLS configuration cannot be changed once it is in use. typedef struct nng_tls_config nng_tls_config; @@ -270,6 +273,11 @@ NNG_DECL int nng_socket_raw(nng_socket id, bool *rawp); NNG_DECL const char *nng_str_sockaddr( const nng_sockaddr *sa, char *buf, size_t bufsz); +// Obtain a port number (for NNG_AF_INET and NNG_AF_INET6this will be 16 bits +// maximum, but other address familiies may have larger port numbers.) For +// address that don't have the concept of port numbers, zero will be returned. +uint32_t nng_sockaddr_port(const nng_sockaddr *sa); + // Arguably the pipe callback functions could be handled as an option, // but with the need to specify an argument, we find it best to unify // this as a separate function to pass in the argument and the callback. @@ -357,6 +365,7 @@ NNG_DECL int nng_dialer_get_ptr(nng_dialer, const char *, void **); NNG_DECL int nng_dialer_get_ms(nng_dialer, const char *, nng_duration *); NNG_DECL int nng_dialer_get_addr(nng_dialer, const char *, nng_sockaddr *); NNG_DECL int nng_dialer_get_tls(nng_dialer, nng_tls_config **); +NNG_DECL int nng_dialer_get_url(nng_dialer id, const nng_url **urlp); NNG_DECL int nng_listener_set_bool(nng_listener, const char *, bool); NNG_DECL int nng_listener_set_int(nng_listener, const char *, int); @@ -368,6 +377,7 @@ NNG_DECL int nng_listener_set_ms(nng_listener, const char *, nng_duration); NNG_DECL int nng_listener_set_addr( nng_listener, const char *, const nng_sockaddr *); NNG_DECL int nng_listener_set_tls(nng_listener, nng_tls_config *); +NNG_DECL int nng_listener_get_url(nng_listener id, const nng_url **urlp); NNG_DECL int nng_listener_get_bool(nng_listener, const char *, bool *); NNG_DECL int nng_listener_get_int(nng_listener, const char *, int *); @@ -1079,24 +1089,6 @@ enum nng_errno_enum { NNG_ETRANERR = 0x20000000 }; -// URL support. We frequently want to process a URL, and these methods -// give us a convenient way of doing so. - -typedef struct nng_url { - char *u_rawurl; // never NULL - const char *u_scheme; // never NULL - const char *u_userinfo; // will be NULL if not specified - char *u_hostname; // name only, will be "" if not specified - uint16_t u_port; // port, may be zero for schemes that do not use - 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 - // these members are private - char *u_buffer; - size_t u_bufsz; - char u_static[NNG_MAXADDRLEN]; // Most URLs fit within this -} nng_url; - // nng_url_parse parses a URL string into a structured form. // Note that the u_port member will be filled out with a numeric // port if one isn't specified and a default port is appropriate for @@ -1114,6 +1106,27 @@ NNG_DECL int nng_url_clone(nng_url **, const nng_url *); // snprintf. NNG_DECL int nng_url_sprintf(char *, size_t, const nng_url *); +NNG_DECL const char *nng_url_scheme(const nng_url *); + +// Port (such as UDP or TCP) for a URL, can be zero for ports are not used by +// the scheme. +NNG_DECL uint32_t nng_url_port(const nng_url *); + +// hostname part of URL, can be NULL if irerelvant to scheme +const char *nng_url_hostname(const nng_url *); + +// user info part (thing before '@') of URL, NULL if absent. +const char *nng_url_userinfo(const nng_url *); + +// path portion of URL, will always non-NULL, but may be empty. +const char *nng_url_path(const nng_url *); + +// query info part of URL, not including '?, NULL if absent' +const char *nng_url_query(const nng_url *); + +// fragment part of URL, not including '#', NULL if absent. +const char *nng_url_fragment(const nng_url *); + // nng_version returns the library version as a human readable string. NNG_DECL const char *nng_version(void); diff --git a/src/core/defs.h b/src/core/defs.h index 6d6e3ff6f..46a32ef59 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -36,7 +36,6 @@ // Internal code should use these names when possible. typedef nng_msg nni_msg; typedef nng_sockaddr nni_sockaddr; -typedef nng_url nni_url; typedef nng_iov nni_iov; typedef nng_aio nni_aio; diff --git a/src/core/dialer.c b/src/core/dialer.c index d39eb99a5..3cd6620f8 100644 --- a/src/core/dialer.c +++ b/src/core/dialer.c @@ -9,6 +9,7 @@ // found online at https://opensource.org/licenses/MIT. // +#include "core/defs.h" #include "core/nng_impl.h" #include "sockimpl.h" @@ -42,7 +43,7 @@ nni_dialer_destroy(nni_dialer *d) d->d_ops.d_fini(d->d_data); } nni_mtx_fini(&d->d_mtx); - nni_url_free(d->d_url); + nni_url_fini(&d->d_url); NNI_FREE_STRUCT(d); } @@ -214,22 +215,20 @@ nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *url_str) nni_sp_tran *tran; nni_dialer *d; int rv; - nni_url *url; - if ((rv = nni_url_parse(&url, url_str)) != 0) { - return (rv); + if ((d = NNI_ALLOC_STRUCT(d)) == NULL) { + return (NNG_ENOMEM); } - if (((tran = nni_sp_tran_find(url)) == NULL) || + if (((tran = nni_sp_tran_find(url_str)) == NULL) || (tran->tran_dialer == NULL)) { - nni_url_free(url); + NNI_FREE_STRUCT(d); return (NNG_ENOTSUP); } - - if ((d = NNI_ALLOC_STRUCT(d)) == NULL) { - nni_url_free(url); - return (NNG_ENOMEM); + if ((rv = nni_url_parse_inline(&d->d_url, url_str)) != 0) { + nni_url_fini(&d->d_url); + NNI_FREE_STRUCT(d); + return (rv); } - d->d_url = url; d->d_closed = false; d->d_data = NULL; d->d_ref = 1; @@ -258,7 +257,8 @@ nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *url_str) dialer_stats_init(d); #endif - if ((rv != 0) || ((rv = d->d_ops.d_init(&d->d_data, url, d)) != 0) || + if ((rv != 0) || + ((rv = d->d_ops.d_init(&d->d_data, &d->d_url, d)) != 0) || ((rv = nni_sock_add_dialer(s, d)) != 0)) { nni_mtx_lock(&dialers_lk); nni_id_remove(&dialers, d->d_id); @@ -538,7 +538,7 @@ nni_dialer_getopt( // override. This allows the URL to be created with wildcards, // that are resolved later. if (strcmp(name, NNG_OPT_URL) == 0) { - return (nni_copyout_str(d->d_url->u_rawurl, valp, szp, t)); + return (nni_copyout_str(d->d_url.u_rawurl, valp, szp, t)); } return (nni_sock_getopt(d->d_sock, name, valp, szp, t)); @@ -562,6 +562,12 @@ nni_dialer_set_tls(nni_dialer *d, nng_tls_config *cfg) return (d->d_ops.d_set_tls(d->d_data, cfg)); } +nng_url * +nni_dialer_url(nni_dialer *d) +{ + return (&d->d_url); +} + void nni_dialer_add_stat(nni_dialer *d, nni_stat_item *item) { diff --git a/src/core/dialer.h b/src/core/dialer.h index 97a24e4a7..19b39cf29 100644 --- a/src/core/dialer.h +++ b/src/core/dialer.h @@ -25,9 +25,10 @@ extern int nni_dialer_setopt( nni_dialer *, const char *, const void *, size_t, nni_type); extern int nni_dialer_getopt( nni_dialer *, const char *, void *, size_t *, nni_type); -extern int nni_dialer_get_tls(nni_dialer *, nng_tls_config **); -extern int nni_dialer_set_tls(nni_dialer *, nng_tls_config *); -extern void nni_dialer_add_stat(nni_dialer *, nni_stat_item *); -extern void nni_dialer_bump_error(nni_dialer *, int); +extern int nni_dialer_get_tls(nni_dialer *, nng_tls_config **); +extern int nni_dialer_set_tls(nni_dialer *, nng_tls_config *); +extern nng_url *nni_dialer_url(nni_dialer *); +extern void nni_dialer_add_stat(nni_dialer *, nni_stat_item *); +extern void nni_dialer_bump_error(nni_dialer *, int); #endif // CORE_DIALER_H diff --git a/src/core/listener.c b/src/core/listener.c index e1cdf833b..3c2d7bf02 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -43,7 +43,7 @@ nni_listener_destroy(nni_listener *l) if (l->l_data != NULL) { l->l_ops.l_fini(l->l_data); } - nni_url_free(l->l_url); + nni_url_fini(&l->l_url); NNI_FREE_STRUCT(l); } @@ -203,22 +203,20 @@ nni_listener_create(nni_listener **lp, nni_sock *s, const char *url_str) nni_sp_tran *tran; nni_listener *l; int rv; - nni_url *url; - if ((rv = nni_url_parse(&url, url_str)) != 0) { - return (rv); + if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { + return (NNG_ENOMEM); } - if (((tran = nni_sp_tran_find(url)) == NULL) || + if (((tran = nni_sp_tran_find(url_str)) == NULL) || (tran->tran_listener == NULL)) { - nni_url_free(url); + NNI_FREE_STRUCT(l); return (NNG_ENOTSUP); } - - if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { - nni_url_free(url); - return (NNG_ENOMEM); + if ((rv = nni_url_parse_inline(&l->l_url, url_str)) != 0) { + nni_url_fini(&l->l_url); + NNI_FREE_STRUCT(l); + return (rv); } - l->l_url = url; l->l_closed = false; l->l_data = NULL; l->l_ref = 1; @@ -245,7 +243,8 @@ nni_listener_create(nni_listener **lp, nni_sock *s, const char *url_str) listener_stats_init(l); #endif - if ((rv != 0) || ((rv = l->l_ops.l_init(&l->l_data, url, l)) != 0) || + if ((rv != 0) || + ((rv = l->l_ops.l_init(&l->l_data, &l->l_url, l)) != 0) || ((rv = nni_sock_add_listener(s, l)) != 0)) { nni_mtx_lock(&listeners_lk); nni_id_remove(&listeners, l->l_id); @@ -385,16 +384,16 @@ listener_accept_start(nni_listener *l) int nni_listener_start(nni_listener *l, int flags) { - int rv; - char *url; - size_t sz; + int rv; + const nng_url *url; + char us[NNG_MAXADDRSTRLEN]; NNI_ARG_UNUSED(flags); if (nni_atomic_flag_test_and_set(&l->l_started)) { return (NNG_ESTATE); } - if ((rv = l->l_ops.l_bind(l->l_data)) != 0) { + if ((rv = l->l_ops.l_bind(l->l_data, &l->l_url)) != 0) { nng_log_warn("NNG-BIND-FAIL", "Failed binding socket<%u>: %s", nni_sock_id(l->l_sock), nng_strerror(rv)); nni_listener_bump_error(l, rv); @@ -402,12 +401,10 @@ nni_listener_start(nni_listener *l, int flags) return (rv); } // collect the URL which may have changed (e.g. binding to port 0) - sz = sizeof(url); - (void) (nni_listener_getopt( - l, NNG_OPT_URL, &url, &sz, NNI_TYPE_STRING)); + url = nni_listener_url(l); + nng_url_sprintf(us, sizeof(us), url); nng_log_info("NNG-LISTEN", "Starting listener for socket<%u> on %s", - nni_sock_id(l->l_sock), url); - nni_strfree(url); + nni_sock_id(l->l_sock), us); listener_accept_start(l); @@ -486,7 +483,7 @@ nni_listener_getopt( // override. This allows the URL to be created with wildcards, // that are resolved later. if (strcmp(name, NNG_OPT_URL) == 0) { - return (nni_copyout_str(l->l_url->u_rawurl, val, szp, t)); + return (nni_copyout_str(l->l_url.u_rawurl, val, szp, t)); } return (nni_sock_getopt(l->l_sock, name, val, szp, t)); @@ -510,6 +507,12 @@ nni_listener_set_tls(nni_listener *l, nng_tls_config *cfg) return (l->l_ops.l_set_tls(l->l_data, cfg)); } +nng_url * +nni_listener_url(nni_listener *l) +{ + return (&l->l_url); +} + void nni_listener_add_stat(nni_listener *l, nni_stat_item *item) { diff --git a/src/core/listener.h b/src/core/listener.h index 67c80be02..74ca0a0bd 100644 --- a/src/core/listener.h +++ b/src/core/listener.h @@ -25,9 +25,10 @@ extern int nni_listener_setopt( nni_listener *, const char *, const void *, size_t, nni_type); extern int nni_listener_getopt( nni_listener *, const char *, void *, size_t *, nni_type); -extern int nni_listener_get_tls(nni_listener *, nng_tls_config **); -extern int nni_listener_set_tls(nni_listener *, nng_tls_config *); -extern void nni_listener_add_stat(nni_listener *, nni_stat_item *); -extern void nni_listener_bump_error(nni_listener *, int); +extern int nni_listener_get_tls(nni_listener *, nng_tls_config **); +extern int nni_listener_set_tls(nni_listener *, nng_tls_config *); +extern nng_url *nni_listener_url(nni_listener *); +extern void nni_listener_add_stat(nni_listener *, nni_stat_item *); +extern void nni_listener_bump_error(nni_listener *, int); #endif // CORE_LISTENER_H diff --git a/src/core/platform.h b/src/core/platform.h index 783cc9fcd..0249e2a02 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -353,7 +353,7 @@ 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 *); +extern int nni_get_port_by_name(const char *, uint32_t *); // // IPC (UNIX Domain Sockets & Named Pipes) Support. diff --git a/src/core/sockaddr.c b/src/core/sockaddr.c index 50fd42141..d55db1565 100644 --- a/src/core/sockaddr.c +++ b/src/core/sockaddr.c @@ -163,3 +163,21 @@ nng_str_sockaddr(const nng_sockaddr *sa, char *buf, size_t bufsz) return ("unknown"); } } + +uint32_t +nng_sockaddr_port(const nng_sockaddr *sa) +{ + uint16_t port16; + switch (sa->s_family) { + case NNG_AF_INET: + NNI_GET16(&sa->s_in.sa_port, port16); + return (port16); + case NNG_AF_INET6: + NNI_GET16(&sa->s_in6.sa_port, port16); + return (port16); + case NNG_AF_ZT: + return (sa->s_zt.sa_port); + default: + return (0); + } +} diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index 0a5114c01..45135976e 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -22,7 +22,6 @@ struct nni_dialer { uint32_t d_id; // endpoint id nni_list_node d_node; // per socket list nni_sock *d_sock; - nni_url *d_url; nni_pipe *d_pipe; // active pipe (for re-dialer) int d_ref; bool d_closed; // full shutdown @@ -37,6 +36,7 @@ struct nni_dialer { nni_duration d_currtime; // current time for reconnect nni_duration d_inirtime; // initial time for reconnect nni_reap_node d_reap; + nng_url d_url; #ifdef NNG_ENABLE_STATS nni_stat_item st_root; @@ -63,7 +63,6 @@ struct nni_listener { uint32_t l_id; // endpoint id nni_list_node l_node; // per socket list nni_sock *l_sock; - nni_url *l_url; int l_ref; bool l_closed; // full shutdown nni_atomic_flag l_closing; // close started (shutdown) @@ -72,6 +71,7 @@ struct nni_listener { nni_aio l_acc_aio; nni_aio l_tmo_aio; nni_reap_node l_reap; + nng_url l_url; #ifdef NNG_ENABLE_STATS nni_stat_item st_root; diff --git a/src/core/url.c b/src/core/url.c index c5be4f835..c4bda443c 100644 --- a/src/core/url.c +++ b/src/core/url.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2024 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -326,23 +326,17 @@ nni_url_default_port(const char *scheme) // scheme with a leading //, such as http:// or tcp://. So our parser // is a bit more restricted, but sufficient for our needs. int -nni_url_parse(nni_url **urlp, const char *raw) +nni_url_parse_inline(nng_url *url, const char *raw) { - nni_url *url; size_t len; const char *s; char *p; char c; int rv; - if ((url = NNI_ALLOC_STRUCT(url)) == NULL) { - return (NNG_ENOMEM); - } - // TODO: remove this when NNG_OPT_URL is gone if ((url->u_rawurl = nni_strdup(raw)) == NULL) { - rv = NNG_ENOMEM; - goto error; + return (NNG_ENOMEM); } // Grab the scheme. @@ -353,8 +347,7 @@ nni_url_parse(nni_url **urlp, const char *raw) } } if (strncmp(s + len, "://", 3) != 0) { - rv = NNG_EINVAL; - goto error; + return (NNG_EINVAL); } for (int i = 0; nni_schemes[i] != NULL; i++) { @@ -364,8 +357,7 @@ nni_url_parse(nni_url **urlp, const char *raw) } } if (url->u_scheme == NULL) { - rv = NNG_ENOTSUP; - goto error; + return (NNG_ENOTSUP); } s += len; @@ -398,9 +390,13 @@ nni_url_parse(nni_url **urlp, const char *raw) if ((strcmp(url->u_scheme, "ipc") == 0) || (strcmp(url->u_scheme, "unix") == 0) || (strcmp(url->u_scheme, "abstract") == 0) || - (strcmp(url->u_scheme, "inproc") == 0)) { - url->u_path = p; - *urlp = url; + (strcmp(url->u_scheme, "inproc") == 0) || + (strcmp(url->u_scheme, "socket") == 0)) { + url->u_path = p; + url->u_hostname = NULL; + url->u_query = NULL; + url->u_fragment = NULL; + url->u_userinfo = NULL; return (0); } @@ -434,8 +430,7 @@ nni_url_parse(nni_url **urlp, const char *raw) // make sure only one '@' appears in the host (only one user // info is allowed) if (strchr(url->u_hostname, '@') != NULL) { - rv = NNG_EADDRINVAL; - goto error; + return (NNG_EINVAL); } } @@ -446,7 +441,7 @@ nni_url_parse(nni_url **urlp, const char *raw) } if ((rv = url_canonify_uri(p)) != 0) { - goto error; + return (rv); } while ((c = *p) != '\0') { @@ -481,14 +476,12 @@ nni_url_parse(nni_url **urlp, const char *raw) p++; while (*p != ']') { if (*p++ == '\0') { - rv = NNG_EINVAL; - goto error; + return (NNG_EINVAL); } } *p++ = '\0'; if ((*p != ':') && (*p != '\0')) { - rv = NNG_EINVAL; - goto error; + return (NNG_EINVAL); } } else { while (*p != ':' && *p != '\0') { @@ -500,47 +493,62 @@ nni_url_parse(nni_url **urlp, const char *raw) } // hostname length check if (strlen(url->u_hostname) >= 256) { - rv = NNG_EADDRINVAL; - goto error; + return (NNG_EINVAL); } if (c == ':') { // If a colon was present, but no port value present, then // that is an error. if (*p == '\0') { - rv = NNG_EINVAL; - goto error; + return (NNG_EINVAL); } - rv = nni_get_port_by_name(p, &url->u_port); - if (rv != 0) { - goto error; + if (nni_get_port_by_name(p, &url->u_port) != 0) { + return (NNG_EINVAL); } } else { url->u_port = nni_url_default_port(url->u_scheme); } + return (0); +} + +int +nng_url_parse(nng_url **urlp, const char *raw) +{ + nng_url *url; + int rv; + + if ((url = NNI_ALLOC_STRUCT(url)) == NULL) { + return (NNG_ENOMEM); + } + if ((rv = nni_url_parse_inline(url, raw)) != 0) { + nng_url_free(url); + return (rv); + } *urlp = url; return (0); +} -error: - nni_url_free(url); - return (rv); +void +nni_url_fini(nng_url *url) +{ + nni_strfree(url->u_rawurl); + if (url->u_bufsz != 0) { + nni_free(url->u_buffer, url->u_bufsz); + } } void -nni_url_free(nni_url *url) +nng_url_free(nng_url *url) { if (url != NULL) { - nni_strfree(url->u_rawurl); - if (url->u_bufsz != 0) { - nni_free(url->u_buffer, url->u_bufsz); - } + nni_url_fini(url); NNI_FREE_STRUCT(url); } } int -nni_url_sprintf(char *str, size_t size, const nni_url *url) +nng_url_sprintf(char *str, size_t size, const nng_url *url) { const char *scheme = url->u_scheme; const char *host = url->u_hostname; @@ -550,7 +558,8 @@ nni_url_sprintf(char *str, size_t size, const nni_url *url) if ((strcmp(scheme, "ipc") == 0) || (strcmp(scheme, "inproc") == 0) || (strcmp(scheme, "unix") == 0) || - (strcmp(scheme, "abstract") == 0)) { + (strcmp(scheme, "abstract") == 0) || + (strcmp(scheme, "socket") == 0)) { return (snprintf(str, size, "%s://%s", scheme, url->u_path)); } @@ -576,16 +585,16 @@ nni_url_sprintf(char *str, size_t size, const nni_url *url) } int -nni_url_asprintf(char **str, const nni_url *url) +nni_url_asprintf(char **str, const nng_url *url) { char *result; size_t sz; - sz = nni_url_sprintf(NULL, 0, url) + 1; + sz = nng_url_sprintf(NULL, 0, url) + 1; if ((result = nni_alloc(sz)) == NULL) { return (NNG_ENOMEM); } - nni_url_sprintf(result, sz, url); + nng_url_sprintf(result, sz, url); *str = result; return (0); } @@ -594,9 +603,9 @@ nni_url_asprintf(char **str, const nni_url *url) // 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) +nni_url_asprintf_port(char **str, const nng_url *url, int port) { - nni_url myurl = *url; + nng_url myurl = *url; if (port > 0) { myurl.u_port = (uint16_t) port; @@ -607,9 +616,9 @@ nni_url_asprintf_port(char **str, const nni_url *url, int port) #define URL_COPYSTR(d, s) ((s != NULL) && ((d = nni_strdup(s)) == NULL)) int -nni_url_clone(nni_url **dstp, const nni_url *src) +nng_url_clone(nng_url **dstp, const nng_url *src) { - nni_url *dst; + nng_url *dst; if ((dst = NNI_ALLOC_STRUCT(dst)) == NULL) { return (NNG_ENOMEM); @@ -687,3 +696,45 @@ nni_url_to_address(nng_sockaddr *sa, const nng_url *url) nni_aio_fini(&aio); return (rv); } + +const char * +nng_url_scheme(const nng_url *url) +{ + return (url->u_scheme); +} + +uint32_t +nng_url_port(const nng_url *url) +{ + return (url->u_port); +} + +const char * +nng_url_hostname(const nng_url *url) +{ + return (url->u_hostname); +} + +const char * +nng_url_path(const nng_url *url) +{ + return (url->u_path); +} + +const char * +nng_url_query(const nng_url *url) +{ + return (url->u_query); +} + +const char * +nng_url_userinfo(const nng_url *url) +{ + return (url->u_userinfo); +} + +const char * +nng_url_fragment(const nng_url *url) +{ + return (url->u_fragment); +} diff --git a/src/core/url.h b/src/core/url.h index f43d3db6b..5aa53dfdd 100644 --- a/src/core/url.h +++ b/src/core/url.h @@ -13,14 +13,27 @@ #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 *); +struct nng_url { + char *u_rawurl; // never NULL + const char *u_scheme; // never NULL + const char *u_userinfo; // will be NULL if not specified + char *u_hostname; // name only, will be "" if not specified + uint32_t u_port; // port, may be zero for schemes that do not use + 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 + // these members are private + char *u_buffer; + size_t u_bufsz; + char u_static[NNG_MAXADDRLEN]; // Most URLs fit within this +}; + extern uint16_t nni_url_default_port(const char *); -extern int nni_url_sprintf(char *, size_t, const nni_url *); -extern int nni_url_asprintf(char **, const nni_url *); -extern int nni_url_asprintf_port(char **, const nni_url *, int); +extern int nni_url_asprintf(char **, const nng_url *); +extern int nni_url_asprintf_port(char **, const nng_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_to_address(nng_sockaddr *, const nng_url *); +extern int nni_url_parse_inline(nng_url *, const char *); +extern void nni_url_fini(nng_url *); #endif // CORE_URL_H diff --git a/src/core/url_test.c b/src/core/url_test.c index 4b767188e..0e30c29e4 100644 --- a/src/core/url_test.c +++ b/src/core/url_test.c @@ -8,6 +8,7 @@ // found online at https://opensource.org/licenses/MIT. // +#include "nng/nng.h" #include "nng_impl.h" #include #include @@ -19,13 +20,13 @@ test_url_host(void) NUTS_PASS(nng_url_parse(&url, "http://www.google.com")); NUTS_ASSERT(url != NULL); - NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); - NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(url->u_port == 80); - NUTS_TRUE(strcmp(url->u_path, "") == 0); - NUTS_TRUE(url->u_query == NULL); - NUTS_TRUE(url->u_fragment == NULL); - NUTS_TRUE(url->u_userinfo == NULL); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -40,7 +41,7 @@ test_url_host_too_long(void) for (size_t i = strlen(buffer); i < sizeof(buffer) - 1; i++) { buffer[i] = 'a'; } - NUTS_FAIL(nng_url_parse(&url, buffer), NNG_EADDRINVAL); + NUTS_FAIL(nng_url_parse(&url, buffer), NNG_EINVAL); } void @@ -49,13 +50,13 @@ test_url_host_port(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://www.google.com:1234")); NUTS_ASSERT(url != NULL); - NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); - NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(url->u_port == 1234); - NUTS_TRUE(strcmp(url->u_path, "") == 0); - NUTS_TRUE(url->u_query == NULL); - NUTS_TRUE(url->u_fragment == NULL); - NUTS_TRUE(url->u_userinfo == NULL); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 1234); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -66,13 +67,13 @@ test_url_host_port_path(void) NUTS_PASS(nng_url_parse(&url, "http://www.google.com:1234/somewhere")); NUTS_ASSERT(url != NULL); - NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); - NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(url->u_port == 1234); - NUTS_TRUE(strcmp(url->u_path, "/somewhere") == 0); - NUTS_TRUE(url->u_userinfo == NULL); - NUTS_TRUE(url->u_query == NULL); - NUTS_TRUE(url->u_fragment == NULL); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 1234); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_NULL(nng_url_userinfo(url)); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); nng_url_free(url); } @@ -83,13 +84,13 @@ test_url_user_info(void) NUTS_PASS(nng_url_parse( &url, "http://garrett@www.google.com:1234/somewhere")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_userinfo, "garrett"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_TRUE(url->u_port == 1234); - NUTS_MATCH(url->u_path, "/somewhere"); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_userinfo(url), "garrett"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 1234); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); nng_url_free(url); } @@ -100,13 +101,13 @@ test_url_path_query_param(void) NUTS_PASS( nng_url_parse(&url, "http://www.google.com/somewhere?result=yes")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/somewhere"); - NUTS_MATCH(url->u_query, "result=yes"); - NUTS_NULL(url->u_userinfo); - NUTS_NULL(url->u_fragment); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_MATCH(nng_url_query(url), "result=yes"); + NUTS_NULL(nng_url_userinfo(url)); + NUTS_NULL(nng_url_fragment(url)); nng_url_free(url); } @@ -118,13 +119,13 @@ test_url_query_param_anchor(void) "http://www.google.com/" "somewhere?result=yes#chapter1")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - 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"); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_MATCH(nng_url_query(url), "result=yes"); + NUTS_MATCH(nng_url_fragment(url), "chapter1"); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -139,13 +140,13 @@ test_url_clone(void) NUTS_ASSERT(src != NULL); NUTS_PASS(nng_url_clone(&url, src)); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - 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"); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_MATCH(nng_url_query(url), "result=yes"); + NUTS_MATCH(nng_url_fragment(url), "chapter1"); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); nng_url_free(src); } @@ -157,13 +158,13 @@ test_url_path_anchor(void) NUTS_PASS( nng_url_parse(&url, "http://www.google.com/somewhere#chapter2")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/somewhere"); - NUTS_MATCH(url->u_fragment, "chapter2"); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/somewhere"); + NUTS_MATCH(nng_url_fragment(url), "chapter2"); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -173,13 +174,13 @@ test_url_anchor(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://www.google.com#chapter3")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_fragment, "chapter3"); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_fragment(url), "chapter3"); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -189,13 +190,13 @@ test_url_query_param(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://www.google.com?color=red")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_query, "color=red"); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.google.com"); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_query(url), "color=red"); NUTS_ASSERT(url != NULL); - NUTS_NULL(url->u_userinfo); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -205,13 +206,13 @@ test_url_v6_host(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://[::1]")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "::1"); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 80); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "::1"); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -221,13 +222,13 @@ test_url_v6_host_port(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://[::1]:29")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "::1"); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 29); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "::1"); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 29); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -237,13 +238,13 @@ test_url_v6_host_port_path(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "http://[::1]:29/bottles")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "::1"); - NUTS_MATCH(url->u_path, "/bottles"); - NUTS_TRUE(url->u_port == 29); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "::1"); + NUTS_MATCH(nng_url_path(url), "/bottles"); + NUTS_TRUE(nng_url_port(url) == 29); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -253,13 +254,13 @@ test_url_tcp_port(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "tcp://:9876/")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "tcp"); - NUTS_MATCH(url->u_hostname, ""); - NUTS_MATCH(url->u_path, "/"); - NUTS_TRUE(url->u_port == 9876); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "tcp"); + NUTS_MATCH(nng_url_hostname(url), ""); + NUTS_MATCH(nng_url_path(url), "/"); + NUTS_TRUE(nng_url_port(url) == 9876); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -270,13 +271,13 @@ test_url_bare_ws(void) NUTS_PASS(nng_url_parse(&url, "ws://")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "ws"); - NUTS_MATCH(url->u_hostname, ""); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 80); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_NULL(url->u_userinfo); + NUTS_MATCH(nng_url_scheme(url), "ws"); + NUTS_MATCH(nng_url_hostname(url), ""); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_NULL(nng_url_userinfo(url)); nng_url_free(url); } @@ -286,13 +287,13 @@ test_url_ssh(void) nng_url *url; NUTS_PASS(nng_url_parse(&url, "ssh://user@host.example.com")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "ssh"); - NUTS_MATCH(url->u_hostname, "host.example.com"); - NUTS_MATCH(url->u_path, ""); - NUTS_TRUE(url->u_port == 22); - NUTS_NULL(url->u_query); - NUTS_NULL(url->u_fragment); - NUTS_MATCH(url->u_userinfo, "user"); + NUTS_MATCH(nng_url_scheme(url), "ssh"); + NUTS_MATCH(nng_url_hostname(url), "host.example.com"); + NUTS_MATCH(nng_url_path(url), ""); + NUTS_TRUE(nng_url_port(url) == 22); + NUTS_NULL(nng_url_query(url)); + NUTS_NULL(nng_url_fragment(url)); + NUTS_MATCH(nng_url_userinfo(url), "user"); nng_url_free(url); } @@ -325,10 +326,10 @@ test_url_canonify(void) NUTS_PASS(nng_url_parse( &url, "http://www.EXAMPLE.com/bogus/.%2e/%7egarrett")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.example.com"); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/~garrett"); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.example.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/~garrett"); nng_url_free(url); } @@ -338,10 +339,10 @@ test_url_path_resolve(void) nng_url *url = NULL; NUTS_PASS( 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_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/abc/y"); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.x.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/abc/y"); nng_url_free(url); } @@ -352,11 +353,11 @@ test_url_query_info_pass(void) NUTS_PASS( nng_url_parse(&url, "http://www.x.com/?/abc/def/./x/.././../y")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.x.com"); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/"); - NUTS_MATCH(url->u_query, "/abc/def/./x/.././../y"); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.x.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/"); + NUTS_MATCH(nng_url_query(url), "/abc/def/./x/.././../y"); nng_url_free(url); } @@ -376,13 +377,37 @@ test_url_good_utf8(void) nng_url *url = NULL; NUTS_PASS(nng_url_parse(&url, "http://www.x.com/%c2%a2_cents")); NUTS_ASSERT(url != NULL); - NUTS_MATCH(url->u_scheme, "http"); - NUTS_MATCH(url->u_hostname, "www.x.com"); - NUTS_TRUE(url->u_port == 80); - NUTS_MATCH(url->u_path, "/\xc2\xa2_cents"); + NUTS_MATCH(nng_url_scheme(url), "http"); + NUTS_MATCH(nng_url_hostname(url), "www.x.com"); + NUTS_TRUE(nng_url_port(url) == 80); + NUTS_MATCH(nng_url_path(url), "/\xc2\xa2_cents"); nng_url_free(url); } +void +test_url_missing_port(void) +{ + nng_url *url = NULL; + NUTS_FAIL( + nng_url_parse(&url, "http://www.x.com:/something"), NNG_EINVAL); +} + +void +test_url_unknown_service(void) +{ + nng_url *url = NULL; + NUTS_FAIL( + nng_url_parse(&url, "http://www.x.com:nosuchservice"), NNG_EINVAL); +} + +void +test_url_duplicate_userinfo(void) +{ + nng_url *url = NULL; + NUTS_FAIL( + nng_url_parse(&url, "http://user@@user@www.x.com"), NNG_EINVAL); +} + void test_url_decode(void) { @@ -462,6 +487,9 @@ NUTS_TESTS = { { "url canonify", test_url_canonify }, { "url path resolve", test_url_path_resolve }, { "url query info pass", test_url_query_info_pass }, + { "url missing port", test_url_missing_port }, + { "url unknown service", test_url_unknown_service }, + { "url duplicate userinfo", test_url_duplicate_userinfo }, { "url bad utf8", test_url_bad_utf8 }, { "url good utf8", test_url_good_utf8 }, { "url decode", test_url_decode }, diff --git a/src/nng.c b/src/nng.c index dd8a98f13..b25701a39 100644 --- a/src/nng.c +++ b/src/nng.c @@ -950,6 +950,33 @@ nng_listener_set_tls(nng_listener id, nng_tls_config *cfg) nni_listener_rele(l); return (rv); } + +int +nng_dialer_get_url(nng_dialer id, const nng_url **urlp) +{ + int rv; + nni_dialer *d; + if ((rv = nni_dialer_find(&d, id.id)) != 0) { + return (rv); + } + *urlp = nni_dialer_url(d); + nni_dialer_rele(d); + return (0); +} + +int +nng_listener_get_url(nng_listener id, const nng_url **urlp) +{ + int rv; + nni_listener *l; + if ((rv = nni_listener_find(&l, id.id)) != 0) { + return (rv); + } + *urlp = nni_listener_url(l); + nni_listener_rele(l); + return (0); +} + int nng_dialer_close(nng_dialer did) { @@ -2020,30 +2047,6 @@ nng_aio_begin(nng_aio *aio) return (true); } -int -nng_url_parse(nng_url **result, const char *ustr) -{ - return (nni_url_parse(result, ustr)); -} - -void -nng_url_free(nng_url *url) -{ - nni_url_free(url); -} - -int -nng_url_clone(nng_url **dstp, const nng_url *src) -{ - return (nni_url_clone(dstp, src)); -} - -int -nng_url_sprintf(char *buf, size_t bufsz, const nng_url *src) -{ - return (nni_url_sprintf(buf, bufsz, src)); -} - #define xstr(a) str(a) #define str(a) #a diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c index c26657e90..66d7b35b4 100644 --- a/src/platform/posix/posix_resolv_gai.c +++ b/src/platform/posix/posix_resolv_gai.c @@ -460,7 +460,7 @@ nni_parse_ip_port(const char *addr, nni_sockaddr *sa) } int -nni_get_port_by_name(const char *name, uint16_t *portp) +nni_get_port_by_name(const char *name, uint32_t *portp) { struct servent *se; long port; diff --git a/src/platform/resolver_test.c b/src/platform/resolver_test.c index 9c7db2c09..005affe3f 100644 --- a/src/platform/resolver_test.c +++ b/src/platform/resolver_test.c @@ -111,7 +111,7 @@ test_service_names(void) { nng_aio *aio; nng_sockaddr sa; - uint16_t port; + uint32_t port; NUTS_PASS(nng_aio_alloc(&aio, NULL, NULL)); nni_resolv_ip("8.8.4.4", 80, NNG_AF_INET, true, &sa, aio); diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c index f9e5e1f6e..46695b7e7 100644 --- a/src/platform/windows/win_resolv.c +++ b/src/platform/windows/win_resolv.c @@ -412,7 +412,7 @@ nni_parse_ip_port(const char *addr, nni_sockaddr *sa) } int -nni_get_port_by_name(const char *name, uint16_t *portp) +nni_get_port_by_name(const char *name, uint32_t *portp) { struct servent *se; long port; diff --git a/src/sp/transport.c b/src/sp/transport.c index 973be40b0..a2220e7be 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -32,14 +32,16 @@ nni_sp_tran_register(nni_sp_tran *tran) } nni_sp_tran * -nni_sp_tran_find(nni_url *url) +nni_sp_tran_find(const char *url) { // address is of the form "://blah..." nni_sp_tran *t; nni_rwlock_rdlock(&sp_tran_lk); NNI_LIST_FOREACH (&sp_tran_list, t) { - if (strcmp(url->u_scheme, t->tran_scheme) == 0) { + size_t len = strlen(t->tran_scheme); + if ((strncmp(url, t->tran_scheme, len) == 0) && + (strncmp(url + len, "://", 3) == 0)) { nni_rwlock_unlock(&sp_tran_lk); return (t); } diff --git a/src/sp/transport.h b/src/sp/transport.h index 8fd474836..b65486eda 100644 --- a/src/sp/transport.h +++ b/src/sp/transport.h @@ -27,7 +27,7 @@ struct nni_sp_dialer_ops { // d_init creates a vanilla dialer. The value created is // used for the first argument for all other dialer functions. - int (*d_init)(void **, nni_url *, nni_dialer *); + int (*d_init)(void **, nng_url *, nni_dialer *); // d_fini frees the resources associated with the dialer. // The dialer will already have been closed. @@ -66,7 +66,7 @@ struct nni_sp_dialer_ops { struct nni_sp_listener_ops { // l_init creates a vanilla listener. The value created is // used for the first argument for all other listener functions. - int (*l_init)(void **, nni_url *, nni_listener *); + int (*l_init)(void **, nng_url *, nni_listener *); // l_fini frees the resources associated with the listener. // The listener will already have been closed. @@ -76,8 +76,10 @@ struct nni_sp_listener_ops { // reserving the address but not creating any connections. // It should return NNG_EADDRINUSE if the address is already // taken. It can also return NNG_EBADADDR for an unsuitable - // address, or NNG_EACCESS for permission problems. - int (*l_bind)(void *); + // address, or NNG_EACCESS for permission problems. The transport + // should update the url if it has changed (e.g. due to converting + // from port 0 to a real port.) + int (*l_bind)(void *, nng_url *); // l_accept accepts an inbound connection. void (*l_accept)(void *, nni_aio *); @@ -184,7 +186,7 @@ struct nni_sp_tran { // These APIs are used by the framework internally, and not for use by // transport implementations. -extern nni_sp_tran *nni_sp_tran_find(nni_url *); +extern nni_sp_tran *nni_sp_tran_find(const char *); extern void nni_sp_tran_sys_init(void); extern void nni_sp_tran_sys_fini(void); extern void nni_sp_tran_register(nni_sp_tran *); diff --git a/src/sp/transport/inproc/inproc.c b/src/sp/transport/inproc/inproc.c index b7ead07ce..5216b5e6b 100644 --- a/src/sp/transport/inproc/inproc.c +++ b/src/sp/transport/inproc/inproc.c @@ -283,7 +283,7 @@ inproc_pipe_get_addr(void *arg, void *buf, size_t *szp, nni_opt_type t) } static int -inproc_dialer_init(void **epp, nni_url *url, nni_dialer *ndialer) +inproc_dialer_init(void **epp, nng_url *url, nni_dialer *ndialer) { inproc_ep *ep; nni_sock *sock = nni_dialer_sock(ndialer); @@ -306,7 +306,7 @@ inproc_dialer_init(void **epp, nni_url *url, nni_dialer *ndialer) } static int -inproc_listener_init(void **epp, nni_url *url, nni_listener *nlistener) +inproc_listener_init(void **epp, nng_url *url, nni_listener *nlistener) { inproc_ep *ep; nni_sock *sock = nni_listener_sock(nlistener); @@ -510,11 +510,12 @@ inproc_ep_connect(void *arg, nni_aio *aio) } static int -inproc_ep_bind(void *arg) +inproc_ep_bind(void *arg, nng_url *url) { inproc_ep *ep = arg; inproc_ep *srch; nni_list *list = &nni_inproc.servers; + NNI_ARG_UNUSED(url); nni_mtx_lock(&nni_inproc.mx); NNI_LIST_FOREACH (list, srch) { diff --git a/src/sp/transport/ipc/ipc.c b/src/sp/transport/ipc/ipc.c index 82af69252..69efa741c 100644 --- a/src/sp/transport/ipc/ipc.c +++ b/src/sp/transport/ipc/ipc.c @@ -11,6 +11,7 @@ #include +#include "core/defs.h" #include "core/nng_impl.h" // IPC transport. Platform specific IPC operations must be @@ -851,7 +852,7 @@ ipc_ep_init(ipc_ep **epp, nni_sock *sock) } static int -ipc_ep_init_dialer(void **dp, nni_url *url, nni_dialer *dialer) +ipc_ep_init_dialer(void **dp, nng_url *url, nni_dialer *dialer) { ipc_ep *ep; int rv; @@ -874,7 +875,7 @@ ipc_ep_init_dialer(void **dp, nni_url *url, nni_dialer *dialer) } static int -ipc_ep_init_listener(void **dp, nni_url *url, nni_listener *listener) +ipc_ep_init_listener(void **dp, nng_url *url, nni_listener *listener) { ipc_ep *ep; int rv; @@ -971,10 +972,11 @@ ipc_ep_set_recv_max_sz(void *arg, const void *v, size_t sz, nni_type t) } static int -ipc_ep_bind(void *arg) +ipc_ep_bind(void *arg, nng_url *url) { ipc_ep *ep = arg; int rv; + NNI_ARG_UNUSED(url); nni_mtx_lock(&ep->mtx); rv = nng_stream_listener_listen(ep->listener); diff --git a/src/sp/transport/socket/sockfd.c b/src/sp/transport/socket/sockfd.c index 2313d12d6..d3d4218f4 100644 --- a/src/sp/transport/socket/sockfd.c +++ b/src/sp/transport/socket/sockfd.c @@ -12,6 +12,7 @@ #include #include +#include "core/defs.h" #include "core/nng_impl.h" // Socket transport. This takes sockets that may have been @@ -817,7 +818,7 @@ sfd_tran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) nni_sock *sock = nni_listener_sock(nlistener); // Check for invalid URL components -- we only accept a bare scheme - if ((strlen(url->u_hostname) != 0) || (strlen(url->u_path) != 0) || + if ((url->u_hostname != NULL) || (strlen(url->u_path) != 0) || (url->u_fragment != NULL) || (url->u_userinfo != NULL) || (url->u_query != NULL)) { return (NNG_EADDRINVAL); @@ -884,9 +885,10 @@ sfd_tran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) } static int -sfd_tran_ep_bind(void *arg) +sfd_tran_ep_bind(void *arg, nng_url *url) { sfd_tran_ep *ep = arg; + NNI_ARG_UNUSED(url); return (nng_stream_listener_listen(ep->listener)); } diff --git a/src/sp/transport/socket/sockfd_test.c b/src/sp/transport/socket/sockfd_test.c index 842a377c7..c27f49bdf 100644 --- a/src/sp/transport/socket/sockfd_test.c +++ b/src/sp/transport/socket/sockfd_test.c @@ -10,6 +10,7 @@ // found online at https://opensource.org/licenses/MIT. // +#include #include #ifdef NNG_PLATFORM_POSIX @@ -50,10 +51,20 @@ test_sfd_malformed_address(void) void test_sfd_listen(void) { - nng_socket s1; + nng_socket s1; + nng_listener l; + const nng_url *u; NUTS_OPEN(s1); - NUTS_PASS(nng_listen(s1, "socket://", NULL, 0)); + NUTS_PASS(nng_listen(s1, "socket://", &l, 0)); + NUTS_PASS(nng_listener_get_url(l, &u)); + NUTS_MATCH(nng_url_scheme(u), "socket"); + NUTS_MATCH(nng_url_path(u), ""); + NUTS_NULL(nng_url_userinfo(u)); + NUTS_NULL(nng_url_hostname(u)); + NUTS_NULL(nng_url_query(u)); + NUTS_NULL(nng_url_fragment(u)); + NUTS_CLOSE(s1); } diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 86d0ac074..f619d4d99 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -1023,13 +1023,19 @@ tcptran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) } static int -tcptran_ep_bind(void *arg) +tcptran_ep_bind(void *arg, nng_url *url) { tcptran_ep *ep = arg; int rv; nni_mtx_lock(&ep->mtx); rv = nng_stream_listener_listen(ep->listener); + if (rv == 0) { + int port; + nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + url->u_port = (uint32_t) port; + } nni_mtx_unlock(&ep->mtx); return (rv); diff --git a/src/sp/transport/tcp/tcp_test.c b/src/sp/transport/tcp/tcp_test.c index c80a259ff..37321ac1c 100644 --- a/src/sp/transport/tcp/tcp_test.c +++ b/src/sp/transport/tcp/tcp_test.c @@ -125,6 +125,42 @@ test_tcp_no_delay_option(void) NUTS_CLOSE(s); } +static bool +has_v6(void) +{ + nng_sockaddr sa; + nng_udp *u; + int rv; + + sa.s_in6.sa_family = NNG_AF_INET6; + sa.s_in6.sa_port = 0; + memset(sa.s_in6.sa_addr, 0, 16); + sa.s_in6.sa_addr[15] = 1; + + rv = nng_udp_open(&u, &sa); + if (rv == 0) { + nng_udp_close(u); + } + return (rv == 0 ? 1 : 0); +} + +void +test_tcp_ipv6(void) +{ + if (!has_v6()) { + NUTS_SKIP("No IPv6 support"); + return; + } + nng_socket s; + NUTS_OPEN(s); + // this should have a [::1] bracket + NUTS_FAIL(nng_dial(s, "tcp://::1", NULL, 0), NNG_EINVAL); + NUTS_FAIL(nng_dial(s, "tcp://::1:5055", NULL, 0), NNG_EINVAL); + // this requires a port, but otherwise its ok, so address is invalid + NUTS_FAIL(nng_dial(s, "tcp://[::1]", NULL, 0), NNG_EADDRINVAL); + NUTS_CLOSE(s); +} + void test_tcp_keep_alive_option(void) { @@ -206,5 +242,6 @@ NUTS_TESTS = { { "tcp no delay option", test_tcp_no_delay_option }, { "tcp keep alive option", test_tcp_keep_alive_option }, { "tcp recv max", test_tcp_recv_max }, + { "tcp ipv6", test_tcp_ipv6 }, { NULL, NULL }, }; diff --git a/src/sp/transport/tls/tls.c b/src/sp/transport/tls/tls.c index b1aea7b39..929e3f8ef 100644 --- a/src/sp/transport/tls/tls.c +++ b/src/sp/transport/tls/tls.c @@ -14,6 +14,7 @@ #include "core/nng_impl.h" +#include "nng/nng.h" #include "nng/supplemental/tls/tls.h" // TLS over TCP transport. Platform specific TCP operations must be @@ -61,7 +62,7 @@ struct tlstran_ep { bool closed; bool fini; int refcnt; - nni_url *url; + nng_url *url; nni_list pipes; nni_reap_node reap; nng_stream_dialer *dialer; @@ -825,7 +826,7 @@ tlstran_ep_init(tlstran_ep **epp, nng_url *url, nni_sock *sock) } static int -tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer) +tlstran_ep_init_dialer(void **dp, nng_url *url, nni_dialer *ndialer) { tlstran_ep *ep; int rv; @@ -859,7 +860,7 @@ tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer) } static int -tlstran_ep_init_listener(void **lp, nni_url *url, nni_listener *nlistener) +tlstran_ep_init_listener(void **lp, nng_url *url, nni_listener *nlistener) { tlstran_ep *ep; int rv; @@ -970,13 +971,19 @@ tlstran_ep_connect(void *arg, nni_aio *aio) } static int -tlstran_ep_bind(void *arg) +tlstran_ep_bind(void *arg, nng_url *url) { tlstran_ep *ep = arg; int rv; nni_mtx_lock(&ep->mtx); rv = nng_stream_listener_listen(ep->listener); + if (rv == 0) { + int port; + nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + url->u_port = (uint32_t) port; + } nni_mtx_unlock(&ep->mtx); return (rv); diff --git a/src/sp/transport/udp/udp.c b/src/sp/transport/udp/udp.c index 29a516d8f..ad168642a 100644 --- a/src/sp/transport/udp/udp.c +++ b/src/sp/transport/udp/udp.c @@ -1801,7 +1801,7 @@ udp_ep_start(udp_ep *ep) } static int -udp_ep_bind(void *arg) +udp_ep_bind(void *arg, nng_url *url) { udp_ep *ep = arg; int rv; @@ -1817,6 +1817,9 @@ udp_ep_bind(void *arg) nni_mtx_unlock(&ep->mtx); return (rv); } + nng_sockaddr sa; + nni_plat_udp_sockname(ep->udp, &sa); + url->u_port = nng_sockaddr_port(&sa); udp_ep_start(ep); nni_mtx_unlock(&ep->mtx); diff --git a/src/sp/transport/udp/udp_tran_test.c b/src/sp/transport/udp/udp_tran_test.c index 781c6ad93..654df1e26 100644 --- a/src/sp/transport/udp/udp_tran_test.c +++ b/src/sp/transport/udp/udp_tran_test.c @@ -58,27 +58,38 @@ test_udp_local_address_connect(void) void test_udp_port_zero_bind(void) { - nng_socket s1; - nng_socket s2; - nng_sockaddr sa; - nng_listener l; - char *addr; - int port; + nng_socket s1; + nng_socket s2; + nng_sockaddr sa; + nng_listener l; + nng_dialer d; + char addr[NNG_MAXADDRSTRLEN]; + int port; + const nng_url *u1; + const nng_url *u2; NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_listen(s1, "udp://127.0.0.1:0", &l, 0)); nng_msleep(100); - NUTS_PASS(nng_listener_get_string(l, NNG_OPT_URL, &addr)); - NUTS_TRUE(memcmp(addr, "udp://", 6) == 0); + NUTS_PASS(nng_listener_get_url(l, &u1)); + NUTS_TRUE(nng_url_port(u1) != 0); + NUTS_MATCH(nng_url_scheme(u1), "udp"); + NUTS_MATCH(nng_url_hostname(u1), "127.0.0.1"); + NUTS_MATCH(nng_url_path(u1), ""); + nng_url_sprintf(addr, sizeof(addr), u1); NUTS_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); NUTS_TRUE(sa.s_in.sa_family == NNG_AF_INET); - NUTS_TRUE(sa.s_in.sa_port != 0); + NUTS_TRUE(sa.s_in.sa_port == nuts_be16(nng_url_port(u1))); NUTS_TRUE(sa.s_in.sa_addr == nuts_be32(0x7f000001)); - NUTS_PASS(nng_dial(s2, addr, NULL, 0)); + NUTS_PASS(nng_dial(s2, addr, &d, 0)); + NUTS_PASS(nng_dialer_get_url(d, &u2)); + NUTS_MATCH(nng_url_scheme(u1), nng_url_scheme(u2)); + NUTS_MATCH(nng_url_hostname(u1), nng_url_hostname(u2)); + NUTS_MATCH(nng_url_path(u1), nng_url_path(u2)); + NUTS_TRUE(nng_url_port(u1) == nng_url_port(u2)); NUTS_PASS(nng_listener_get_int(l, NNG_OPT_TCP_BOUND_PORT, &port)); - NUTS_TRUE(port == nuts_be16(sa.s_in.sa_port)); - nng_strfree(addr); + NUTS_TRUE(port == (int) nng_url_port(u1)); NUTS_CLOSE(s2); NUTS_CLOSE(s1); diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 3bfd9f318..dec646ce7 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -252,13 +252,17 @@ wstran_pipe_peer(void *arg) } static int -ws_listener_bind(void *arg) +ws_listener_bind(void *arg, nng_url *url) { ws_listener *l = arg; int rv; if ((rv = nng_stream_listener_listen(l->listener)) == 0) { + int port; l->started = true; + nng_stream_listener_get_int( + l->listener, NNG_OPT_TCP_BOUND_PORT, &port); + url->u_port = (uint32_t) port; } return (rv); } diff --git a/src/sp/transport/zerotier/zerotier.c b/src/sp/transport/zerotier/zerotier.c index 7b2142b1e..6e475c1a3 100644 --- a/src/sp/transport/zerotier/zerotier.c +++ b/src/sp/transport/zerotier/zerotier.c @@ -2336,10 +2336,11 @@ zt_ep_bind_locked(zt_ep *ep) } static int -zt_ep_bind(void *arg) +zt_ep_bind(void *arg, nng_url *url) { int rv; zt_ep *ep = arg; + NNI_ARG_UNUSED(url); nni_mtx_lock(&zt_lk); rv = zt_ep_bind_locked(ep); diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 813f9fe64..dbda53ae9 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -108,7 +108,7 @@ extern int nni_http_conn_getopt( // Note that the iovs of the aio's are clobbered by these methods -- callers // must not use them for any other purpose. -extern int nni_http_req_alloc(nni_http_req **, const nni_url *); +extern int nni_http_req_alloc(nni_http_req **, const nng_url *); extern int nni_http_res_alloc(nni_http_res **); extern int nni_http_res_alloc_error(nni_http_res **, uint16_t); extern void nni_http_req_free(nni_http_req *); @@ -170,7 +170,7 @@ extern void nni_http_write_full(nni_http_conn *, nni_aio *); // a restricted binding is required, we recommend using a URL consisting // of an empty host name, such as http:// or https:// -- this would // convert to binding to the default port on all interfaces on the host. -extern int nni_http_server_init(nni_http_server **, const nni_url *); +extern int nni_http_server_init(nni_http_server **, const nng_url *); // nni_http_server_fini drops the reference count on the server, and // if this was the last reference, closes down the server and frees @@ -349,7 +349,7 @@ extern const char *nni_http_handler_get_uri(nni_http_handler *); // Client stuff. -extern int nni_http_client_init(nni_http_client **, const nni_url *); +extern int nni_http_client_init(nni_http_client **, const nng_url *); extern void nni_http_client_fini(nni_http_client *); // nni_http_client_set_tls sets the TLS configuration. This wipes out diff --git a/src/supplemental/http/http_client.c b/src/supplemental/http/http_client.c index 0fbe3ef93..af5bc717e 100644 --- a/src/supplemental/http/http_client.c +++ b/src/supplemental/http/http_client.c @@ -96,7 +96,7 @@ nni_http_client_fini(nni_http_client *c) } int -nni_http_client_init(nni_http_client **cp, const nni_url *url) +nni_http_client_init(nni_http_client **cp, const nng_url *url) { int rv; nni_http_client *c; diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index a2ab218f7..2c258e2c0 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -600,7 +600,7 @@ nni_http_res_get_buf(nni_http_res *res, void **data, size_t *szp) } int -nni_http_req_alloc(nni_http_req **reqp, const nni_url *url) +nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) { nni_http_req *req; if ((req = NNI_ALLOC_STRUCT(req)) == NULL) { diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 03b3cf684..72e7fa72f 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -1,5 +1,5 @@ // -// Copyright 2023 Staysail Systems, Inc. +// Copyright 2024 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2018 QXSoftware // Copyright 2019 Devolutions @@ -77,7 +77,7 @@ struct nng_http_server { bool fini; // if nni_http_server_fini was called nni_aio *accaio; nng_stream_listener *listener; - int port; // native order + uint32_t port; // native order char *hostname; nni_list errors; nni_mtx errors_mtx; @@ -932,7 +932,7 @@ http_server_fini(nni_http_server *s) } static int -http_server_init(nni_http_server **serverp, const nni_url *url) +http_server_init(nni_http_server **serverp, const nng_url *url) { nni_http_server *s; int rv; @@ -980,7 +980,7 @@ http_server_init(nni_http_server **serverp, const nni_url *url) } int -nni_http_server_init(nni_http_server **serverp, const nni_url *url) +nni_http_server_init(nni_http_server **serverp, const nng_url *url) { int rv; nni_http_server *s; @@ -1014,8 +1014,10 @@ http_server_start(nni_http_server *s) return (rv); } if (s->port == 0) { + int port; nng_stream_listener_get_int( - s->listener, NNG_OPT_TCP_BOUND_PORT, &s->port); + s->listener, NNG_OPT_TCP_BOUND_PORT, &port); + s->port = (uint32_t) port; } nng_stream_listener_accept(s->listener, s->accaio); return (0); diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h index ea4975fff..fab716bf9 100644 --- a/src/supplemental/websocket/websocket.h +++ b/src/supplemental/websocket/websocket.h @@ -31,7 +31,7 @@ typedef struct nni_ws_dialer nni_ws_dialer; // Much of the websocket API is still "private", meaning you should not // rely upon it being around. -extern int nni_ws_listener_alloc(nng_stream_listener **, const nni_url *); -extern int nni_ws_dialer_alloc(nng_stream_dialer **, const nni_url *); +extern int nni_ws_listener_alloc(nng_stream_listener **, const nng_url *); +extern int nni_ws_dialer_alloc(nng_stream_dialer **, const nng_url *); #endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H diff --git a/tests/httpserver.c b/tests/httpserver.c index f572bc2ce..c3801148f 100644 --- a/tests/httpserver.c +++ b/tests/httpserver.c @@ -143,7 +143,7 @@ httpget(const char *addr, void **datap, size_t *sizep, uint16_t *statp, free(ctype); } if (url != NULL) { - nni_url_free(url); + nng_url_free(url); } if (req != NULL) { nng_http_req_free(req); diff --git a/tests/tcp6.c b/tests/tcp6.c index f6fd5a7c7..a3ce919ba 100644 --- a/tests/tcp6.c +++ b/tests/tcp6.c @@ -75,14 +75,4 @@ TestMain("TCP (IPv6) Transport", { } else { SkipSo("IPv6 not available"); } - - Convey("Malformed TCPv6 addresses do not panic", { - nng_socket s1; - - So(nng_pair_open(&s1) == 0); - Reset({ nng_close(s1); }); - So(nng_dial(s1, "tcp://::1", NULL, 0) == NNG_EADDRINVAL); - So(nng_dial(s1, "tcp://::1:5055", NULL, 0) == NNG_EADDRINVAL); - So(nng_dial(s1, "tcp://[::1]", NULL, 0) == NNG_EADDRINVAL); - }); }) diff --git a/tests/trantest.h b/tests/trantest.h index 2434171a0..9c3b2efb3 100644 --- a/tests/trantest.h +++ b/tests/trantest.h @@ -117,9 +117,9 @@ trantest_init(trantest *tt, const char *addr) So(nng_rep_open(&tt->repsock) == 0); nng_url *url; - So(nng_url_parse(&url, tt->addr) == 0); - tt->tran = nni_sp_tran_find(url); + tt->tran = nni_sp_tran_find(addr); So(tt->tran != NULL); + So(nng_url_parse(&url, tt->addr) == 0); nng_url_free(url); }