aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-08-23 11:23:22 -0700
committerGarrett D'Amore <garrett@damore.org>2017-08-23 21:14:12 -0700
commit8ad296769192cf4628710ac0b228be2aca6d8dad (patch)
treeedd6240a63cc3b2a7e6206e1cc07b5c5edb9f1bf
parent7074c5c50936308d1ef58be4ce1ca5e776e4c8cb (diff)
downloadnng-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.c2
-rw-r--r--src/core/options.c157
-rw-r--r--src/core/options.h7
-rw-r--r--src/nng.c12
-rw-r--r--src/nng.h8
-rw-r--r--src/protocol/pair/pair_v1.c46
-rw-r--r--tests/pair1.c49
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
diff --git a/src/nng.c b/src/nng.c
index 2cd1b3a5..191c83fb 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -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)
diff --git a/src/nng.h b/src/nng.h
index 568347b3..e7d7fe2f 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -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;