aboutsummaryrefslogtreecommitdiff
path: root/src/core/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/socket.c')
-rw-r--r--src/core/socket.c337
1 files changed, 254 insertions, 83 deletions
diff --git a/src/core/socket.c b/src/core/socket.c
index 03ae5a9d..dc305b48 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -18,9 +18,15 @@ static nni_list nni_sock_list;
static nni_idhash *nni_sock_hash;
static nni_mtx nni_sock_lk;
+typedef struct nni_socket_option {
+ const char *so_name;
+ int (*so_getopt)(nni_sock *, void *, size_t *);
+ int (*so_setopt)(nni_sock *, const void *, size_t);
+} nni_socket_option;
+
typedef struct nni_sockopt {
nni_list_node node;
- int opt;
+ char * name;
size_t sz;
void * data;
} nni_sockopt;
@@ -71,9 +77,158 @@ struct nni_socket {
nni_notifyfd s_recv_fd;
};
+#if 0
+if (opt == nni_optid_reconnmint) {
+ rv = nni_setopt_usec(&s->s_reconn, val, size);
+} else if (opt == nni_optid_reconnmaxt) {
+ rv = nni_setopt_usec(&s->s_reconnmax, val, size);
+} else if (opt == nni_optid_recvtimeo) {
+ rv = nni_setopt_usec(&s->s_rcvtimeo, val, size);
+} else if (opt == nni_optid_sendtimeo) {
+ rv = nni_setopt_usec(&s->s_sndtimeo, val, size);
+} else if (opt == nni_optid_sendbuf) {
+ rv = nni_setopt_buf(s->s_uwq, val, size);
+} else if (opt == nni_optid_recvbuf) {
+ rv = nni_setopt_buf(s->s_urq, val, size);
+} else if ((opt == nni_optid_sendfd) || (opt == nni_optid_recvfd) ||
+ (opt == nni_optid_locaddr) || (opt == nni_optid_remaddr)) {
+ // these options can be read, but cannot be set
+ rv = NNG_EINVAL;
+#endif
+
+static int
+nni_sock_getopt_sendfd(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_fd(s, &s->s_send_fd, NNG_EV_CAN_SND, buf, szp));
+}
+
+static int
+nni_sock_getopt_recvfd(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_fd(s, &s->s_recv_fd, NNG_EV_CAN_RCV, buf, szp));
+}
+
+static int
+nni_sock_setopt_recvtimeo(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_usec(&s->s_rcvtimeo, buf, sz));
+}
+
+static int
+nni_sock_getopt_recvtimeo(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_usec(s->s_rcvtimeo, buf, szp));
+}
+
+static int
+nni_sock_setopt_sendtimeo(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_usec(&s->s_sndtimeo, buf, sz));
+}
+
+static int
+nni_sock_getopt_sendtimeo(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_usec(s->s_sndtimeo, buf, szp));
+}
+
+static int
+nni_sock_setopt_reconnmint(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_usec(&s->s_reconn, buf, sz));
+}
+
+static int
+nni_sock_getopt_reconnmint(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_usec(s->s_reconn, buf, szp));
+}
+
+static int
+nni_sock_setopt_reconnmaxt(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_usec(&s->s_reconnmax, buf, sz));
+}
+
+static int
+nni_sock_getopt_reconnmaxt(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_usec(s->s_reconnmax, buf, szp));
+}
+
+static int
+nni_sock_setopt_recvbuf(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_buf(s->s_urq, buf, sz));
+}
+
+static int
+nni_sock_getopt_recvbuf(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_buf(s->s_urq, buf, szp));
+}
+
+static int
+nni_sock_setopt_sendbuf(nni_sock *s, const void *buf, size_t sz)
+{
+ return (nni_setopt_buf(s->s_uwq, buf, sz));
+}
+
+static int
+nni_sock_getopt_sendbuf(nni_sock *s, void *buf, size_t *szp)
+{
+ return (nni_getopt_buf(s->s_uwq, buf, szp));
+}
+
+static const nni_socket_option nni_sock_options[] = {
+ {
+ .so_name = NNG_OPT_RECVTIMEO,
+ .so_getopt = nni_sock_getopt_recvtimeo,
+ .so_setopt = nni_sock_setopt_recvtimeo,
+ },
+ {
+ .so_name = NNG_OPT_SENDTIMEO,
+ .so_getopt = nni_sock_getopt_sendtimeo,
+ .so_setopt = nni_sock_setopt_sendtimeo,
+ },
+ {
+ .so_name = NNG_OPT_RECVFD,
+ .so_getopt = nni_sock_getopt_recvfd,
+ .so_setopt = NULL,
+ },
+ {
+ .so_name = NNG_OPT_SENDFD,
+ .so_getopt = nni_sock_getopt_sendfd,
+ .so_setopt = NULL,
+ },
+ {
+ .so_name = NNG_OPT_RECVBUF,
+ .so_getopt = nni_sock_getopt_recvbuf,
+ .so_setopt = nni_sock_setopt_recvbuf,
+ },
+ {
+ .so_name = NNG_OPT_SENDBUF,
+ .so_getopt = nni_sock_getopt_sendbuf,
+ .so_setopt = nni_sock_setopt_sendbuf,
+ },
+ {
+ .so_name = NNG_OPT_RECONNMINT,
+ .so_getopt = nni_sock_getopt_reconnmint,
+ .so_setopt = nni_sock_setopt_reconnmint,
+ },
+ {
+ .so_name = NNG_OPT_RECONNMAXT,
+ .so_getopt = nni_sock_getopt_reconnmaxt,
+ .so_setopt = nni_sock_setopt_reconnmaxt,
+ },
+ // terminate list
+ { NULL, NULL, NULL },
+};
+
static void
nni_free_opt(nni_sockopt *opt)
{
+ nni_strfree(opt->name);
nni_free(opt->data, opt->sz);
NNI_FREE_STRUCT(opt);
}
@@ -366,17 +521,17 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto)
if (((rv = nni_msgq_init(&s->s_uwq, 0)) != 0) ||
((rv = nni_msgq_init(&s->s_urq, 0)) != 0) ||
((rv = s->s_sock_ops.sock_init(&s->s_data, s)) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_linger, &s->s_linger,
+ ((rv = nni_sock_setopt(s, NNG_OPT_LINGER, &s->s_linger,
sizeof(nni_duration))) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_sendtimeo, &s->s_sndtimeo,
+ ((rv = nni_sock_setopt(s, NNG_OPT_SENDTIMEO, &s->s_sndtimeo,
sizeof(nni_duration))) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_recvtimeo, &s->s_rcvtimeo,
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECVTIMEO, &s->s_rcvtimeo,
sizeof(nni_duration))) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_reconnmint, &s->s_reconn,
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECONNMINT, &s->s_reconn,
sizeof(nni_duration))) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_reconnmaxt, &s->s_reconnmax,
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECONNMAXT, &s->s_reconnmax,
sizeof(nni_duration))) != 0) ||
- ((rv = nni_sock_setopt(s, nng_optid_recvmaxsz, &s->s_rcvmaxsz,
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECVMAXSZ, &s->s_rcvmaxsz,
sizeof(size_t))) != 0)) {
nni_sock_destroy(s);
return (rv);
@@ -749,14 +904,16 @@ nni_sock_ep_add(nni_sock *s, nni_ep *ep)
nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
+
NNI_LIST_FOREACH (&s->s_options, sopt) {
int rv;
- rv = nni_ep_setopt(ep, sopt->opt, sopt->data, sopt->sz, 0);
+ rv = nni_ep_setopt(ep, sopt->name, sopt->data, sopt->sz);
if ((rv != 0) && (rv != NNG_ENOTSUP)) {
nni_mtx_unlock(&s->s_mx);
return (rv);
}
}
+
nni_list_append(&s->s_eps, ep);
nni_mtx_unlock(&s->s_mx);
return (0);
@@ -788,41 +945,48 @@ nni_sock_senderr(nni_sock *sock, int err)
}
int
-nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
+nni_sock_setopt(nni_sock *s, const char *name, const void *val, size_t size)
{
- int rv = NNG_ENOTSUP;
- nni_ep * ep;
- int commits = 0;
- nni_sockopt *optv;
- nni_sockopt *oldv = NULL;
+ int rv = NNG_ENOTSUP;
+ nni_ep * ep;
+ int commits = 0;
+ nni_sockopt * optv;
+ nni_sockopt * oldv = NULL;
+ const nni_socket_option * sso;
+ const nni_proto_sock_option *pso;
nni_mtx_lock(&s->s_mx);
if (s->s_closing) {
nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
- if (s->s_sock_ops.sock_setopt != NULL) {
- rv = s->s_sock_ops.sock_setopt(s->s_data, opt, val, size);
- if (rv != NNG_ENOTSUP) {
+
+ // Protocol options.
+ for (pso = s->s_sock_ops.sock_options; pso->pso_name != NULL; pso++) {
+ if (strcmp(pso->pso_name, name) != 0) {
+ continue;
+ }
+ if (pso->pso_setopt == NULL) {
nni_mtx_unlock(&s->s_mx);
- return (rv);
+ return (NNG_EREADONLY);
}
+ rv = pso->pso_setopt(s->s_data, val, size);
+ nni_mtx_unlock(&s->s_mx);
+ return (rv);
}
- // Some options do not go down to transports. Handle them
- // directly.
- if (opt == nng_optid_reconnmint) {
- rv = nni_setopt_usec(&s->s_reconn, val, size);
- } else if (opt == nng_optid_reconnmaxt) {
- rv = nni_setopt_usec(&s->s_reconnmax, val, size);
- } else if (opt == nng_optid_sendbuf) {
- rv = nni_setopt_buf(s->s_uwq, val, size);
- } else if (opt == nng_optid_recvbuf) {
- rv = nni_setopt_buf(s->s_urq, val, size);
- } else if ((opt == nng_optid_sendfd) || (opt == nng_optid_recvfd) ||
- (opt == nng_optid_locaddr) || (opt == nng_optid_remaddr)) {
- // these options can be read, but cannot be set
- rv = NNG_EINVAL;
+ // Some options do not go down to transports. Handle them directly.
+ for (sso = nni_sock_options; sso->so_name != NULL; sso++) {
+ if (strcmp(sso->so_name, name) != 0) {
+ continue;
+ }
+ if (sso->so_setopt == NULL) {
+ nni_mtx_unlock(&s->s_mx);
+ return (NNG_EREADONLY);
+ }
+ rv = sso->so_setopt(s, val, size);
+ nni_mtx_unlock(&s->s_mx);
+ return (rv);
}
nni_mtx_unlock(&s->s_mx);
@@ -832,20 +996,16 @@ nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
return (rv);
}
- // Validation of transport options. This is stateless, so
- // transports should not fail to set an option later if they
- // passed it here.
- rv = nni_tran_chkopt(opt, val, size);
+ // Validation of transport options. This is stateless, so transports
+ // should not fail to set an option later if they passed it here.
+ rv = nni_tran_chkopt(name, val, size);
// Also check a few generic things. We do this if no transport
- // check was found, or even if a transport rejected one of the
- // settings.
+ // was found, or even if a transport rejected one of the settings.
if ((rv == NNG_ENOTSUP) || (rv == 0)) {
- if ((opt == nng_optid_linger) ||
- (opt == nng_optid_sendtimeo) ||
- (opt == nng_optid_recvtimeo)) {
+ if ((strcmp(name, NNG_OPT_LINGER) == 0)) {
rv = nni_chkopt_usec(val, size);
- } else if (opt == nng_optid_recvmaxsz) {
+ } else if (strcmp(name, NNG_OPT_RECVMAXSZ) == 0) {
// just a sanity test on the size; it also ensures that
// a size can be set even with no transport configured.
rv = nni_chkopt_size(val, size, 0, NNI_MAXSZ);
@@ -864,14 +1024,18 @@ nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
NNI_FREE_STRUCT(optv);
return (NNG_ENOMEM);
}
+ if ((optv->name = nni_strdup(name)) == NULL) {
+ nni_free(optv->data, size);
+ NNI_FREE_STRUCT(optv);
+ return (NNG_ENOMEM);
+ }
memcpy(optv->data, val, size);
- optv->opt = opt;
- optv->sz = size;
+ optv->sz = size;
NNI_LIST_NODE_INIT(&optv->node);
nni_mtx_lock(&s->s_mx);
NNI_LIST_FOREACH (&s->s_options, oldv) {
- if (oldv->opt == opt) {
+ if (strcmp(oldv->name, name) == 0) {
if ((oldv->sz != size) ||
(memcmp(oldv->data, val, size) != 0)) {
break;
@@ -889,7 +1053,7 @@ nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
// important that transport wide checks properly pre-validate.
NNI_LIST_FOREACH (&s->s_eps, ep) {
int x;
- x = nni_ep_setopt(ep, opt, optv->data, size, 0);
+ x = nni_ep_setopt(ep, optv->name, optv->data, size);
if (x != NNG_ENOTSUP) {
if ((rv = x) != 0) {
nni_mtx_unlock(&s->s_mx);
@@ -903,12 +1067,8 @@ nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
// behavior, we save a local value. Note that the transport
// will already have had a chance to veto this.
- if (opt == nng_optid_linger) {
+ if (strcmp(name, NNG_OPT_LINGER) == 0) {
rv = nni_setopt_usec(&s->s_linger, val, size);
- } else if (opt == nng_optid_sendtimeo) {
- rv = nni_setopt_usec(&s->s_sndtimeo, val, size);
- } else if (opt == nng_optid_recvtimeo) {
- rv = nni_setopt_usec(&s->s_rcvtimeo, val, size);
}
if (rv == 0) {
@@ -931,52 +1091,63 @@ nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
}
int
-nni_sock_getopt(nni_sock *s, int opt, void *val, size_t *szp)
+nni_sock_getopt(nni_sock *s, const char *name, void *val, size_t *szp)
{
- int rv = NNG_ENOTSUP;
- nni_sockopt *sopt;
+ int rv = NNG_ENOTSUP;
+ nni_sockopt * sopt;
+ int opt;
+ const nni_socket_option * sso;
+ const nni_proto_sock_option *pso;
+
+ opt = nni_option_lookup(name);
nni_mtx_lock(&s->s_mx);
if (s->s_closing) {
nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
- if (s->s_sock_ops.sock_getopt != NULL) {
- rv = s->s_sock_ops.sock_getopt(s->s_data, opt, val, szp);
- if (rv != NNG_ENOTSUP) {
+
+ // Protocol specific options.
+ for (pso = s->s_sock_ops.sock_options; pso->pso_name != NULL; pso++) {
+ if (strcmp(name, pso->pso_name) != 0) {
+ continue;
+ }
+ if (pso->pso_getopt == NULL) {
nni_mtx_unlock(&s->s_mx);
- return (rv);
+ return (NNG_EWRITEONLY);
}
+ rv = pso->pso_getopt(s->s_data, val, szp);
+ nni_mtx_unlock(&s->s_mx);
+ return (rv);
}
- // Options that are handled by socket core, and never
- // passed down.
- if (opt == nng_optid_sendbuf) {
- rv = nni_getopt_buf(s->s_uwq, val, szp);
- } else if (opt == nng_optid_recvbuf) {
- rv = nni_getopt_buf(s->s_urq, val, szp);
- } else if (opt == nng_optid_sendfd) {
- rv = nni_getopt_fd(s, &s->s_send_fd, NNG_EV_CAN_SND, val, szp);
- } else if (opt == nng_optid_recvfd) {
- rv = nni_getopt_fd(s, &s->s_recv_fd, NNG_EV_CAN_RCV, val, szp);
- } else if (opt == nng_optid_reconnmint) {
- rv = nni_getopt_usec(s->s_reconn, val, szp);
- } else if (opt == nng_optid_reconnmaxt) {
- rv = nni_getopt_usec(s->s_reconnmax, val, szp);
- } else {
- NNI_LIST_FOREACH (&s->s_options, sopt) {
- if (sopt->opt == opt) {
- size_t sz = sopt->sz;
- if (sopt->sz > *szp) {
- sz = *szp;
- }
- *szp = sopt->sz;
- memcpy(val, sopt->data, sz);
- rv = 0;
- break;
+ // Options that are handled by socket core, and never passed down.
+ for (sso = nni_sock_options; sso->so_name != NULL; sso++) {
+ if (strcmp(name, sso->so_name) != 0) {
+ continue;
+ }
+ if (sso->so_getopt == NULL) {
+ nni_mtx_unlock(&s->s_mx);
+ return (NNG_EWRITEONLY);
+ }
+ rv = sso->so_getopt(s, val, szp);
+ nni_mtx_unlock(&s->s_mx);
+ return (rv);
+ }
+
+ NNI_LIST_FOREACH (&s->s_options, sopt) {
+ if (strcmp(sopt->name, name) == 0) {
+ size_t sz = sopt->sz;
+ 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);
}