aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-11-03 12:07:27 -0800
committerGarrett D'Amore <garrett@damore.org>2024-11-03 12:07:27 -0800
commitae6cd215afdb312b22827cd1abbbbe6a6164703f (patch)
tree1de810075d4663987ced88962c437c49f983232c
parent49076237cc0b82e7007535e789f3fadc19a18c45 (diff)
downloadnng-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.md14
-rw-r--r--src/core/socket.c270
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);
}