Skip to content

Commit

Permalink
Implement dynamic option numbering.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gdamore committed Aug 24, 2017
1 parent 7074c5c commit 8ad2967
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 33 deletions.
2 changes: 2 additions & 0 deletions src/core/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) ||
Expand All @@ -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();
Expand Down
157 changes: 157 additions & 0 deletions src/core/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
7 changes: 7 additions & 0 deletions src/core/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 12 additions & 0 deletions src/nng.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 7 additions & 1 deletion src/nng.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
46 changes: 26 additions & 20 deletions src/protocol/pair/pair_v1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down
Loading

0 comments on commit 8ad2967

Please sign in to comment.