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 | |
| 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')
| -rw-r--r-- | src/core/defs.h | 23 | ||||
| -rw-r--r-- | src/core/device.c | 8 | ||||
| -rw-r--r-- | src/core/endpt.c | 64 | ||||
| -rw-r--r-- | src/core/endpt.h | 38 | ||||
| -rw-r--r-- | src/core/options.c | 41 | ||||
| -rw-r--r-- | src/core/options.h | 10 | ||||
| -rw-r--r-- | src/core/pipe.c | 26 | ||||
| -rw-r--r-- | src/core/pipe.h | 2 | ||||
| -rw-r--r-- | src/core/protocol.h | 13 | ||||
| -rw-r--r-- | src/core/socket.c | 337 | ||||
| -rw-r--r-- | src/core/socket.h | 8 | ||||
| -rw-r--r-- | src/core/transport.c | 26 | ||||
| -rw-r--r-- | src/core/transport.h | 56 |
13 files changed, 439 insertions, 213 deletions
diff --git a/src/core/defs.h b/src/core/defs.h index 4d8e6ffb..ff02b28b 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -32,16 +32,19 @@ typedef struct nng_event nni_event; typedef struct nng_notify nni_notify; // These are our own names. -typedef struct nni_socket nni_sock; -typedef struct nni_ep nni_ep; -typedef struct nni_pipe nni_pipe; -typedef struct nni_tran nni_tran; -typedef struct nni_tran_ep nni_tran_ep; -typedef struct nni_tran_pipe nni_tran_pipe; - -typedef struct nni_proto_sock_ops nni_proto_sock_ops; -typedef struct nni_proto_pipe_ops nni_proto_pipe_ops; -typedef struct nni_proto nni_proto; +typedef struct nni_socket nni_sock; +typedef struct nni_ep nni_ep; +typedef struct nni_pipe nni_pipe; +typedef struct nni_tran nni_tran; +typedef struct nni_tran_ep nni_tran_ep; +typedef struct nni_tran_ep_option nni_tran_ep_option; +typedef struct nni_tran_pipe nni_tran_pipe; +typedef struct nni_tran_pipe_option nni_tran_pipe_option; + +typedef struct nni_proto_sock_ops nni_proto_sock_ops; +typedef struct nni_proto_pipe_ops nni_proto_pipe_ops; +typedef struct nni_proto_sock_option nni_proto_sock_option; +typedef struct nni_proto nni_proto; typedef struct nni_plat_mtx nni_mtx; typedef struct nni_plat_cv nni_cv; diff --git a/src/core/device.c b/src/core/device.c index e7140664..9161e2f0 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -91,10 +91,10 @@ nni_device(nni_sock *sock1, nni_sock *sock2) // No timeouts. sz = sizeof(never); - if ((nni_sock_setopt(sock1, nng_optid_recvtimeo, &never, sz) != 0) || - (nni_sock_setopt(sock2, nng_optid_recvtimeo, &never, sz) != 0) || - (nni_sock_setopt(sock1, nng_optid_sendtimeo, &never, sz) != 0) || - (nni_sock_setopt(sock2, nng_optid_sendtimeo, &never, sz) != 0)) { + if ((nni_sock_setopt(sock1, NNG_OPT_RECVTIMEO, &never, sz) != 0) || + (nni_sock_setopt(sock2, NNG_OPT_RECVTIMEO, &never, sz) != 0) || + (nni_sock_setopt(sock1, NNG_OPT_SENDTIMEO, &never, sz) != 0) || + (nni_sock_setopt(sock2, NNG_OPT_SENDTIMEO, &never, sz) != 0)) { // This should never happen. rv = NNG_EINVAL; goto out; diff --git a/src/core/endpt.c b/src/core/endpt.c index a99041ab..e6216ba3 100644 --- a/src/core/endpt.c +++ b/src/core/endpt.c @@ -480,7 +480,7 @@ nni_ep_acc_cb(void *arg) break; case NNG_ECLOSED: case NNG_ECANCELED: - // Canceled or closed, no furhter action. + // Canceled or closed, no further action. break; case NNG_ECONNABORTED: case NNG_ECONNRESET: @@ -587,38 +587,62 @@ nni_ep_pipe_remove(nni_ep *ep, nni_pipe *pipe) } int -nni_ep_setopt(nni_ep *ep, int opt, const void *val, size_t sz, int check) +nni_ep_setopt(nni_ep *ep, const char *name, const void *val, size_t sz) { - int rv; + nni_tran_ep_option *eo; - if (ep->ep_ops.ep_setopt == NULL) { - return (NNG_ENOTSUP); + if (strcmp(name, NNG_OPT_URL) == 0) { + return (NNG_EREADONLY); } - nni_mtx_lock(&ep->ep_mtx); - if (check && ep->ep_started) { + + for (eo = ep->ep_ops.ep_options; eo && eo->eo_name; eo++) { + int rv; + + if (strcmp(eo->eo_name, name) != 0) { + continue; + } + if (eo->eo_setopt == NULL) { + return (NNG_EREADONLY); + } + nni_mtx_lock(&ep->ep_mtx); + // XXX: Consider removing this test. + if (ep->ep_started) { + nni_mtx_unlock(&ep->ep_mtx); + return (NNG_ESTATE); + } + rv = eo->eo_setopt(ep->ep_data, val, sz); nni_mtx_unlock(&ep->ep_mtx); - return (NNG_ESTATE); + return (rv); } - rv = ep->ep_ops.ep_setopt(ep->ep_data, opt, val, sz); - nni_mtx_unlock(&ep->ep_mtx); - return (rv); + + // XXX: socket fallback + return (NNG_ENOTSUP); } int -nni_ep_getopt(nni_ep *ep, int opt, void *valp, size_t *szp) +nni_ep_getopt(nni_ep *ep, const char *name, void *valp, size_t *szp) { - int rv; + nni_tran_ep_option *eo; - if (opt == nng_optid_url) { + if (strcmp(name, NNG_OPT_URL) == 0) { return (nni_getopt_str(ep->ep_url, valp, szp)); } - if (ep->ep_ops.ep_getopt == NULL) { - return (NNG_ENOTSUP); + + for (eo = ep->ep_ops.ep_options; eo && eo->eo_name; eo++) { + int rv; + if (strcmp(eo->eo_name, name) != 0) { + continue; + } + if (eo->eo_getopt == NULL) { + return (NNG_EWRITEONLY); + } + nni_mtx_lock(&ep->ep_mtx); + rv = eo->eo_getopt(ep->ep_data, valp, szp); + nni_mtx_unlock(&ep->ep_mtx); + return (rv); } - nni_mtx_lock(&ep->ep_mtx); - rv = ep->ep_ops.ep_getopt(ep->ep_data, opt, valp, szp); - nni_mtx_unlock(&ep->ep_mtx); - return (rv); + + return (nni_sock_getopt(ep->ep_sock, name, valp, szp)); } void diff --git a/src/core/endpt.h b/src/core/endpt.h index 161c030f..d12d661f 100644 --- a/src/core/endpt.h +++ b/src/core/endpt.h @@ -11,25 +11,25 @@ #ifndef CORE_ENDPT_H #define CORE_ENDPT_H -extern int nni_ep_sys_init(void); -extern void nni_ep_sys_fini(void); -extern nni_tran * nni_ep_tran(nni_ep *); -extern nni_sock * nni_ep_sock(nni_ep *); -extern int nni_ep_find(nni_ep **, uint32_t); -extern int nni_ep_hold(nni_ep *); -extern void nni_ep_rele(nni_ep *); -extern uint32_t nni_ep_id(nni_ep *); -extern int nni_ep_create_dialer(nni_ep **, nni_sock *, const char *); -extern int nni_ep_create_listener(nni_ep **, nni_sock *, const char *); -extern void nni_ep_stop(nni_ep *); -extern int nni_ep_shutdown(nni_ep *); -extern void nni_ep_close(nni_ep *); -extern int nni_ep_dial(nni_ep *, int); -extern int nni_ep_listen(nni_ep *, int); -extern void nni_ep_list_init(nni_list *); -extern int nni_ep_setopt(nni_ep *, int, const void *, size_t, int); -extern int nni_ep_getopt(nni_ep *, int, void *, size_t *); -extern int nni_ep_pipe_add(nni_ep *ep, nni_pipe *); +extern int nni_ep_sys_init(void); +extern void nni_ep_sys_fini(void); +extern nni_tran *nni_ep_tran(nni_ep *); +extern nni_sock *nni_ep_sock(nni_ep *); +extern int nni_ep_find(nni_ep **, uint32_t); +extern int nni_ep_hold(nni_ep *); +extern void nni_ep_rele(nni_ep *); +extern uint32_t nni_ep_id(nni_ep *); +extern int nni_ep_create_dialer(nni_ep **, nni_sock *, const char *); +extern int nni_ep_create_listener(nni_ep **, nni_sock *, const char *); +extern void nni_ep_stop(nni_ep *); +extern int nni_ep_shutdown(nni_ep *); +extern void nni_ep_close(nni_ep *); +extern int nni_ep_dial(nni_ep *, int); +extern int nni_ep_listen(nni_ep *, int); +extern void nni_ep_list_init(nni_list *); +extern int nni_ep_setopt(nni_ep *, const char *, const void *, size_t); +extern int nni_ep_getopt(nni_ep *, const char *, void *, size_t *); +extern int nni_ep_pipe_add(nni_ep *ep, nni_pipe *); extern void nni_ep_pipe_remove(nni_ep *, nni_pipe *); extern const char *nni_ep_url(nni_ep *); diff --git a/src/core/options.c b/src/core/options.c index b7934a06..e9a79f35 100644 --- a/src/core/options.c +++ b/src/core/options.c @@ -344,23 +344,6 @@ nni_option_lookup(const char *name) return (id); } -const char * -nni_option_name(int id) -{ - nni_option *opt; - const char *name = NULL; - - nni_mtx_lock(&nni_option_lk); - NNI_LIST_FOREACH (&nni_options, opt) { - if (id == opt->o_id) { - name = opt->o_name; - break; - } - } - nni_mtx_unlock(&nni_option_lk); - return (name); -} - int nni_option_register(const char *name, int *idp) { @@ -390,6 +373,15 @@ nni_option_sys_fini(void) nni_option_nextid = 0; } +int nni_optid_raw; +int nni_optid_recvmaxsz; +int nni_optid_maxttl; +int nni_optid_protocol; +int nni_optid_transport; +int nni_optid_locaddr; +int nni_optid_remaddr; +int nni_optid_surveyor_surveytime; + int nni_option_sys_init(void) { @@ -398,28 +390,15 @@ nni_option_sys_init(void) nni_option_nextid = 0x10000; int rv; -#define OPT_REGISTER(o) nni_option_register(nng_opt_##o, &nng_optid_##o) +#define OPT_REGISTER(o) nni_option_register(nng_opt_##o, &nni_optid_##o) // Register our well-known options. if (((rv = OPT_REGISTER(raw)) != 0) || - ((rv = OPT_REGISTER(linger)) != 0) || - ((rv = OPT_REGISTER(recvbuf)) != 0) || - ((rv = OPT_REGISTER(sendbuf)) != 0) || - ((rv = OPT_REGISTER(recvtimeo)) != 0) || - ((rv = OPT_REGISTER(sendtimeo)) != 0) || - ((rv = OPT_REGISTER(reconnmint)) != 0) || - ((rv = OPT_REGISTER(reconnmaxt)) != 0) || ((rv = OPT_REGISTER(recvmaxsz)) != 0) || ((rv = OPT_REGISTER(maxttl)) != 0) || ((rv = OPT_REGISTER(protocol)) != 0) || ((rv = OPT_REGISTER(transport)) != 0) || ((rv = OPT_REGISTER(locaddr)) != 0) || ((rv = OPT_REGISTER(remaddr)) != 0) || - ((rv = OPT_REGISTER(recvfd)) != 0) || - ((rv = OPT_REGISTER(sendfd)) != 0) || - ((rv = OPT_REGISTER(url)) != 0) || - ((rv = OPT_REGISTER(req_resendtime)) != 0) || - ((rv = OPT_REGISTER(sub_subscribe)) != 0) || - ((rv = OPT_REGISTER(sub_unsubscribe)) != 0) || ((rv = OPT_REGISTER(surveyor_surveytime)) != 0)) { nni_option_sys_fini(); return (rv); diff --git a/src/core/options.h b/src/core/options.h index 64036db1..418a5d00 100644 --- a/src/core/options.h +++ b/src/core/options.h @@ -72,4 +72,14 @@ extern const char *nni_option_name(int); extern int nni_option_sys_init(void); extern void nni_option_sys_fini(void); +extern int nni_optid_raw; +extern int nni_optid_recvmaxsz; +extern int nni_optid_maxttl; +extern int nni_optid_protocol; +extern int nni_optid_transport; +extern int nni_optid_locaddr; +extern int nni_optid_remaddr; +extern int nni_optid_req_resendtime; +extern int nni_optid_surveyor_surveytime; + #endif // CORE_OPTIONS_H diff --git a/src/core/pipe.c b/src/core/pipe.c index edc8c15d..7351997a 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -10,6 +10,8 @@ #include "core/nng_impl.h" +#include <string.h> + // This file contains functions relating to pipes. // // Operations on pipes (to the transport) are generally blocking operations, @@ -281,8 +283,7 @@ nni_pipe_create(nni_ep *ep, void *tdata) rv = nni_idhash_alloc(nni_pipes, &p->p_id, p); nni_mtx_unlock(&nni_pipe_lk); - if ((rv != 0) || - ((rv = nni_ep_pipe_add(ep, p)) != 0) || + if ((rv != 0) || ((rv = nni_ep_pipe_add(ep, p)) != 0) || ((rv = nni_sock_pipe_add(sock, p)) != 0)) { nni_pipe_destroy(p); } @@ -291,21 +292,18 @@ nni_pipe_create(nni_ep *ep, void *tdata) } int -nni_pipe_getopt(nni_pipe *p, int opt, void *val, size_t *szp) +nni_pipe_getopt(nni_pipe *p, const char *name, void *val, size_t *szp) { - int rv = NNG_ENOTSUP; + nni_tran_pipe_option *po; - if (opt == nng_optid_url) { - return (nni_getopt_str(p->p_url, val, szp)); - } - if (p->p_tran_ops.p_getopt != NULL) { - rv = p->p_tran_ops.p_getopt(p->p_tran_data, opt, val, szp); - } - if (rv == NNG_ENOTSUP) { - // Maybe its a generic socket option? - rv = nni_sock_getopt(p->p_sock, opt, val, szp); + for (po = p->p_tran_ops.p_options; po && po->po_name; po++) { + if (strcmp(po->po_name, name) != 0) { + continue; + } + return (po->po_getopt(p->p_tran_data, val, szp)); } - return (rv); + // Maybe the endpoint knows? + return (nni_ep_getopt(p->p_ep, name, val, szp)); } void diff --git a/src/core/pipe.h b/src/core/pipe.h index bb55a8cd..54629810 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -57,7 +57,7 @@ extern void nni_pipe_start(nni_pipe *); extern uint16_t nni_pipe_proto(nni_pipe *); extern uint16_t nni_pipe_peer(nni_pipe *); -extern int nni_pipe_getopt(nni_pipe *, int, void *, size_t *sizep); +extern int nni_pipe_getopt(nni_pipe *, const char *, void *, size_t *); // nni_pipe_get_proto_data gets the protocol private data set with the // nni_pipe_set_proto_data function. No locking is performed. diff --git a/src/core/protocol.h b/src/core/protocol.h index 9416b2bf..0c0d93ce 100644 --- a/src/core/protocol.h +++ b/src/core/protocol.h @@ -47,6 +47,12 @@ struct nni_proto_pipe_ops { void (*pipe_stop)(void *); }; +struct nni_proto_sock_option { + const char *pso_name; + int (*pso_getopt)(void *, void *, size_t *); + int (*pso_setopt)(void *, const void *, size_t); +}; + struct nni_proto_sock_ops { // sock_init creates the protocol instance, which will be stored on // the socket. This is run without the sock lock held, and allocates @@ -68,10 +74,6 @@ struct nni_proto_sock_ops { // it can signal the socket worker threads to exit. void (*sock_close)(void *); - // Option manipulation. These may be NULL. - int (*sock_setopt)(void *, int, const void *, size_t); - int (*sock_getopt)(void *, int, void *, size_t *); - // Receive filter. This may be NULL, but if it isn't, then // messages coming into the system are routed here just before being // delivered to the application. To drop the message, the prtocol @@ -81,6 +83,9 @@ struct nni_proto_sock_ops { // Send filter. This may be NULL, but if it isn't, then messages // here are filtered just after they come from the application. nni_msg *(*sock_sfilter)(void *, nni_msg *); + + // Options. Must not be NULL. Final entry should have NULL name. + nni_proto_sock_option *sock_options; }; typedef struct nni_proto_id { 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); } diff --git a/src/core/socket.h b/src/core/socket.h index 931fefac..850c4641 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -22,10 +22,10 @@ extern void nni_sock_closeall(void); extern int nni_sock_shutdown(nni_sock *); extern uint16_t nni_sock_proto(nni_sock *); extern uint16_t nni_sock_peer(nni_sock *); -extern int nni_sock_setopt(nni_sock *, int, const void *, size_t); -extern int nni_sock_getopt(nni_sock *, int, void *, size_t *); -extern int nni_sock_recvmsg(nni_sock *, nni_msg **, int); -extern int nni_sock_sendmsg(nni_sock *, nni_msg *, int); +extern int nni_sock_setopt(nni_sock *, const char *, const void *, size_t); +extern int nni_sock_getopt(nni_sock *, const char *, void *, size_t *); +extern int nni_sock_recvmsg(nni_sock *, nni_msg **, int); +extern int nni_sock_sendmsg(nni_sock *, nni_msg *, int); extern uint32_t nni_sock_id(nni_sock *); extern void nni_sock_lock(nni_sock *); diff --git a/src/core/transport.c b/src/core/transport.c index eead861b..2697ce74 100644 --- a/src/core/transport.c +++ b/src/core/transport.c @@ -97,19 +97,29 @@ nni_tran_find(const char *addr) } int -nni_tran_chkopt(int o, const void *v, size_t sz) +nni_tran_chkopt(const char *name, const void *v, size_t sz) { nni_transport *t; int rv = NNG_ENOTSUP; + nni_mtx_lock(&nni_tran_lk); NNI_LIST_FOREACH (&nni_tran_list, t) { - int x; - if (t->t_tran.tran_chkopt == NULL) { - continue; - } - if ((x = t->t_tran.tran_chkopt(o, v, sz)) != NNG_ENOTSUP) { - if ((rv = x) != 0) { - break; + const nni_tran_ep * ep; + const nni_tran_ep_option *eo; + + // Generally we look for endpoint options. + ep = t->t_tran.tran_ep; + for (eo = ep->ep_options; eo && eo->eo_name != NULL; eo++) { + if (strcmp(name, eo->eo_name) != 0) { + continue; + } + if (eo->eo_setopt == NULL) { + nni_mtx_unlock(&nni_tran_lk); + return (NNG_EREADONLY); + } + if ((rv = eo->eo_setopt(NULL, v, sz)) != 0) { + nni_mtx_unlock(&nni_tran_lk); + return (rv); } } } diff --git a/src/core/transport.h b/src/core/transport.h index 2891d8a4..b82e2c92 100644 --- a/src/core/transport.h +++ b/src/core/transport.h @@ -29,11 +29,6 @@ struct nni_tran { // tran_pipe links our pipe-specific operations. const nni_tran_pipe *tran_pipe; - // tran_chkopt, if not NULL, is used to validate that the - // option data presented is valid. This allows an option to - // be set on a socket, even if no endpoints are configured. - int (*tran_chkopt)(int, const void *, size_t); - // tran_init, if not NULL, is called once during library // initialization. int (*tran_init)(void); @@ -54,10 +49,31 @@ struct nni_tran { #define NNI_TRANSPORT_V0 0x54520000 #define NNI_TRANSPORT_VERSION NNI_TRANSPORT_V0 +// Endpoint option handlers. +struct nni_tran_ep_option { + // eo_name is the name of the option. + const char *eo_name; + + // eo_getopt retrieves the value of the option. + int (*eo_getopt)(void *, void *, size_t *); + + // eo_set sets the value of the option. If the first argument + // (the endpoint) is NULL, then no actual set operation should be + // performed, but the option should be sanity tested for presence + // and size. (This permits the core to validate that an option + // is reasonable and be set even before endpoints are created.) + int (*eo_setopt)(void *, const void *, size_t); +}; + // Endpoint operations are called by the socket in a protocol-independent // fashion. The socket makes individual calls, which are expected to block -// if appropriate (except for destroy). Endpoints are unable to call back -// into the socket, to prevent recusive entry and deadlock. +// if appropriate (except for destroy), or run asynchronously if an aio +// is provided. Endpoints are unable to call back into the socket, to prevent +// recusive entry and deadlock. +// +// For a given endpoint, the framework holds a lock so that each entry +// point is run exclusively of the others. (Transports must still guard +// against any asynchronous operations they manage themselves, though.) struct nni_tran_ep { // ep_init creates a vanilla endpoint. The value created is // used for the first argument for all other endpoint functions. @@ -86,11 +102,20 @@ struct nni_tran_ep { // not affect pipes that have already been created. void (*ep_close)(void *); - // ep_setopt sets an endpoint (transport-specific) option. - int (*ep_setopt)(void *, int, const void *, size_t); + // ep_options is an array of endpoint options. The final element must + // have a NULL name. If this member is NULL, then no transport specific + // options are available. + nni_tran_ep_option *ep_options; +}; + +// Pipe option handlers. We only have get for pipes; once a pipe is created +// no options may be set on it. +struct nni_tran_pipe_option { + // po_name is the name of the option. + const char *po_name; - // ep_getopt gets an endpoint (transport-specific) option. - int (*ep_getopt)(void *, int, void *, size_t *); + // po_getopt retrieves the value of the option. + int (*po_getopt)(void *, void *, size_t *); }; // Pipe operations are entry points called by the socket. These may be called @@ -132,15 +157,16 @@ struct nni_tran_pipe { // transport specific manner is appropriate. uint16_t (*p_peer)(void *); - // p_getopt gets an pipe (transport-specific) property. These values - // may not be changed once the pipe is created. - int (*p_getopt)(void *, int, void *, size_t *); + // p_options is an array of pipe options. The final element must have + // a NULL name. If this member is NULL, then no transport specific + // options are available. + nni_tran_pipe_option *p_options; }; // These APIs are used by the framework internally, and not for use by // transport implementations. extern nni_tran *nni_tran_find(const char *); -extern int nni_tran_chkopt(int, const void *, size_t); +extern int nni_tran_chkopt(const char *, const void *, size_t); extern int nni_tran_sys_init(void); extern void nni_tran_sys_fini(void); extern int nni_tran_register(const nni_tran *); |
