diff options
| -rw-r--r-- | docs/man/nng_dialer_get.3.adoc | 5 | ||||
| -rw-r--r-- | docs/man/nng_listener_get.3.adoc | 5 | ||||
| -rw-r--r-- | docs/ref/api/pipe.md | 21 | ||||
| -rw-r--r-- | docs/ref/api/stream.md | 14 | ||||
| -rw-r--r-- | include/nng/nng.h | 23 | ||||
| -rw-r--r-- | src/core/options.c | 12 | ||||
| -rw-r--r-- | src/core/stream.c | 8 | ||||
| -rw-r--r-- | src/nng.c | 66 | ||||
| -rw-r--r-- | src/supplemental/websocket/websocket_test.c | 10 |
9 files changed, 119 insertions, 45 deletions
diff --git a/docs/man/nng_dialer_get.3.adoc b/docs/man/nng_dialer_get.3.adoc index 9b1e6577..575db971 100644 --- a/docs/man/nng_dialer_get.3.adoc +++ b/docs/man/nng_dialer_get.3.adoc @@ -29,7 +29,7 @@ int nng_dialer_get_size(nng_dialer d, const char *opt, size_t *zp); int nng_dialer_get_addr(nng_dialer d, const char *opt, nng_sockaddr *sap); -int nng_dialer_get_string(nng_dialer d, const char *opt, char **strp); +int nng_dialer_get_string(nng_dialer d, const char *opt, const char **strp); int nng_dialer_get_uint64(nng_dialer d, const char *opt, uint64_t *u64p); @@ -77,9 +77,6 @@ into the value referenced by _sap_. `nng_dialer_get_string()`:: This function is used to retrieve a string into _strp_. -This string is created from the source using xref:nng_strdup.3.adoc[`nng_strdup()`] -and consequently must be freed by the caller using -xref:nng_strfree.3.adoc[`nng_strfree()`] when it is no longer needed. `nng_dialer_get_uint64()`:: This function is used to retrieve a 64-bit unsigned value into the value diff --git a/docs/man/nng_listener_get.3.adoc b/docs/man/nng_listener_get.3.adoc index a5df826d..4c4de6b4 100644 --- a/docs/man/nng_listener_get.3.adoc +++ b/docs/man/nng_listener_get.3.adoc @@ -29,7 +29,7 @@ int nng_listener_get_size(nng_listener l, const char *opt, size_t *zp); int nng_listener_get_addr(nng_listener l, const char *opt, nng_sockaddr *sap); -int nng_listener_get_string(nng_listener l, const char *opt, char **strp); +int nng_listener_get_string(nng_listener l, const char *opt, const char **strp); int nng_listener_get_uint64(nng_listener l, const char *opt, uint64_t *u64p); @@ -75,9 +75,6 @@ into the value referenced by _sap_. `nng_listener_get_string()`:: This function is used to retrieve a string into _strp_. -This string is created from the source using xref:nng_strdup.3.adoc[`nng_strdup()`] -and consequently must be freed by the caller using -xref:nng_strfree.3.adoc[`nng_strfree()`] when it is no longer needed. `nng_listener_get_uint64()`:: This function is used to retrieve a 64-bit unsigned value into the value diff --git a/docs/ref/api/pipe.md b/docs/ref/api/pipe.md index fbd89120..4fae1d06 100644 --- a/docs/ref/api/pipe.md +++ b/docs/ref/api/pipe.md @@ -92,7 +92,10 @@ nng_err nng_pipe_get_int(nng_pipe p, const char *opt, int *valp); nng_err nng_pipe_get_ms(nng_pipe p, const char *opt, nng_duration *valp); nng_err nng_pipe_get_size(nng_pipe p, const char *opt, size_t *valp); nng_err nng_pipe_get_addr(nng_pipe p, const char *opt, nng_sockaddr *valp); -nng_err nng_pipe_get_string(nng_pipe p, const char *opt, char **valp); +nng_err nng_pipe_get_string(nng_pipe p, const char *opt, const char **valp); +nng_err nng_pipe_get_strcpy(nng_pipe p, const char *opt, char *val, size_t len); +nng_err nng_pipe_get_strdup(nng_pipe p, const char *opt, char **valp); +nng_err nng_pipe_get_strlen(nng_pipe p, const char *opt, size_t *lenp); ``` {{hi:`nng_pipe_get_bool`}} @@ -101,14 +104,26 @@ nng_err nng_pipe_get_string(nng_pipe p, const char *opt, char **valp); {{hi:`nng_pipe_get_size`}} {{hi:`nng_pipe_get_addr`}} {{hi:`nng_pipe_get_string`}} +{{hi:`nng_pipe_get_strcpy`}} +{{hi:`nng_pipe_get_strdup`}} These functions are used to obtain value of an option named _opt_ from the pipe _p_, and store it in the location referenced by _valp_. These functions access an option as a specific type. The transport layer will have details about which options are available, and which type they may be accessed using. -In the case of `nng_pipe_get_string`, the string is created as if by [`nng_strdup`], and must be freed by -the caller using [`nng_strfree`] when no longer needed. +In the case of `nng_pipe_get_string`, the underlying string may only be valid for as long as the pipe is valid. +Thus, this function can only be safely called in a pipe event callback set up with [`nng_pipe_notify`]. + +The `nng_pipe_get_strdup` function is like `nng_pipe_get_string`, but makes a copy into a newly allocated buffer, so that the string must be freed by the caller using [`nng_strfree`]. + +The `nng_pipe_get_strcpy` function is also like `nng_pipe_get_string`, but it makes a copy into a buffer +supplied by the caller. The buffer is passed in _val_, and the size of the buffer is passed in _len_. +The value of _len_ must be large enough to hold the string and the terminating zero byte. + +The `nng_pipe_get_strlen` function is used to obtain the length of the string. This can be useful +to find the size of the buffer needed by the `nng_pipe_get_strcpy` function for a property. +Note that like `strlen`, this size does not account for the zero byte to terminate the string. ## Pipe Notifications diff --git a/docs/ref/api/stream.md b/docs/ref/api/stream.md index 5715990f..a2427a70 100644 --- a/docs/ref/api/stream.md +++ b/docs/ref/api/stream.md @@ -84,7 +84,7 @@ nng_err nng_stream_get_int(nng_stream *s, const char *opt, int *valp); nng_err nng_stream_get_ms(nng_stream *s, const char *opt, nng_duration *valp); nng_err nng_stream_get_size(nng_stream *s, const char *opt, size_t *valp); nng_err nng_stream_get_addr(nng_stream *s, const char *opt, nng_sockaddr *valp); -nng_err nng_stream_get_string(nng_stream *s, const char *opt, char **valp); +nng_err nng_stream_get_string(nng_stream *s, const char *opt, const char **valp); ``` {{hi:`nng_stream_get_bool`}} @@ -99,8 +99,8 @@ referenced by _valp_. These functions access an option as a specific type. The transport layer will have details about which options are available, and which type they may be accessed using. -In the case of `nng_stream_get_string`, the string is created as if by [`nng_strdup`], and must be freed by -the caller using [`nng_strfree`] when no longer needed. +In the case of `nng_stream_get_string`, the string pointer is only guaranteed to be valid while the +stream exists. Callers should make a copy of the data if required before closing the stream. ## Stream Factories @@ -261,14 +261,14 @@ nng_err nng_stream_dialer_get_bool(nng_stream_dialer *dialer, const char *opt, b nng_err nng_stream_dialer_get_int(nng_stream_dialer *dialer, const char *opt, int *valp); nng_err nng_stream_dialer_get_ms(nng_stream_dialer *dialer, const char *opt, nng_duration *valp); nng_err nng_stream_dialer_get_size(nng_stream_dialer *dialer, const char *opt, size_t *valp); -nng_err nng_stream_dialer_get_string(nng_stream_dialer *dialer, const char *opt, char **valp); +nng_err nng_stream_dialer_get_string(nng_stream_dialer *dialer, const char *opt, const char **valp); nng_err nng_stream_listener_get_addr(nng_stream_listener *listener, const char *opt, nng_sockaddr *valp); nng_err nng_stream_listener_get_bool(nng_stream_listener *listener, const char *opt, bool *valp); nng_err nng_stream_listener_get_int(nng_stream_listener *listener, const char *opt, int *valp); nng_err nng_stream_listener_get_ms(nng_stream_listener *listener, const char *opt, nng_duration *valp); nng_err nng_stream_listener_get_size(nng_stream_listener *listener, const char *opt, size_t *valp); -nng_err nng_stream_listener_get_string(nng_stream_listener *listener, const char *opt, char **valp); +nng_err nng_stream_listener_get_string(nng_stream_listener *listener, const char *opt, const char **valp); nng_err nng_stream_dialer_set_addr(nng_stream_dialer *dialer, const char *opt, const nng_sockaddr *val); nng_err nng_stream_dialer_set_bool(nng_stream_dialer *dialer, const char *opt, bool val); @@ -316,8 +316,8 @@ The `nng_stream_dialer_set_` and `nng_stream_listener_set_` function families ch These functions access an option as a specific type. The transport layer will have details about which options are available, and which type they may be accessed using. -In the case of `nng_stream_dialer_get_string` and `nng_stream_listener_get_string`, the string is created as if by [`nng_strdup`], and must be freed by -the caller using [`nng_strfree`] when no longer needed. +In the case of `nng_stream_dialer_get_string` and `nng_stream_listener_get_string`, the memory holding +the string is only valid as long as the associated object remains open. In the case of `nng_stream_dialer_set_string` and `nng_stream_listener_set_string`, the string contents are copied if necessary, so that the caller need not retain the value referenced once the function returns. diff --git a/include/nng/nng.h b/include/nng/nng.h index 69c5ee89..4108f027 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -432,7 +432,7 @@ NNG_DECL int nng_dialer_get_bool(nng_dialer, const char *, bool *); NNG_DECL int nng_dialer_get_int(nng_dialer, const char *, int *); NNG_DECL int nng_dialer_get_size(nng_dialer, const char *, size_t *); NNG_DECL int nng_dialer_get_uint64(nng_dialer, const char *, uint64_t *); -NNG_DECL int nng_dialer_get_string(nng_dialer, const char *, char **); +NNG_DECL int nng_dialer_get_string(nng_dialer, const char *, const char **); 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 **); @@ -454,7 +454,8 @@ NNG_DECL int nng_listener_get_bool(nng_listener, const char *, bool *); NNG_DECL int nng_listener_get_int(nng_listener, const char *, int *); NNG_DECL int nng_listener_get_size(nng_listener, const char *, size_t *); NNG_DECL int nng_listener_get_uint64(nng_listener, const char *, uint64_t *); -NNG_DECL int nng_listener_get_string(nng_listener, const char *, char **); +NNG_DECL int nng_listener_get_string( + nng_listener, const char *, const char **); NNG_DECL int nng_listener_get_ms(nng_listener, const char *, nng_duration *); NNG_DECL int nng_listener_get_addr(nng_listener, const char *, nng_sockaddr *); NNG_DECL int nng_listener_get_tls(nng_listener, nng_tls_config **); @@ -770,7 +771,7 @@ NNG_DECL nng_err nng_pipe_get_bool(nng_pipe, const char *, bool *); NNG_DECL nng_err nng_pipe_get_int(nng_pipe, const char *, int *); NNG_DECL nng_err nng_pipe_get_ms(nng_pipe, const char *, nng_duration *); NNG_DECL nng_err nng_pipe_get_size(nng_pipe, const char *, size_t *); -NNG_DECL nng_err nng_pipe_get_string(nng_pipe, const char *, char **); +NNG_DECL nng_err nng_pipe_get_string(nng_pipe, const char *, const char **); NNG_DECL nng_err nng_pipe_get_addr(nng_pipe, const char *, nng_sockaddr *); NNG_DECL nng_err nng_pipe_peer_cert(nng_pipe, nng_tls_cert **); @@ -892,6 +893,15 @@ NNG_DECL nng_listener nng_pipe_listener(nng_pipe); // headers from the peer on a pipe. #define NNG_OPT_WS_HEADER "ws:header:" +// NNG_OPT_WS_HEADER_KEY is also a prefix, but the value it contains +// is the name (key) of the header at the index referenced. This +// allows successive iteration through headers. +#define NNG_OPT_WS_HEADER_KEY "ws:header_k:" + +// NNG_OPT_WS_HEADER_VAL is also a prefix, but the value it contains +// is the value of the header at the index referenced. +#define NNG_OPT_WS_HEADER_VAL "ws:header_v:" + // NNG_OPT_WS_REQUEST_URI is used to obtain the URI sent by the client. // This can be useful when a handler supports an entire directory tree. #define NNG_OPT_WS_REQUEST_URI "ws:request-uri" @@ -1141,7 +1151,8 @@ NNG_DECL nng_err nng_stream_get_int(nng_stream *, const char *, int *); NNG_DECL nng_err nng_stream_get_ms(nng_stream *, const char *, nng_duration *); NNG_DECL nng_err nng_stream_get_size(nng_stream *, const char *, size_t *); NNG_DECL nng_err nng_stream_get_uint64(nng_stream *, const char *, uint64_t *); -NNG_DECL nng_err nng_stream_get_string(nng_stream *, const char *, char **); +NNG_DECL nng_err nng_stream_get_string( + nng_stream *, const char *, const char **); NNG_DECL nng_err nng_stream_get_addr( nng_stream *, const char *, nng_sockaddr *); NNG_DECL nng_err nng_stream_peer_cert(nng_stream *, nng_tls_cert **); @@ -1164,7 +1175,7 @@ NNG_DECL nng_err nng_stream_dialer_get_size( NNG_DECL nng_err nng_stream_dialer_get_uint64( nng_stream_dialer *, const char *, uint64_t *); NNG_DECL nng_err nng_stream_dialer_get_string( - nng_stream_dialer *, const char *, char **); + nng_stream_dialer *, const char *, const char **); NNG_DECL nng_err nng_stream_dialer_get_addr( nng_stream_dialer *, const char *, nng_sockaddr *); NNG_DECL nng_err nng_stream_dialer_set_bool( @@ -1211,7 +1222,7 @@ NNG_DECL nng_err nng_stream_listener_get_size( NNG_DECL nng_err nng_stream_listener_get_uint64( nng_stream_listener *, const char *, uint64_t *); NNG_DECL nng_err nng_stream_listener_get_string( - nng_stream_listener *, const char *, char **); + nng_stream_listener *, const char *, const char **); NNG_DECL nng_err nng_stream_listener_get_addr( nng_stream_listener *, const char *, nng_sockaddr *); NNG_DECL nng_err nng_stream_listener_set_bool( diff --git a/src/core/options.c b/src/core/options.c index 23e63d1c..f3843c0d 100644 --- a/src/core/options.c +++ b/src/core/options.c @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2025 Staysail Systems, Inc. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> // Copyright 2018 Devolutions <info@devolutions.net> // @@ -9,9 +9,9 @@ // found online at https://opensource.org/licenses/MIT. // -#include "core/defs.h" -#include "core/nng_impl.h" +#include "defs.h" #include "nng/nng.h" +#include "nng_impl.h" #include <stdio.h> #include <string.h> @@ -174,16 +174,12 @@ nni_copyout_sockaddr( nng_err nni_copyout_str(const char *str, void *dst, size_t *szp, nni_type t) { - char *s; NNI_ARG_UNUSED(szp); if (t != NNI_TYPE_STRING) { return (NNG_EBADTYPE); } - if ((s = nni_strdup(str)) == NULL) { - return (NNG_ENOMEM); - } - *(char **) dst = s; + *(const char **) dst = str; return (NNG_OK); } diff --git a/src/core/stream.c b/src/core/stream.c index 61a8a3ba..572f28d1 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -368,7 +368,7 @@ nng_stream_get_size(nng_stream *s, const char *n, size_t *v) } nng_err -nng_stream_get_string(nng_stream *s, const char *n, char **v) +nng_stream_get_string(nng_stream *s, const char *n, const char **v) { return (nni_stream_get(s, n, v, NULL, NNI_TYPE_STRING)); } @@ -413,7 +413,8 @@ nng_stream_dialer_get_size(nng_stream_dialer *d, const char *n, size_t *v) } nng_err -nng_stream_dialer_get_string(nng_stream_dialer *d, const char *n, char **v) +nng_stream_dialer_get_string( + nng_stream_dialer *d, const char *n, const char **v) { return (nni_stream_dialer_get(d, n, v, NULL, NNI_TYPE_STRING)); } @@ -456,7 +457,8 @@ nng_stream_listener_get_size(nng_stream_listener *l, const char *n, size_t *v) } nng_err -nng_stream_listener_get_string(nng_stream_listener *l, const char *n, char **v) +nng_stream_listener_get_string( + nng_stream_listener *l, const char *n, const char **v) { return (nni_stream_listener_get(l, n, v, NULL, NNI_TYPE_STRING)); } @@ -780,7 +780,7 @@ nng_dialer_get_size(nng_dialer id, const char *n, size_t *v) } int -nng_dialer_get_string(nng_dialer id, const char *n, char **v) +nng_dialer_get_string(nng_dialer id, const char *n, const char **v) { return (dialer_get(id, n, v, NULL, NNI_TYPE_STRING)); } @@ -909,7 +909,7 @@ nng_listener_get_size(nng_listener id, const char *n, size_t *v) } int -nng_listener_get_string(nng_listener id, const char *n, char **v) +nng_listener_get_string(nng_listener id, const char *n, const char **v) { return (listener_get(id, n, v, NULL, NNI_TYPE_STRING)); } @@ -1358,12 +1358,72 @@ nng_pipe_get_size(nng_pipe id, const char *n, size_t *v) } nng_err -nng_pipe_get_string(nng_pipe id, const char *n, char **v) +nng_pipe_get_string(nng_pipe id, const char *n, const char **v) { return (pipe_get(id, n, v, NULL, NNI_TYPE_STRING)); } nng_err +nng_pipe_get_strcpy(nng_pipe p, const char *n, char *buf, size_t len) +{ + nng_err rv; + nni_pipe *pipe; + const char *s; + + if ((rv = nni_pipe_find(&pipe, p.id)) != 0) { + return (rv); + } + rv = nni_pipe_getopt(pipe, n, &s, NULL, NNI_TYPE_STRING); + if (rv == NNG_OK) { + if (nni_strlcpy(buf, s != NULL ? s : "", len) >= len) { + rv = NNG_ENOSPC; + } + } + nni_pipe_rele(pipe); + return (rv); +} + +nng_err +nng_pipe_get_strdup(nng_pipe p, const char *n, char **v) +{ + nng_err rv; + nni_pipe *pipe; + const char *s; + + if ((rv = nni_pipe_find(&pipe, p.id)) != 0) { + return (rv); + } + rv = nni_pipe_getopt(pipe, n, &s, NULL, NNI_TYPE_STRING); + if (rv == NNG_OK) { + if (s == NULL) { + *v = NULL; + } else if ((*v = nni_strdup(s)) == NULL) { + rv = NNG_ENOMEM; + } + } + nni_pipe_rele(pipe); + return (rv); +} + +nng_err +nng_pipe_get_strlen(nng_pipe p, const char *n, size_t *len) +{ + nng_err rv; + nni_pipe *pipe; + const char *s; + + if ((rv = nni_pipe_find(&pipe, p.id)) != 0) { + return (rv); + } + rv = nni_pipe_getopt(pipe, n, &s, NULL, NNI_TYPE_STRING); + if (rv == NNG_OK) { + *len = s == NULL ? 0 : strlen(s); + } + nni_pipe_rele(pipe); + return (rv); +} + +nng_err nng_pipe_get_ms(nng_pipe id, const char *n, nng_duration *v) { return (pipe_get(id, n, v, NULL, NNI_TYPE_DURATION)); diff --git a/src/supplemental/websocket/websocket_test.c b/src/supplemental/websocket/websocket_test.c index 98bcf658..cb502ef4 100644 --- a/src/supplemental/websocket/websocket_test.c +++ b/src/supplemental/websocket/websocket_test.c @@ -13,7 +13,7 @@ #include "sha1.h" -#include <nuts.h> +#include "../../testing/nuts.h" void test_websocket_wildcard(void) @@ -138,7 +138,7 @@ test_websocket_conn_props(void) nng_stream *c2 = NULL; char uri[64]; bool on; - char *str; + const char *str; uint16_t port; int rv; @@ -208,18 +208,14 @@ test_websocket_conn_props(void) NUTS_PASS( nng_stream_get_string(c1, NNG_OPT_WS_HEADER "NNG-Req", &str)); NUTS_MATCH(str, "True"); - nng_strfree(str); NUTS_PASS( nng_stream_get_string(c2, NNG_OPT_WS_HEADER "NNG-Rep", &str)); NUTS_MATCH(str, "True"); - nng_strfree(str); NUTS_PASS(nng_stream_get_string( c1, NNG_OPT_WS_HEADER "Sec-WebSocket-Version", &str)); - NUTS_TRUE(str != NULL); - NUTS_TRUE(strcmp(str, "13") == 0); - nng_strfree(str); + NUTS_MATCH(str, "13"); nng_stream_close(c1); nng_stream_close(c2); |
