diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-08-23 11:23:22 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-08-23 21:14:12 -0700 |
| commit | 8ad296769192cf4628710ac0b228be2aca6d8dad (patch) | |
| tree | edd6240a63cc3b2a7e6206e1cc07b5c5edb9f1bf | |
| parent | 7074c5c50936308d1ef58be4ce1ca5e776e4c8cb (diff) | |
| download | nng-8ad296769192cf4628710ac0b228be2aca6d8dad.tar.gz nng-8ad296769192cf4628710ac0b228be2aca6d8dad.tar.bz2 nng-8ad296769192cf4628710ac0b228be2aca6d8dad.zip | |
Implement dynamic option numbering.
This permits option numbers to be allocated based on string name.
Eventually all the option values will be replaced with option
names. This will facilitate transports (ZeroTier) that may need
further options.
| -rw-r--r-- | src/core/init.c | 2 | ||||
| -rw-r--r-- | src/core/options.c | 157 | ||||
| -rw-r--r-- | src/core/options.h | 7 | ||||
| -rw-r--r-- | src/nng.c | 12 | ||||
| -rw-r--r-- | src/nng.h | 8 | ||||
| -rw-r--r-- | src/protocol/pair/pair_v1.c | 46 | ||||
| -rw-r--r-- | tests/pair1.c | 49 |
7 files changed, 248 insertions, 33 deletions
diff --git a/src/core/init.c b/src/core/init.c index 4025c0f4..54c72c5e 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -21,6 +21,7 @@ nni_init_helper(void) ((rv = nni_timer_sys_init()) != 0) || ((rv = nni_aio_sys_init()) != 0) || ((rv = nni_random_sys_init()) != 0) || + ((rv = nni_option_sys_init()) != 0) || ((rv = nni_sock_sys_init()) != 0) || ((rv = nni_ep_sys_init()) != 0) || ((rv = nni_pipe_sys_init()) != 0) || @@ -43,6 +44,7 @@ nni_fini(void) nni_pipe_sys_fini(); nni_ep_sys_fini(); nni_sock_sys_fini(); + nni_option_sys_fini(); nni_random_sys_fini(); nni_aio_sys_fini(); nni_timer_sys_fini(); diff --git a/src/core/options.c b/src/core/options.c index ecfa437e..55797218 100644 --- a/src/core/options.c +++ b/src/core/options.c @@ -10,8 +10,22 @@ #include "core/nng_impl.h" +#include <stdio.h> #include <string.h> +// Dynamic options. + +typedef struct nni_option nni_option; +struct nni_option { + nni_list_node o_link; + char * o_name; + int o_id; +}; + +static nni_mtx nni_option_lk; +static nni_list nni_options; +static int nni_option_nextid; + int nni_chkopt_usec(const void *v, size_t sz) { @@ -241,3 +255,146 @@ nni_getopt_fd(nni_sock *s, nni_notifyfd *fd, int mask, void *val, size_t *szp) memcpy(val, &fd->sn_rfd, sizeof(int)); return (0); } + +// nni_option_set_id sets the id for an option, if not already done so. +// (Some options have hard coded values that end-user may depend upon.) +// If the ID passed in is negative, then a new ID is allocated dynamically. +static int +nni_option_set_id(const char *name, int id) +{ + nni_option *opt; + int len; + nni_mtx_lock(&nni_option_lk); + NNI_LIST_FOREACH (&nni_options, opt) { + if (strcmp(name, opt->o_name) == 0) { + nni_mtx_unlock(&nni_option_lk); + return (0); + } + } + if ((opt = NNI_ALLOC_STRUCT(opt)) == NULL) { + nni_mtx_unlock(&nni_option_lk); + return (NNG_ENOMEM); + } + len = strlen(name) + 1; + if ((opt->o_name = nni_alloc(len)) == NULL) { + nni_mtx_unlock(&nni_option_lk); + NNI_FREE_STRUCT(opt); + return (NNG_ENOMEM); + } + (void) snprintf(opt->o_name, len, "%s", name); + if (id < 0) { + id = nni_option_nextid++; + } + opt->o_id = id; + nni_list_append(&nni_options, opt); + nni_mtx_unlock(&nni_option_lk); + return (0); +} + +int +nni_option_lookup(const char *name) +{ + nni_option *opt; + int id = -1; + + nni_mtx_lock(&nni_option_lk); + NNI_LIST_FOREACH (&nni_options, opt) { + if (strcmp(name, opt->o_name) == 0) { + id = opt->o_id; + break; + } + } + nni_mtx_unlock(&nni_option_lk); + 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) +{ + int id; + int rv; + + // Note that if the id was already in use, we will + // wind up leaving a gap in the ID space. That should + // be inconsequential. + if ((rv = nni_option_set_id(name, -1)) != 0) { + return (rv); + } + *idp = nni_option_lookup(name); + return (0); +} + +int +nni_option_sys_init(void) +{ + nni_mtx_init(&nni_option_lk); + NNI_LIST_INIT(&nni_options, nni_option, o_link); + nni_option_nextid = 0x10000; + int rv; + + // Register our well-known options. + if (((rv = nni_option_set_id("raw", NNG_OPT_RAW)) != 0) || + ((rv = nni_option_set_id("linger", NNG_OPT_LINGER)) != 0) || + ((rv = nni_option_set_id("recv-buf", NNG_OPT_RCVBUF)) != 0) || + ((rv = nni_option_set_id("send-buf", NNG_OPT_SNDBUF)) != 0) || + ((rv = nni_option_set_id("recv-timeout", NNG_OPT_RCVTIMEO)) != + 0) || + ((rv = nni_option_set_id("send-timeout", NNG_OPT_SNDTIMEO)) != + 0) || + ((rv = nni_option_set_id("reconnect-time", NNG_OPT_RECONN_TIME)) != + 0) || + ((rv = nni_option_set_id( + "reconnect-max-time", NNG_OPT_RECONN_MAXTIME)) != 0) || + ((rv = nni_option_set_id("recv-max-size", NNG_OPT_RCVMAXSZ)) != + 0) || + ((rv = nni_option_set_id("max-ttl", NNG_OPT_MAXTTL)) != 0) || + ((rv = nni_option_set_id("protocol", NNG_OPT_PROTOCOL)) != 0) || + ((rv = nni_option_set_id("subscribe", NNG_OPT_SUBSCRIBE)) != 0) || + ((rv = nni_option_set_id("unsubscribe", NNG_OPT_UNSUBSCRIBE)) != + 0) || + ((rv = nni_option_set_id("survey-time", NNG_OPT_SURVEYTIME)) != + 0) || + ((rv = nni_option_set_id("resend-time", NNG_OPT_RESENDTIME)) != + 0) || + ((rv = nni_option_set_id("transport", NNG_OPT_TRANSPORT)) != 0) || + ((rv = nni_option_set_id("local-addr", NNG_OPT_LOCALADDR)) != 0) || + ((rv = nni_option_set_id("remote-addr", NNG_OPT_REMOTEADDR)) != + 0) || + ((rv = nni_option_set_id("recv-fd", NNG_OPT_RCVFD)) != 0) || + ((rv = nni_option_set_id("send-fd", NNG_OPT_SNDFD)) != 0)) { + nni_option_sys_fini(); + return (rv); + } + return (0); +} + +void +nni_option_sys_fini(void) +{ + if (nni_option_nextid != 0) { + nni_option *opt; + while ((opt = nni_list_first(&nni_options)) != NULL) { + nni_list_remove(&nni_options, opt); + nni_free(opt->o_name, strlen(opt->o_name) + 1); + NNI_FREE_STRUCT(opt); + } + } + nni_option_nextid = 0; +}
\ No newline at end of file diff --git a/src/core/options.h b/src/core/options.h index 4b29c4b6..03a6e37e 100644 --- a/src/core/options.h +++ b/src/core/options.h @@ -56,4 +56,11 @@ extern int nni_chkopt_usec(const void *, size_t); extern int nni_chkopt_int(const void *, size_t, int, int); extern int nni_chkopt_size(const void *, size_t, size_t, size_t); +extern int nni_option_register(const char *, int *); +extern int nni_option_lookup(const char *); +extern const char *nni_option_name(int); + +extern int nni_option_sys_init(void); +extern void nni_option_sys_fini(void); + #endif // CORE_OPTIONS_H @@ -878,6 +878,18 @@ nng_msg_getopt(nng_msg *msg, int opt, void *ptr, size_t *szp) return (nni_msg_getopt(msg, opt, ptr, szp)); } +int +nng_option_lookup(const char *name) +{ + return (nni_option_lookup(name)); +} + +const char * +nng_option_name(int id) +{ + return (nni_option_name(id)); +} + #if 0 int nng_snapshot_create(nng_socket sock, nng_snapshot **snapp) @@ -309,6 +309,13 @@ NNG_DECL void nng_msg_set_pipe(nng_msg *, nng_pipe); NNG_DECL nng_pipe nng_msg_get_pipe(const nng_msg *); NNG_DECL int nng_msg_getopt(nng_msg *, int, void *, size_t *); +// Lookup an option by name. This returns either the option value, +// or -1 if the option name is unknown. +NNG_DECL int nng_option_lookup(const char *); + +// Lookup an option name by id. Returns NULL if not known. +NNG_DECL const char *nng_option_name(int); + // Pipe API. Generally pipes are only "observable" to applications, but // we do permit an application to close a pipe. This can be useful, for // example during a connection notification, to disconnect a pipe that @@ -417,7 +424,6 @@ enum nng_opt_enum { NNG_OPT_REMOTEADDR = NNG_OPT_SOCKET(17), NNG_OPT_RCVFD = NNG_OPT_SOCKET(18), NNG_OPT_SNDFD = NNG_OPT_SOCKET(19), - NNG_OPT_POLYAMOROUS = NNG_OPT_SOCKET(20), }; // XXX: TBD: priorities, socket names, ipv4only diff --git a/src/protocol/pair/pair_v1.c b/src/protocol/pair/pair_v1.c index 2b8a9120..09543830 100644 --- a/src/protocol/pair/pair_v1.c +++ b/src/protocol/pair/pair_v1.c @@ -69,6 +69,7 @@ pair1_sock_init(void **sp, nni_sock *nsock) { pair1_sock *s; int rv; + int poly; if ((s = NNI_ALLOC_STRUCT(s)) == NULL) { return (NNG_ENOMEM); @@ -83,6 +84,11 @@ pair1_sock_init(void **sp, nni_sock *nsock) nni_aio_init(&s->aio_getq, pair1_sock_getq_cb, s); nni_mtx_init(&s->mtx); + if ((rv = nni_option_register("polyamorous", &poly)) != 0) { + pair1_sock_fini(s); + return (rv); + } + s->nsock = nsock; s->raw = 0; s->poly = 0; @@ -393,30 +399,30 @@ pair1_sock_setopt(void *arg, int opt, const void *buf, size_t sz) pair1_sock *s = arg; int rv; - nni_mtx_lock(&s->mtx); - switch (opt) { - case NNG_OPT_RAW: + if (opt == nni_option_lookup("raw")) { + nni_mtx_lock(&s->mtx); if (s->started) { rv = NNG_ESTATE; } else { rv = nni_setopt_int(&s->raw, buf, sz, 0, 1); } - break; - case NNG_OPT_POLYAMOROUS: + nni_mtx_unlock(&s->mtx); + } else if (opt == nni_option_lookup("polyamorous")) { + nni_mtx_lock(&s->mtx); if (s->started) { rv = NNG_ESTATE; } else { rv = nni_setopt_int(&s->poly, buf, sz, 0, 1); } - break; - case NNG_OPT_MAXTTL: + nni_mtx_unlock(&s->mtx); + } else if (opt == nni_option_lookup("max-ttl")) { + nni_mtx_lock(&s->mtx); rv = nni_setopt_int(&s->ttl, buf, sz, 1, 255); - break; - default: + nni_mtx_unlock(&s->mtx); + } else { rv = NNG_ENOTSUP; } - nni_mtx_unlock(&s->mtx); return (rv); } @@ -426,21 +432,21 @@ pair1_sock_getopt(void *arg, int opt, void *buf, size_t *szp) pair1_sock *s = arg; int rv; - nni_mtx_lock(&s->mtx); - switch (opt) { - case NNG_OPT_RAW: + if (opt == nni_option_lookup("raw")) { + nni_mtx_lock(&s->mtx); rv = nni_getopt_int(&s->raw, buf, szp); - break; - case NNG_OPT_MAXTTL: + nni_mtx_unlock(&s->mtx); + } else if (opt == nni_option_lookup("max-ttl")) { + nni_mtx_lock(&s->mtx); rv = nni_getopt_int(&s->ttl, buf, szp); - break; - case NNG_OPT_POLYAMOROUS: + nni_mtx_unlock(&s->mtx); + } else if (opt == nni_option_lookup("polyamorous")) { + nni_mtx_lock(&s->mtx); rv = nni_getopt_int(&s->poly, buf, szp); - break; - default: + nni_mtx_unlock(&s->mtx); + } else { rv = NNG_ENOTSUP; } - nni_mtx_unlock(&s->mtx); return (rv); } diff --git a/tests/pair1.c b/tests/pair1.c index d160acdd..adb50c88 100644 --- a/tests/pair1.c +++ b/tests/pair1.c @@ -106,8 +106,13 @@ TestMain("PAIRv1 protocol", { int rv; int i; nng_msg *msg; + int poly; - So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == 0); + poly = nng_option_lookup("polyamorous"); + So(poly >= 0); + So(nng_option_name(poly) != NULL); + So(strcmp(nng_option_name(poly), "polyamorous") == 0); + So(nng_setopt_int(s1, poly, 1) == 0); So(nng_setopt_int(s1, NNG_OPT_RCVBUF, 1) == 0); So(nng_setopt_int(s1, NNG_OPT_SNDBUF, 1) == 0); @@ -155,14 +160,16 @@ TestMain("PAIRv1 protocol", { }); Convey("Cannot set polyamorous mode after connect", { + int poly; So(nng_listen(s1, addr, NULL, 0) == 0); So(nng_dial(c1, addr, NULL, 0) == 0); nng_usleep(100000); + poly = nng_option_lookup("polyamorous"); + So(poly >= 0); + So(nng_option_name(poly) != NULL); + So(strcmp(nng_option_name(poly), "polyamorous") == 0); - So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == - NNG_ESTATE); - So(nng_setopt_int(c1, NNG_OPT_POLYAMOROUS, 1) == - NNG_ESTATE); + So(nng_setopt_int(s1, poly, 1) == NNG_ESTATE); }); Convey("Monogamous raw mode works", { @@ -329,12 +336,18 @@ TestMain("PAIRv1 protocol", { int v; nng_pipe p1; nng_pipe p2; + int poly; - So(nng_getopt_int(s1, NNG_OPT_POLYAMOROUS, &v) == 0); + poly = nng_option_lookup("polyamorous"); + So(poly >= 0); + So(nng_option_name(poly) != NULL); + So(strcmp(nng_option_name(poly), "polyamorous") == 0); + + So(nng_getopt_int(s1, poly, &v) == 0); So(v == 0); - So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == 0); - So(nng_getopt_int(s1, NNG_OPT_POLYAMOROUS, &v) == 0); + So(nng_setopt_int(s1, poly, 1) == 0); + So(nng_getopt_int(s1, poly, &v) == 0); So(v == 1); So(nng_listen(s1, addr, NULL, 0) == 0); @@ -389,8 +402,14 @@ TestMain("PAIRv1 protocol", { Convey("Polyamorous default works", { nng_msg *msg; + int poly; + + poly = nng_option_lookup("polyamorous"); + So(poly >= 0); + So(nng_option_name(poly) != NULL); + So(strcmp(nng_option_name(poly), "polyamorous") == 0); - So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == 0); + So(nng_setopt_int(s1, poly, 1) == 0); So(nng_listen(s1, addr, NULL, 0) == 0); So(nng_dial(c1, addr, NULL, 0) == 0); @@ -421,12 +440,18 @@ TestMain("PAIRv1 protocol", { uint32_t hops; nng_pipe p1; nng_pipe p2; + int poly; + + poly = nng_option_lookup("polyamorous"); + So(poly >= 0); + So(nng_option_name(poly) != NULL); + So(strcmp(nng_option_name(poly), "polyamorous") == 0); - So(nng_getopt_int(s1, NNG_OPT_POLYAMOROUS, &v) == 0); + So(nng_getopt_int(s1, poly, &v) == 0); So(v == 0); - So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == 0); - So(nng_getopt_int(s1, NNG_OPT_POLYAMOROUS, &v) == 0); + So(nng_setopt_int(s1, poly, 1) == 0); + So(nng_getopt_int(s1, poly, &v) == 0); So(v == 1); v = 0; |
