diff options
| author | Garrett D'Amore <garrett@damore.org> | 2024-11-03 12:07:27 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-11-03 12:07:27 -0800 |
| commit | ae6cd215afdb312b22827cd1abbbbe6a6164703f (patch) | |
| tree | 1de810075d4663987ced88962c437c49f983232c | |
| parent | 49076237cc0b82e7007535e789f3fadc19a18c45 (diff) | |
| download | nng-ae6cd215afdb312b22827cd1abbbbe6a6164703f.tar.gz nng-ae6cd215afdb312b22827cd1abbbbe6a6164703f.tar.bz2 nng-ae6cd215afdb312b22827cd1abbbbe6a6164703f.zip | |
Socket option handling clean ups for endpoints.
The framework for saving and replaying socket options was left
over, and should not be used. But we do need to send the initial
socket options to endpoints when creating them, so we have support
for that in a cleaner fashion that does not require memory allocations.
| -rw-r--r-- | docs/ref/migrate/nng1.md | 14 | ||||
| -rw-r--r-- | src/core/socket.c | 270 |
2 files changed, 127 insertions, 157 deletions
diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index f44deb7c..4b96725d 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -90,6 +90,20 @@ options must be set on the endpoint (dialer or listener) using the appropriate to allocate and configure the endpoint before attaching it to the socket. This will also afford a much more fine-grained level of control over transport options. +The following options are copied from the socket when creating a dialer or listener, +but afterwards will not be changed on the dialer or listener if the socket +changes. It is recommended to set them properly on the socket before +creating dialers or listeners, or set them explicitly on the dialer or listener +directly: + +- `NNG_OPT_RECONNMINT` +- `NNG_OPT_RECONNMAXT` +- `NNG_OPT_RECVMAXSZ` + +The latter option is a hint for transports and intended to facilitate early +detection (and possibly avoidance of extra allocations) of oversize messages, +before bringing them into the socket itself. + ## Socket Options The `NNG_OPT_PROTO`, `NNG_OPT_PROTONAME`, `NNG_OPT_PEER`, and `NNG_OPT_PEERNAME` options diff --git a/src/core/socket.c b/src/core/socket.c index c911fa40..2b94e573 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -8,11 +8,12 @@ // found online at https://opensource.org/licenses/MIT. // +#include "core/defs.h" #include "core/nng_impl.h" +#include "core/options.h" #include "core/pipe.h" #include "list.h" #include "nng/nng.h" -#include "nng/supplemental/tls/tls.h" #include "sockimpl.h" #include <stdio.h> @@ -33,19 +34,37 @@ struct nni_ctx { nng_duration c_rcvtimeo; }; -typedef struct nni_sockopt { - nni_list_node node; - char *name; - nni_type typ; - size_t sz; - void *data; -} nni_sockopt; - typedef struct nni_sock_pipe_cb { nng_pipe_cb cb_fn; void *cb_arg; } nni_sock_pipe_cb; +// This struct is used in array form for options +// that we pass down to endpoints when they get added. +// The list is fixed, and so we have to set it up. +typedef struct { + const char *eo_name; + nni_type eo_type; +} nni_ep_option; + +static const nni_ep_option ep_options[] = { + { + .eo_name = NNG_OPT_RECONNMINT, + .eo_type = NNI_TYPE_DURATION, + }, + { + .eo_name = NNG_OPT_RECONNMAXT, + .eo_type = NNI_TYPE_DURATION, + }, + { + .eo_name = NNG_OPT_RECVMAXSZ, + .eo_type = NNI_TYPE_SIZE, + }, + { + .eo_name = NULL, + }, +}; + struct nni_socket { nni_list_node s_node; nni_mtx s_mx; @@ -74,7 +93,6 @@ struct nni_socket { nni_duration s_reconn; // reconnect time nni_duration s_reconnmax; // max reconnect time size_t s_rcvmaxsz; // max receive size - nni_list s_options; // opts not handled by sock/proto char s_name[64]; // socket name (legacy compat) nni_list s_listeners; // active listeners @@ -161,6 +179,43 @@ sock_get_sendtimeo(void *s, void *buf, size_t *szp, nni_type t) } static int +sock_set_reconnmint(void *s, const void *buf, size_t sz, nni_type t) +{ + return (nni_copyin_ms(&SOCK(s)->s_reconn, buf, sz, t)); +} + +static int +sock_get_reconnmint(void *s, void *buf, size_t *szp, nni_type t) +{ + return (nni_copyout_ms(SOCK(s)->s_reconn, buf, szp, t)); +} + +static int +sock_set_reconnmaxt(void *s, const void *buf, size_t sz, nni_type t) +{ + return (nni_copyin_ms(&SOCK(s)->s_reconnmax, buf, sz, t)); +} + +static int +sock_get_reconnmaxt(void *s, void *buf, size_t *szp, nni_type t) +{ + return (nni_copyout_ms(SOCK(s)->s_reconnmax, buf, szp, t)); +} + +static int +sock_set_recvmaxsz(void *s, const void *buf, size_t sz, nni_type t) +{ + return ( + nni_copyin_size(&SOCK(s)->s_rcvmaxsz, buf, sz, 0, NNI_MAXSZ, t)); +} + +static int +sock_get_recvmaxsz(void *s, void *buf, size_t *szp, nni_type t) +{ + return (nni_copyout_size(SOCK(s)->s_rcvmaxsz, buf, szp, t)); +} + +static int sock_set_recvbuf(void *s, const void *buf, size_t sz, nni_type t) { int len; @@ -247,24 +302,27 @@ static const nni_option sock_options[] = { .o_get = sock_get_sockname, .o_set = sock_set_sockname, }, + { + .o_name = NNG_OPT_RECONNMINT, + .o_get = sock_get_reconnmint, + .o_set = sock_set_reconnmint, + }, + { + .o_name = NNG_OPT_RECONNMAXT, + .o_get = sock_get_reconnmaxt, + .o_set = sock_set_reconnmaxt, + }, + { + .o_name = NNG_OPT_RECVMAXSZ, + .o_get = sock_get_recvmaxsz, + .o_set = sock_set_recvmaxsz, + }, // terminate list { .o_name = NULL, }, }; -static void -nni_free_opt(nni_sockopt *opt) -{ - if ((strcmp(opt->name, NNG_OPT_TLS_CONFIG) == 0) && - (opt->sz == sizeof(nng_tls_config *))) { - nng_tls_config_free(*(nng_tls_config **) (opt->data)); - } - nni_strfree(opt->name); - nni_free(opt->data, opt->sz); - NNI_FREE_STRUCT(opt); -} - uint32_t nni_sock_id(nni_sock *s) { @@ -457,8 +515,6 @@ sock_stats_init(nni_sock *s) static void sock_destroy(nni_sock *s) { - nni_sockopt *sopt; - #ifdef NNG_ENABLE_STATS nni_stat_unregister(&s->st_root); #endif @@ -468,13 +524,6 @@ sock_destroy(nni_sock *s) s->s_sock_ops.sock_fini(s->s_data); } - nni_mtx_lock(&s->s_mx); - while ((sopt = nni_list_first(&s->s_options)) != NULL) { - nni_list_remove(&s->s_options, sopt); - nni_free_opt(sopt); - } - nni_mtx_unlock(&s->s_mx); - nni_msgq_fini(s->s_urq); nni_msgq_fini(s->s_uwq); nni_cv_fini(&s->s_close_cv); @@ -520,7 +569,6 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto) NNI_ASSERT(s->s_sock_ops.sock_close != NULL); NNI_LIST_NODE_INIT(&s->s_node); - NNI_LIST_INIT(&s->s_options, nni_sockopt, node); NNI_LIST_INIT(&s->s_ctxs, nni_ctx, c_node); NNI_LIST_INIT(&s->s_pipes, nni_pipe, p_sock_node); NNI_LIST_INIT(&s->s_listeners, nni_listener, l_node); @@ -548,10 +596,6 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto) sizeof(nni_duration), NNI_TYPE_DURATION); (void) nni_sock_setopt(s, NNG_OPT_RECVTIMEO, &s->s_rcvtimeo, sizeof(nni_duration), NNI_TYPE_DURATION); - (void) nni_sock_setopt(s, NNG_OPT_RECONNMINT, &s->s_reconn, - sizeof(nni_duration), NNI_TYPE_DURATION); - (void) nni_sock_setopt(s, NNG_OPT_RECONNMAXT, &s->s_reconnmax, - sizeof(nni_duration), NNI_TYPE_DURATION); (void) nni_sock_setopt(s, NNG_OPT_RECVMAXSZ, &s->s_rcvmaxsz, sizeof(size_t), NNI_TYPE_SIZE); @@ -846,14 +890,28 @@ nni_sock_proto_data(nni_sock *sock) int nni_sock_add_listener(nni_sock *s, nni_listener *l) { - nni_sockopt *sopt; - int rv; + int rv; // grab a hold on the listener for the socket if ((rv = nni_listener_hold(l)) != 0) { return (rv); } + // copy initial values for some options from socket + for (int i = 0; ep_options[i].eo_name != NULL; i++) { + uint64_t val; // big enough + const nni_ep_option *o = &ep_options[i]; + rv = nni_sock_getopt(s, o->eo_name, &val, NULL, o->eo_type); + if (rv == 0) { + rv = nni_listener_setopt( + l, o->eo_name, &val, 0, o->eo_type); + } + if (rv != 0 && rv != NNG_ENOTSUP) { + nni_listener_rele(l); + return (rv); + } + } + nni_mtx_lock(&s->s_mx); if (s->s_closing) { nni_mtx_unlock(&s->s_mx); @@ -861,16 +919,6 @@ nni_sock_add_listener(nni_sock *s, nni_listener *l) return (NNG_ECLOSED); } - NNI_LIST_FOREACH (&s->s_options, sopt) { - int rv; - rv = nni_listener_setopt( - l, sopt->name, sopt->data, sopt->sz, sopt->typ); - if ((rv != 0) && (rv != NNG_ENOTSUP)) { - nni_mtx_unlock(&s->s_mx); - return (rv); - } - } - nni_list_append(&s->s_listeners, l); #ifdef NNG_ENABLE_STATS @@ -897,13 +945,26 @@ nni_sock_remove_listener(nni_listener *l) int nni_sock_add_dialer(nni_sock *s, nni_dialer *d) { - nni_sockopt *sopt; - int rv; + int rv; // grab a hold on the dialer for the socket if ((rv = nni_dialer_hold(d)) != 0) { return (rv); } + // copy initial values for some options from socket + for (int i = 0; ep_options[i].eo_name != NULL; i++) { + uint64_t val; // big enough + const nni_ep_option *o = &ep_options[i]; + rv = nni_sock_getopt(s, o->eo_name, &val, NULL, o->eo_type); + if (rv == 0) { + rv = nni_dialer_setopt( + d, o->eo_name, &val, 0, o->eo_type); + } + if (rv != 0 && rv != NNG_ENOTSUP) { + nni_dialer_rele(d); + return (rv); + } + } nni_mtx_lock(&s->s_mx); if (s->s_closing) { @@ -912,16 +973,6 @@ nni_sock_add_dialer(nni_sock *s, nni_dialer *d) return (NNG_ECLOSED); } - NNI_LIST_FOREACH (&s->s_options, sopt) { - int rv; - rv = nni_dialer_setopt( - d, sopt->name, sopt->data, sopt->sz, sopt->typ); - if ((rv != 0) && (rv != NNG_ENOTSUP)) { - nni_mtx_unlock(&s->s_mx); - return (rv); - } - } - nni_list_append(&s->s_dialers, d); #ifdef NNG_ENABLE_STATS @@ -949,9 +1000,7 @@ int nni_sock_setopt( nni_sock *s, const char *name, const void *v, size_t sz, nni_type t) { - int rv; - nni_sockopt *optv; - nni_sockopt *oldv = NULL; + int rv; nni_mtx_lock(&s->s_mx); if (s->s_closing) { @@ -968,80 +1017,9 @@ nni_sock_setopt( return (rv); } - // Some options do not go down to transports. Handle them directly. rv = nni_setopt(sock_options, name, s, v, sz, t); - if (rv != NNG_ENOTSUP) { - nni_mtx_unlock(&s->s_mx); - return (rv); - } nni_mtx_unlock(&s->s_mx); - // Validation of generic and transport options. - // NOTE: Setting transport options via socket is deprecated. - // These options should be set on the endpoint to which they apply. - if ((strcmp(name, NNG_OPT_RECONNMINT) == 0) || - (strcmp(name, NNG_OPT_RECONNMAXT) == 0)) { - if ((rv = nni_copyin_ms(NULL, v, sz, t)) != 0) { - return (rv); - } - - } else if (strcmp(name, NNG_OPT_RECVMAXSZ) == 0) { - size_t scratch; - if ((rv = nni_copyin_size(&scratch, v, sz, 0, NNI_MAXSZ, t)) != - 0) { - return (rv); - } - } - - // Prepare a copy of the socket option. - if ((optv = NNI_ALLOC_STRUCT(optv)) == NULL) { - return (NNG_ENOMEM); - } - if ((optv->data = nni_alloc(sz)) == NULL) { - NNI_FREE_STRUCT(optv); - return (NNG_ENOMEM); - } - if ((optv->name = nni_strdup(name)) == NULL) { - nni_free(optv->data, sz); - NNI_FREE_STRUCT(optv); - return (NNG_ENOMEM); - } - memcpy(optv->data, v, sz); - optv->sz = sz; - optv->typ = t; - NNI_LIST_NODE_INIT(&optv->node); - - nni_mtx_lock(&s->s_mx); - NNI_LIST_FOREACH (&s->s_options, oldv) { - if (strcmp(oldv->name, name) == 0) { - if ((oldv->sz != sz) || - (memcmp(oldv->data, v, sz) != 0)) { - break; - } - - // The values are the same. This is a no-op. - nni_mtx_unlock(&s->s_mx); - nni_free_opt(optv); - return (0); - } - } - - if (rv == 0) { - // Remove and toss the old value; we are using a new one. - if (oldv != NULL) { - nni_list_remove(&s->s_options, oldv); - nni_free_opt(oldv); - } - - // Insert our new value. This permits it to be - // compared against later, and for new endpoints to - // automatically receive these values, - nni_list_append(&s->s_options, optv); - } else { - nni_free_opt(optv); - } - - nni_mtx_unlock(&s->s_mx); return (rv); } @@ -1049,8 +1027,7 @@ int nni_sock_getopt( nni_sock *s, const char *name, void *val, size_t *szp, nni_type t) { - int rv; - nni_sockopt *sopt; + int rv; nni_mtx_lock(&s->s_mx); if (s->s_closing) { @@ -1075,27 +1052,6 @@ nni_sock_getopt( return (rv); } - NNI_LIST_FOREACH (&s->s_options, sopt) { - if (strcmp(sopt->name, name) == 0) { - size_t sz = sopt->sz; - - if (t != sopt->typ) { - nni_mtx_unlock(&s->s_mx); - return (NNG_EBADTYPE); - } - - if (szp != NULL) { - if (sopt->sz > *szp) { - sz = *szp; - } - *szp = sopt->sz; - } - memcpy(val, sopt->data, sz); - rv = 0; - break; - } - } - nni_mtx_unlock(&s->s_mx); return (rv); } |
