From ae6cd215afdb312b22827cd1abbbbe6a6164703f Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 3 Nov 2024 12:07:27 -0800 Subject: 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. --- src/core/socket.c | 270 +++++++++++++++++++++++------------------------------- 1 file changed, 113 insertions(+), 157 deletions(-) (limited to 'src') 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 @@ -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 @@ -160,6 +178,43 @@ sock_get_sendtimeo(void *s, void *buf, size_t *szp, nni_type t) return (nni_copyout_ms(SOCK(s)->s_sndtimeo, buf, szp, 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) { @@ -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); } -- cgit v1.2.3-70-g09d2