diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-09-25 12:49:10 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-09-27 14:38:12 -0700 |
| commit | 64db0f085be0c9efc6dca8d9e72d3e5a47cb792e (patch) | |
| tree | 475520498d8ebe9e47e9785d8f9d209c87582400 /src/core/socket.c | |
| parent | 86a96e5bf1b207a8b1aa925e1d9f73ce834505b8 (diff) | |
| download | nng-64db0f085be0c9efc6dca8d9e72d3e5a47cb792e.tar.gz nng-64db0f085be0c9efc6dca8d9e72d3e5a47cb792e.tar.bz2 nng-64db0f085be0c9efc6dca8d9e72d3e5a47cb792e.zip | |
Refactor option handling APIs.
This makes the APIs use string keys, and largely eliminates the use of
integer option IDs altogether. The underlying registration for options
is also now a bit richer, letting protcols and transports declare the
actual options they use, rather than calling down into each entry point
carte blanche and relying on ENOTSUP.
This code may not be as fast as the integers was, but it is more intuitive,
easier to extend, and is not on any hot code paths. (If you're diddling
options on a hot code path you're doing something wrong.)
Diffstat (limited to 'src/core/socket.c')
| -rw-r--r-- | src/core/socket.c | 337 |
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); } |
