aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-08-17 23:57:09 -0700
committerGarrett D'Amore <garrett@damore.org>2017-08-18 01:57:35 -0700
commit446b150032f24c34644f0ab91ac6ab9206250865 (patch)
treee47b4e3812016716187201961c43b9e407a3ed50
parent76c1fc80c931b086493835d037245ebbb5f8d406 (diff)
downloadnng-446b150032f24c34644f0ab91ac6ab9206250865.tar.gz
nng-446b150032f24c34644f0ab91ac6ab9206250865.tar.bz2
nng-446b150032f24c34644f0ab91ac6ab9206250865.zip
Endpoint API completely implemented.
This supports creating listeners and dialers, managing options on them (though only a few options are supported at present), starting them and closing them, all independently.
-rw-r--r--src/core/endpt.c33
-rw-r--r--src/core/endpt.h2
-rw-r--r--src/core/options.c79
-rw-r--r--src/core/options.h7
-rw-r--r--src/core/pipe.c4
-rw-r--r--src/core/socket.c299
-rw-r--r--src/core/socket.h3
-rw-r--r--src/core/transport.c21
-rw-r--r--src/core/transport.h6
-rw-r--r--src/nng.c167
-rw-r--r--src/nng.h37
-rw-r--r--src/transport/ipc/ipc.c52
-rw-r--r--src/transport/tcp/tcp.c64
-rw-r--r--tests/sock.c192
14 files changed, 847 insertions, 119 deletions
diff --git a/src/core/endpt.c b/src/core/endpt.c
index 34debc0e..f90bd068 100644
--- a/src/core/endpt.c
+++ b/src/core/endpt.c
@@ -418,6 +418,7 @@ nni_ep_dial(nni_ep *ep, int flags)
}
if ((flags & NNG_FLAG_NONBLOCK) != 0) {
+ ep->ep_started = 1;
nni_ep_con_start(ep);
nni_mtx_unlock(&ep->ep_mtx);
return (0);
@@ -567,6 +568,38 @@ nni_ep_pipe_remove(nni_ep *ep, nni_pipe *pipe)
nni_mtx_unlock(&ep->ep_mtx);
}
+int
+nni_ep_setopt(nni_ep *ep, int opt, const void *val, size_t sz, int check)
+{
+ int rv;
+
+ if (ep->ep_ops.ep_setopt == NULL) {
+ return (NNG_ENOTSUP);
+ }
+ nni_mtx_lock(&ep->ep_mtx);
+ if (check && ep->ep_started) {
+ nni_mtx_unlock(&ep->ep_mtx);
+ return (NNG_ESTATE);
+ }
+ rv = ep->ep_ops.ep_setopt(ep->ep_data, opt, val, sz);
+ nni_mtx_unlock(&ep->ep_mtx);
+ return (rv);
+}
+
+int
+nni_ep_getopt(nni_ep *ep, int opt, void *valp, size_t *szp)
+{
+ int rv;
+
+ if (ep->ep_ops.ep_getopt == NULL) {
+ return (NNG_ENOTSUP);
+ }
+ 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);
+}
+
void
nni_ep_list_init(nni_list *list)
{
diff --git a/src/core/endpt.h b/src/core/endpt.h
index fbb10911..de058d4b 100644
--- a/src/core/endpt.h
+++ b/src/core/endpt.h
@@ -27,6 +27,8 @@ 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 void nni_ep_pipe_remove(nni_ep *, nni_pipe *);
diff --git a/src/core/options.c b/src/core/options.c
index b243b262..ecfa437e 100644
--- a/src/core/options.c
+++ b/src/core/options.c
@@ -13,57 +13,98 @@
#include <string.h>
int
-nni_setopt_usec(nni_duration *ptr, const void *val, size_t size)
+nni_chkopt_usec(const void *v, size_t sz)
+{
+ nni_duration val;
+ if (sz != sizeof(val)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&val, v, sz);
+ if (val < -1) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+int
+nni_chkopt_int(const void *v, size_t sz, int minv, int maxv)
+{
+ int val;
+ if (sz != sizeof(val)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&val, v, sz);
+ if ((val < minv) || (val > maxv)) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+int
+nni_chkopt_size(const void *v, size_t sz, size_t minv, size_t maxv)
+{
+ size_t val;
+ if (sz != sizeof(val)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&val, v, sz);
+ if ((val < minv) || (val > maxv)) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+int
+nni_setopt_usec(nni_duration *dp, const void *v, size_t sz)
{
nni_duration dur;
- if (size != sizeof(*ptr)) {
+ if (sz != sizeof(*dp)) {
return (NNG_EINVAL);
}
- memcpy(&dur, val, sizeof(dur));
+ memcpy(&dur, v, sizeof(dur));
if (dur < -1) {
return (NNG_EINVAL);
}
- *ptr = dur;
+ *dp = dur;
return (0);
}
int
-nni_setopt_int(int *ptr, const void *val, size_t size, int minval, int maxval)
+nni_setopt_int(int *ip, const void *v, size_t sz, int minv, int maxv)
{
- int v;
+ int i;
- if (size != sizeof(v)) {
+ if (sz != sizeof(i)) {
return (NNG_EINVAL);
}
- memcpy(&v, val, sizeof(v));
- if (v > maxval) {
+ memcpy(&i, v, sizeof(i));
+ if (i > maxv) {
return (NNG_EINVAL);
}
- if (v < minval) {
+ if (i < minv) {
return (NNG_EINVAL);
}
- *ptr = v;
+ *ip = i;
return (0);
}
int
-nni_setopt_size(
- size_t *ptr, const void *val, size_t size, size_t minval, size_t maxval)
+nni_setopt_size(size_t *sp, const void *v, size_t sz, size_t minv, size_t maxv)
{
- size_t v;
+ size_t val;
- if (size != sizeof(v)) {
+ if (sz != sizeof(val)) {
return (NNG_EINVAL);
}
- memcpy(&v, val, sizeof(v));
- if (v > maxval) {
+ memcpy(&val, v, sizeof(val));
+ if (val > maxv) {
return (NNG_EINVAL);
}
- if (v < minval) {
+ if (val < minv) {
return (NNG_EINVAL);
}
- *ptr = v;
+ *sp = val;
return (0);
}
diff --git a/src/core/options.h b/src/core/options.h
index 8e6e1edf..4b29c4b6 100644
--- a/src/core/options.h
+++ b/src/core/options.h
@@ -1,5 +1,6 @@
//
-// Copyright 2016 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -51,4 +52,8 @@ extern int nni_getopt_size(size_t *, void *, size_t *);
// nni_getopt_fd obtains a notification file descriptor.
extern int nni_getopt_fd(nni_sock *, nni_notifyfd *, int, void *, size_t *);
+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);
+
#endif // CORE_OPTIONS_H
diff --git a/src/core/pipe.c b/src/core/pipe.c
index cdbeb6a7..94524da4 100644
--- a/src/core/pipe.c
+++ b/src/core/pipe.c
@@ -117,7 +117,9 @@ nni_pipe_destroy(nni_pipe *p)
if (nni_list_node_active(&p->p_ep_node)) {
nni_ep_pipe_remove(p->p_ep, p);
}
- nni_sock_pipe_remove(p->p_sock, p);
+ if (nni_list_node_active(&p->p_sock_node)) {
+ nni_sock_pipe_remove(p->p_sock, p);
+ }
if (p->p_tran_data != NULL) {
p->p_tran_ops.p_fini(p->p_tran_data);
diff --git a/src/core/socket.c b/src/core/socket.c
index 9aa89a2d..79c1602b 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -18,6 +18,13 @@ static nni_list nni_sock_list;
static nni_idhash *nni_sock_hash;
static nni_mtx nni_sock_lk;
+typedef struct nni_sockopt {
+ nni_list_node node;
+ int opt;
+ size_t sz;
+ void * data;
+} nni_sockopt;
+
struct nni_socket {
nni_list_node s_node;
nni_mtx s_mx;
@@ -44,7 +51,8 @@ struct nni_socket {
nni_duration s_rcvtimeo; // receive timeout
nni_duration s_reconn; // reconnect time
nni_duration s_reconnmax; // max reconnect time
- size_t s_rcvmaxsz; // maximum receive size
+ size_t s_rcvmaxsz; // max receive size
+ nni_list s_options; // opts not handled by sock/proto
nni_list s_eps; // active endpoints
nni_list s_pipes; // active pipes
@@ -63,6 +71,13 @@ struct nni_socket {
nni_notifyfd s_recv_fd;
};
+static void
+nni_free_opt(nni_sockopt *opt)
+{
+ nni_free(opt->data, opt->sz);
+ NNI_FREE_STRUCT(opt);
+}
+
uint32_t
nni_sock_id(nni_sock *s)
{
@@ -268,6 +283,8 @@ nni_sock_unnotify(nni_sock *sock, nni_notify *notify)
static void
nni_sock_destroy(nni_sock *s)
{
+ nni_sockopt *sopt;
+
if (s == NULL) {
return;
}
@@ -285,6 +302,11 @@ nni_sock_destroy(nni_sock *s)
s->s_sock_ops.sock_fini(s->s_data);
}
+ while ((sopt = nni_list_first(&s->s_options)) != NULL) {
+ nni_list_remove(&s->s_options, sopt);
+ nni_free_opt(sopt);
+ }
+
nni_ev_fini(&s->s_send_ev);
nni_ev_fini(&s->s_recv_ev);
nni_msgq_fini(s->s_urq);
@@ -305,8 +327,8 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto)
return (NNG_ENOMEM);
}
s->s_linger = 0;
- s->s_sndtimeo = -1;
- s->s_rcvtimeo = -1;
+ s->s_sndtimeo = NNI_TIME_NEVER;
+ s->s_rcvtimeo = NNI_TIME_NEVER;
s->s_closing = 0;
s->s_reconn = NNI_SECOND;
s->s_reconnmax = 0;
@@ -328,6 +350,7 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto)
NNI_ASSERT(s->s_pipe_ops.pipe_stop != NULL);
NNI_LIST_NODE_INIT(&s->s_node);
+ NNI_LIST_INIT(&s->s_options, nni_sockopt, node);
nni_pipe_sock_list_init(&s->s_pipes);
nni_ep_list_init(&s->s_eps);
nni_mtx_init(&s->s_mx);
@@ -338,10 +361,23 @@ 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 = s->s_sock_ops.sock_init(&s->s_data, s)) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_LINGER, &s->s_linger,
+ sizeof(nni_duration))) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_SNDTIMEO, &s->s_sndtimeo,
+ sizeof(nni_duration))) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_RCVTIMEO, &s->s_rcvtimeo,
+ sizeof(nni_duration))) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECONN_TIME, &s->s_reconn,
+ sizeof(nni_duration))) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_RECONN_MAXTIME, &s->s_reconnmax,
+ sizeof(nni_duration))) != 0) ||
+ ((rv = nni_sock_setopt(s, NNG_OPT_RCVMAXSZ, &s->s_rcvmaxsz,
+ sizeof(size_t))) != 0)) {
nni_sock_destroy(s);
return (rv);
}
+
*sp = s;
return (rv);
}
@@ -383,7 +419,6 @@ nni_sock_open(nni_sock **sockp, const nni_proto *proto)
if (((rv = nni_init()) != 0) ||
((rv = nni_sock_create(&s, proto)) != 0)) {
- nni_sock_destroy(s);
return (rv);
}
@@ -690,12 +725,6 @@ nni_sock_peer(nni_sock *sock)
return (sock->s_peer_id.p_id);
}
-size_t
-nni_sock_rcvmaxsz(nni_sock *sock)
-{
- return (sock->s_rcvmaxsz);
-}
-
void
nni_sock_reconntimes(nni_sock *sock, nni_duration *rcur, nni_duration *rmax)
{
@@ -707,15 +736,25 @@ nni_sock_reconntimes(nni_sock *sock, nni_duration *rcur, nni_duration *rmax)
}
int
-nni_sock_ep_add(nni_sock *sock, nni_ep *ep)
+nni_sock_ep_add(nni_sock *s, nni_ep *ep)
{
- nni_mtx_lock(&sock->s_mx);
- if (sock->s_closing) {
- nni_mtx_unlock(&sock->s_mx);
+ nni_sockopt *sopt;
+
+ nni_mtx_lock(&s->s_mx);
+ if (s->s_closing) {
+ nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
- nni_list_append(&sock->s_eps, ep);
- nni_mtx_unlock(&sock->s_mx);
+ NNI_LIST_FOREACH (&s->s_options, sopt) {
+ int rv;
+ rv = nni_ep_setopt(ep, sopt->opt, sopt->data, sopt->sz, 0);
+ 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);
}
@@ -745,108 +784,222 @@ nni_sock_senderr(nni_sock *sock, int err)
}
int
-nni_sock_setopt(nni_sock *sock, int opt, const void *val, size_t size)
+nni_sock_setopt(nni_sock *s, int opt, const void *val, size_t size)
{
- int rv = NNG_ENOTSUP;
+ int rv = NNG_ENOTSUP;
+ nni_ep * ep;
+ int commits = 0;
+ nni_sockopt *optv;
+ nni_sockopt *oldv = NULL;
- nni_mtx_lock(&sock->s_mx);
- if (sock->s_closing) {
- nni_mtx_unlock(&sock->s_mx);
+ nni_mtx_lock(&s->s_mx);
+ if (s->s_closing) {
+ nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
- if (sock->s_sock_ops.sock_setopt != NULL) {
- rv =
- sock->s_sock_ops.sock_setopt(sock->s_data, opt, val, size);
+ 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) {
- nni_mtx_unlock(&sock->s_mx);
+ nni_mtx_unlock(&s->s_mx);
return (rv);
}
}
+
+ // Some options do not go down to transports. Handle them
+ // directly.
switch (opt) {
- case NNG_OPT_LINGER:
- rv = nni_setopt_usec(&sock->s_linger, val, size);
- break;
- case NNG_OPT_SNDTIMEO:
- rv = nni_setopt_usec(&sock->s_sndtimeo, val, size);
- break;
- case NNG_OPT_RCVTIMEO:
- rv = nni_setopt_usec(&sock->s_rcvtimeo, val, size);
- break;
case NNG_OPT_RECONN_TIME:
- rv = nni_setopt_usec(&sock->s_reconn, val, size);
+ rv = nni_setopt_usec(&s->s_reconn, val, size);
break;
case NNG_OPT_RECONN_MAXTIME:
- rv = nni_setopt_usec(&sock->s_reconnmax, val, size);
+ rv = nni_setopt_usec(&s->s_reconnmax, val, size);
break;
case NNG_OPT_SNDBUF:
- rv = nni_setopt_buf(sock->s_uwq, val, size);
+ rv = nni_setopt_buf(s->s_uwq, val, size);
break;
case NNG_OPT_RCVBUF:
- rv = nni_setopt_buf(sock->s_urq, val, size);
+ rv = nni_setopt_buf(s->s_urq, val, size);
break;
- case NNG_OPT_RCVMAXSZ:
- rv = nni_setopt_size(
- &sock->s_rcvmaxsz, val, size, 0, NNI_MAXSZ);
+ case NNG_OPT_SNDFD:
+ case NNG_OPT_RCVFD:
+ case NNG_OPT_LOCALADDR:
+ case NNG_OPT_REMOTEADDR:
+ // these options can be read, but cannot be set
+ rv = NNG_EINVAL;
break;
}
- nni_mtx_unlock(&sock->s_mx);
+
+ nni_mtx_unlock(&s->s_mx);
+
+ // If the option was already handled one way or the other,
+ if (rv != NNG_ENOTSUP) {
+ 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);
+
+ // 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.
+ if ((rv == NNG_ENOTSUP) || (rv == 0)) {
+ switch (opt) {
+ case NNG_OPT_LINGER:
+ rv = nni_chkopt_usec(val, size);
+ break;
+ case NNG_OPT_SNDTIMEO:
+ rv = nni_chkopt_usec(val, size);
+ break;
+ case NNG_OPT_RCVTIMEO:
+ rv = nni_chkopt_usec(val, size);
+ break;
+ case NNG_OPT_RCVMAXSZ:
+ // 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);
+ break;
+ }
+ }
+
+ if (rv != 0) {
+ return (rv);
+ }
+
+ // Prepare a copy of the sockoption.
+ if ((optv = NNI_ALLOC_STRUCT(optv)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ if ((optv->data = nni_alloc(size)) == NULL) {
+ NNI_FREE_STRUCT(optv);
+ return (NNG_ENOMEM);
+ }
+ memcpy(optv->data, val, size);
+ optv->opt = opt;
+ 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 ((oldv->sz != size) ||
+ (memcmp(oldv->data, val, size) != 0)) {
+ break;
+ }
+
+ // The values are the same. This is a no-op.
+ nni_mtx_unlock(&s->s_mx);
+ nni_free_opt(optv);
+ return (0);
+ }
+ }
+
+ // Apply the options. Failure to set any option on any transport
+ // (other than ENOTSUP) stops the operation altogether. Its
+ // 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);
+ if (x != NNG_ENOTSUP) {
+ if ((rv = x) != 0) {
+ nni_mtx_unlock(&s->s_mx);
+ nni_free_opt(optv);
+ return (rv);
+ }
+ }
+ }
+
+ // For some options, which also have an impact on the socket
+ // behavior, we save a local value. Note that the transport
+ // will already have had a chance to veto this.
+ switch (opt) {
+ case NNG_OPT_LINGER:
+ rv = nni_setopt_usec(&s->s_linger, val, size);
+ break;
+ case NNG_OPT_SNDTIMEO:
+ rv = nni_setopt_usec(&s->s_sndtimeo, val, size);
+ break;
+ case NNG_OPT_RCVTIMEO:
+ rv = nni_setopt_usec(&s->s_rcvtimeo, val, size);
+ break;
+ }
+
+ if (rv == 0) {
+ // Remove and toss the old value, we are using a new one.
+ if (oldv != NULL) {
+ nni_list_remove(&s->s_options, oldv);
+ nni_free_opt(oldv);
+ }
+
+ // Insert our new value. This permits it to be compared
+ // against later, and for new endpoints to automatically
+ // receive these values,
+ nni_list_append(&s->s_options, optv);
+ } else {
+ nni_free_opt(optv);
+ }
+
+ nni_mtx_unlock(&s->s_mx);
return (rv);
}
int
-nni_sock_getopt(nni_sock *sock, int opt, void *val, size_t *sizep)
+nni_sock_getopt(nni_sock *s, int opt, void *val, size_t *szp)
{
- int rv = NNG_ENOTSUP;
+ int rv = NNG_ENOTSUP;
+ nni_sockopt *sopt;
- nni_mtx_lock(&sock->s_mx);
- if (sock->s_closing) {
- nni_mtx_unlock(&sock->s_mx);
+ nni_mtx_lock(&s->s_mx);
+ if (s->s_closing) {
+ nni_mtx_unlock(&s->s_mx);
return (NNG_ECLOSED);
}
- if (sock->s_sock_ops.sock_getopt != NULL) {
- rv = sock->s_sock_ops.sock_getopt(
- sock->s_data, opt, val, sizep);
+ 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) {
- nni_mtx_unlock(&sock->s_mx);
+ nni_mtx_unlock(&s->s_mx);
return (rv);
}
}
+ // Options that are handled by socket core, and never
+ // passed down.
switch (opt) {
- case NNG_OPT_LINGER:
- rv = nni_getopt_usec(&sock->s_linger, val, sizep);
- break;
- case NNG_OPT_SNDTIMEO:
- rv = nni_getopt_usec(&sock->s_sndtimeo, val, sizep);
- break;
- case NNG_OPT_RCVTIMEO:
- rv = nni_getopt_usec(&sock->s_rcvtimeo, val, sizep);
- break;
case NNG_OPT_RECONN_TIME:
- rv = nni_getopt_usec(&sock->s_reconn, val, sizep);
+ rv = nni_getopt_usec(&s->s_reconn, val, szp);
break;
case NNG_OPT_RECONN_MAXTIME:
- rv = nni_getopt_usec(&sock->s_reconnmax, val, sizep);
+ rv = nni_getopt_usec(&s->s_reconnmax, val, szp);
break;
case NNG_OPT_SNDBUF:
- rv = nni_getopt_buf(sock->s_uwq, val, sizep);
+ rv = nni_getopt_buf(s->s_uwq, val, szp);
break;
case NNG_OPT_RCVBUF:
- rv = nni_getopt_buf(sock->s_urq, val, sizep);
- break;
- case NNG_OPT_RCVMAXSZ:
- rv = nni_getopt_size(&sock->s_rcvmaxsz, val, sizep);
+ rv = nni_getopt_buf(s->s_urq, val, szp);
break;
case NNG_OPT_SNDFD:
- rv = nni_getopt_fd(
- sock, &sock->s_send_fd, NNG_EV_CAN_SND, val, sizep);
+ rv = nni_getopt_fd(s, &s->s_send_fd, NNG_EV_CAN_SND, val, szp);
break;
case NNG_OPT_RCVFD:
- rv = nni_getopt_fd(
- sock, &sock->s_recv_fd, NNG_EV_CAN_RCV, val, sizep);
+ rv = nni_getopt_fd(s, &s->s_recv_fd, NNG_EV_CAN_RCV, val, szp);
+ break;
+ default:
+ 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;
+ }
+ }
break;
}
- nni_mtx_unlock(&sock->s_mx);
+ nni_mtx_unlock(&s->s_mx);
return (rv);
}
diff --git a/src/core/socket.h b/src/core/socket.h
index 9fa6c0fa..931fefac 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -64,8 +64,7 @@ extern nni_msgq *nni_sock_sendq(nni_sock *);
// inject incoming messages from pipes to it.
extern nni_msgq *nni_sock_recvq(nni_sock *);
-extern size_t nni_sock_rcvmaxsz(nni_sock *);
-extern void nni_sock_reconntimes(nni_sock *, nni_duration *, nni_duration *);
+extern void nni_sock_reconntimes(nni_sock *, nni_duration *, nni_duration *);
// nni_sock_flags returns the socket flags, used to indicate whether read
// and or write are appropriate for the protocol.
diff --git a/src/core/transport.c b/src/core/transport.c
index 2f373f9a..3130ae26 100644
--- a/src/core/transport.c
+++ b/src/core/transport.c
@@ -89,6 +89,27 @@ nni_tran_find(const char *addr)
return (NULL);
}
+int
+nni_tran_chkopt(int o, 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;
+ }
+ }
+ }
+ nni_mtx_unlock(&nni_tran_lk);
+ return (rv);
+}
+
// nni_tran_sys_init initializes the entire transport subsystem, including
// each individual transport.
int
diff --git a/src/core/transport.h b/src/core/transport.h
index 78cb2bbf..2891d8a4 100644
--- a/src/core/transport.h
+++ b/src/core/transport.h
@@ -29,6 +29,11 @@ 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);
@@ -135,6 +140,7 @@ struct nni_tran_pipe {
// 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_sys_init(void);
extern void nni_tran_sys_fini(void);
extern int nni_tran_register(const nni_tran *);
diff --git a/src/nng.c b/src/nng.c
index a833eeed..6c28f039 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -279,6 +279,20 @@ nng_listener_create(nng_listener *lp, nng_socket sid, const char *addr)
}
int
+nng_listener_start(nng_listener id, int flags)
+{
+ nni_ep *ep;
+ int rv;
+
+ if ((rv = nni_ep_find(&ep, id)) != 0) {
+ return (rv);
+ }
+ rv = nni_ep_listen(ep, flags);
+ nni_ep_rele(ep);
+ return (rv);
+}
+
+int
nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr)
{
nni_sock *s;
@@ -298,6 +312,148 @@ nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr)
return (0);
}
+int
+nng_dialer_start(nng_dialer id, int flags)
+{
+ nni_ep *ep;
+ int rv;
+
+ if ((rv = nni_ep_find(&ep, id)) != 0) {
+ return (rv);
+ }
+ rv = nni_ep_dial(ep, flags);
+ nni_ep_rele(ep);
+ return (rv);
+}
+
+static int
+nng_ep_setopt(uint32_t id, int opt, const void *val, size_t sz)
+{
+ nni_ep *ep;
+ int rv;
+ if ((rv = nni_ep_find(&ep, id)) != 0) {
+ return (rv);
+ }
+ rv = nni_ep_setopt(ep, opt, val, sz, 1);
+ nni_ep_rele(ep);
+ return (rv);
+}
+
+static int
+nng_ep_getopt(uint32_t id, int opt, void *val, size_t *szp)
+{
+ nni_ep *ep;
+ int rv;
+ if ((rv = nni_ep_find(&ep, id)) != 0) {
+ return (rv);
+ }
+ rv = nni_ep_getopt(ep, opt, val, szp);
+ nni_ep_rele(ep);
+ return (rv);
+}
+
+int
+nng_dialer_setopt(nng_dialer id, int opt, const void *v, size_t sz)
+{
+ return (nng_ep_setopt(id, opt, v, sz));
+}
+
+int
+nng_dialer_setopt_int(nng_dialer id, int opt, int val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_dialer_setopt_size(nng_dialer id, int opt, size_t val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_dialer_setopt_usec(nng_dialer id, int opt, uint64_t val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_dialer_getopt(nng_dialer id, int opt, void *val, size_t *szp)
+{
+ return (nng_ep_getopt(id, opt, val, szp));
+}
+
+int
+nng_dialer_getopt_int(nng_dialer id, int opt, int *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
+int
+nng_dialer_getopt_size(nng_dialer id, int opt, size_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
+int
+nng_dialer_getopt_usec(nng_dialer id, int opt, uint64_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
+int
+nng_listener_setopt(nng_listener id, int opt, const void *v, size_t sz)
+{
+ return (nng_ep_setopt(id, opt, v, sz));
+}
+
+int
+nng_listener_setopt_int(nng_listener id, int opt, int val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_listener_setopt_size(nng_listener id, int opt, size_t val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_listener_setopt_usec(nng_listener id, int opt, uint64_t val)
+{
+ return (nng_ep_setopt(id, opt, &val, sizeof(val)));
+}
+
+int
+nng_listener_getopt(nng_listener id, int opt, void *val, size_t *szp)
+{
+ return (nng_ep_getopt(id, opt, val, szp));
+}
+
+int
+nng_listener_getopt_int(nng_listener id, int opt, int *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
+int
+nng_listener_getopt_size(nng_listener id, int opt, size_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
+int
+nng_listener_getopt_usec(nng_listener id, int opt, uint64_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_ep_getopt(id, opt, valp, &sz));
+}
+
static int
nng_ep_close(uint32_t id)
{
@@ -422,7 +578,8 @@ nng_unsetnotify(nng_socket sid, nng_notify *notify)
nng_socket
nng_event_socket(nng_event *ev)
{
- // XXX: FOR NOW.... maybe evnet should contain socket Id instead?
+ // XXX: FOR NOW.... maybe evnet should contain socket Id
+ // instead?
return (nni_sock_id(ev->e_sock));
}
@@ -768,10 +925,10 @@ nng_stat_value(nng_stat *stat)
}
#endif
-// These routines exist as utility functions, exposing some of our "guts"
-// to the external world for the purposes of test code and bundled utilities.
-// They should not be considered part of our public API, and applications
-// should refrain from their use.
+// These routines exist as utility functions, exposing some of our
+// "guts" to the external world for the purposes of test code and
+// bundled utilities. They should not be considered part of our public
+// API, and applications should refrain from their use.
void
nng_usleep(uint64_t usec)
diff --git a/src/nng.h b/src/nng.h
index 9a6a37c8..0c76ffe7 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -199,17 +199,35 @@ NNG_DECL int nng_listener_close(nng_listener);
// nng_dialer_setopt sets an option for a specific dialer. Note
// dialer options may not be altered on a running dialer.
-NNG_DECL int nng_dialer_setopt(nng_dialer, int, void *, size_t);
-
-// nng_dialer_getopt obtains the option for a dialer.
+NNG_DECL int nng_dialer_setopt(nng_dialer, int, const void *, size_t);
+NNG_DECL int nng_dialer_setopt_int(nng_dialer, int, int);
+NNG_DECL int nng_dialer_setopt_usec(nng_dialer, int, uint64_t);
+NNG_DECL int nng_dialer_setopt_size(nng_dialer, int, size_t);
+
+// nng_dialer_getopt obtains the option for a dialer. This will
+// fail for options that a particular dialer is not interested in,
+// even if they were set on the socket.
NNG_DECL int nng_dialer_getopt(nng_dialer, int, void *, size_t *);
-
-// nng_listener_setopt sets an option for a specific listener. Note
-// listener options may not be altered on a running listener.
-NNG_DECL int nng_listener_setopt(nng_listener, int, void *, size_t);
-
-// nng_listener_getopt obtains the option for a listener.
+NNG_DECL int nng_dialer_getopt_int(nng_dialer, int, int *);
+NNG_DECL int nng_dialer_getopt_usec(nng_dialer, int, uint64_t *);
+NNG_DECL int nng_dialer_getopt_size(nng_dialer, int, size_t *);
+
+// nng_listener_setopt sets an option for a dialer. This value is
+// not stored in the socket. Subsequent setopts on the socket may
+// override these value however. Note listener options may not be altered
+// on a running listener.
+NNG_DECL int nng_listener_setopt(nng_dialer, int, const void *, size_t);
+NNG_DECL int nng_listener_setopt_int(nng_dialer, int, int);
+NNG_DECL int nng_listener_setopt_usec(nng_dialer, int, uint64_t);
+NNG_DECL int nng_listener_setopt_size(nng_dialer, int, size_t);
+
+// nng_listener_getopt obtains the option for a listener. This will
+// fail for options that a particular listener is not interested in,
+// even if they were set on the socket.
NNG_DECL int nng_listener_getopt(nng_listener, int, void *, size_t *);
+NNG_DECL int nng_listener_getopt_int(nng_listener, int, int *);
+NNG_DECL int nng_listener_getopt_usec(nng_listener, int, uint64_t *);
+NNG_DECL int nng_listener_getopt_size(nng_listener, int, size_t *);
// nng_strerror returns a human readable string associated with the error
// code supplied.
@@ -302,6 +320,7 @@ NNG_DECL int nng_pipe_close(nng_pipe);
enum nng_flag_enum {
NNG_FLAG_ALLOC = 1, // Recv to allocate receive buffer.
NNG_FLAG_NONBLOCK = 2, // Non-blocking operations.
+ NNG_FLAG_DRYRUN = 4, // Setopt dry-run (internally used).
};
// Protocol numbers. These are to be used with nng_socket_create().
diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c
index d421d57a..11bfceb9 100644
--- a/src/transport/ipc/ipc.c
+++ b/src/transport/ipc/ipc.c
@@ -63,6 +63,16 @@ static void nni_ipc_pipe_nego_cb(void *);
static void nni_ipc_ep_cb(void *);
static int
+nni_ipc_tran_chkopt(int o, const void *data, size_t sz)
+{
+ switch (o) {
+ case NNG_OPT_RCVMAXSZ:
+ return (nni_chkopt_size(data, sz, 0, NNI_MAXSZ));
+ }
+ return (NNG_ENOTSUP);
+}
+
+static int
nni_ipc_tran_init(void)
{
return (0);
@@ -496,7 +506,6 @@ nni_ipc_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
ep->closed = 0;
ep->proto = nni_sock_proto(sock);
- ep->rcvmax = nni_sock_rcvmaxsz(sock);
(void) snprintf(ep->addr, sizeof(ep->addr), "%s", url);
*epp = ep;
@@ -649,6 +658,43 @@ nni_ipc_ep_connect(void *arg, nni_aio *aio)
nni_mtx_unlock(&ep->mtx);
}
+static int
+nni_ipc_ep_setopt(void *arg, int opt, const void *v, size_t sz)
+{
+ int rv;
+ nni_ipc_ep *ep = arg;
+ nni_mtx_lock(&ep->mtx);
+ switch (opt) {
+ case NNG_OPT_RCVMAXSZ:
+ rv = nni_setopt_size(&ep->rcvmax, v, sz, 0, NNI_MAXSZ);
+ break;
+ default:
+ rv = NNG_ENOTSUP;
+ break;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
+static int
+nni_ipc_ep_getopt(void *arg, int opt, void *v, size_t *szp)
+{
+ int rv;
+ nni_ipc_ep *ep = arg;
+
+ nni_mtx_lock(&ep->mtx);
+ switch (opt) {
+ case NNG_OPT_RCVMAXSZ:
+ rv = nni_getopt_size(&ep->rcvmax, v, szp);
+ break;
+ default:
+ rv = NNG_ENOTSUP;
+ break;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
static nni_tran_pipe nni_ipc_pipe_ops = {
.p_fini = nni_ipc_pipe_fini,
.p_start = nni_ipc_pipe_start,
@@ -666,8 +712,8 @@ static nni_tran_ep nni_ipc_ep_ops = {
.ep_bind = nni_ipc_ep_bind,
.ep_accept = nni_ipc_ep_accept,
.ep_close = nni_ipc_ep_close,
- .ep_setopt = NULL,
- .ep_getopt = NULL,
+ .ep_setopt = nni_ipc_ep_setopt,
+ .ep_getopt = nni_ipc_ep_getopt,
};
// This is the IPC transport linkage, and should be the only global
diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c
index 035ced62..99e59302 100644
--- a/src/transport/tcp/tcp.c
+++ b/src/transport/tcp/tcp.c
@@ -51,6 +51,7 @@ struct nni_tcp_ep {
int closed;
uint16_t proto;
size_t rcvmax;
+ nni_duration linger;
int ipv4only;
nni_aio aio;
nni_aio * user_aio;
@@ -63,6 +64,18 @@ static void nni_tcp_pipe_nego_cb(void *);
static void nni_tcp_ep_cb(void *arg);
static int
+nni_tcp_tran_chkopt(int o, const void *data, size_t sz)
+{
+ switch (o) {
+ case NNG_OPT_RCVMAXSZ:
+ return (nni_chkopt_size(data, sz, 0, NNI_MAXSZ));
+ case NNG_OPT_LINGER:
+ return (nni_chkopt_usec(data, sz));
+ }
+ return (NNG_ENOTSUP);
+}
+
+static int
nni_tcp_tran_init(void)
{
return (0);
@@ -561,7 +574,6 @@ nni_tcp_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
ep->closed = 0;
ep->proto = nni_sock_proto(sock);
- ep->rcvmax = nni_sock_rcvmaxsz(sock);
(void) snprintf(ep->addr, sizeof(ep->addr), "%s", url);
*epp = ep;
@@ -713,6 +725,51 @@ nni_tcp_ep_connect(void *arg, nni_aio *aio)
nni_mtx_unlock(&ep->mtx);
}
+static int
+nni_tcp_ep_setopt(void *arg, int opt, const void *v, size_t sz)
+{
+ int rv;
+ nni_tcp_ep *ep = arg;
+
+ nni_mtx_lock(&ep->mtx);
+ switch (opt) {
+ case NNG_OPT_RCVMAXSZ:
+ rv = nni_setopt_size(&ep->rcvmax, v, sz, 0, NNI_MAXSZ);
+ break;
+ case NNG_OPT_LINGER:
+ rv = nni_setopt_usec(&ep->linger, v, sz);
+ break;
+ default:
+ rv = NNG_ENOTSUP;
+ break;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
+static int
+nni_tcp_ep_getopt(void *arg, int opt, void *v, size_t *szp)
+{
+ int rv;
+ nni_tcp_ep *ep = arg;
+
+ nni_mtx_lock(&ep->mtx);
+ switch (opt) {
+ case NNG_OPT_RCVMAXSZ:
+ rv = nni_getopt_size(&ep->rcvmax, v, szp);
+ break;
+ case NNG_OPT_LINGER:
+ rv = nni_getopt_usec(&ep->linger, v, szp);
+ break;
+ default:
+ // XXX: add address properties
+ rv = NNG_ENOTSUP;
+ break;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
static nni_tran_pipe nni_tcp_pipe_ops = {
.p_fini = nni_tcp_pipe_fini,
.p_start = nni_tcp_pipe_start,
@@ -730,8 +787,8 @@ static nni_tran_ep nni_tcp_ep_ops = {
.ep_bind = nni_tcp_ep_bind,
.ep_accept = nni_tcp_ep_accept,
.ep_close = nni_tcp_ep_close,
- .ep_setopt = NULL,
- .ep_getopt = NULL,
+ .ep_setopt = nni_tcp_ep_setopt,
+ .ep_getopt = nni_tcp_ep_getopt,
};
// This is the TCP transport linkage, and should be the only global
@@ -741,6 +798,7 @@ struct nni_tran nni_tcp_tran = {
.tran_scheme = "tcp",
.tran_ep = &nni_tcp_ep_ops,
.tran_pipe = &nni_tcp_pipe_ops,
+ .tran_chkopt = nni_tcp_tran_chkopt,
.tran_init = nni_tcp_tran_init,
.tran_fini = nni_tcp_tran_fini,
};
diff --git a/tests/sock.c b/tests/sock.c
index d33b0c81..2e2345c9 100644
--- a/tests/sock.c
+++ b/tests/sock.c
@@ -9,12 +9,15 @@
#include "convey.h"
#include "nng.h"
+#include "trantest.h"
#include <string.h>
TestMain("Socket Operations", {
- Reset({ nng_fini(); });
+ atexit(nng_fini);
+ // Reset({ nng_fini(); });
+ Reset({ nng_closeall(); });
Convey("We are able to open a PAIR socket", {
int rv;
@@ -98,12 +101,63 @@ TestMain("Socket Operations", {
So(nng_setopt_usec(s1, NNG_OPT_SNDTIMEO, to) == 0);
+ Convey("Read only options handled properly", {
+ So(nng_setopt_int(s1, NNG_OPT_RCVFD, 0) ==
+ NNG_EINVAL);
+ So(nng_setopt_int(s1, NNG_OPT_SNDFD, 0) ==
+ NNG_EINVAL);
+ So(nng_setopt(s1, NNG_OPT_LOCALADDR, "a", 1) ==
+ NNG_EINVAL);
+ So(nng_setopt(s1, NNG_OPT_REMOTEADDR, "a",
+ 1) == NNG_EINVAL);
+ });
+
+ Convey("We can apply options before endpoint", {
+ nng_listener l;
+ char addr[NNG_MAXADDRLEN];
+ trantest_next_address(
+ addr, "ipc:///tmp/lopt_%u");
+
+ So(nng_setopt_size(
+ s1, NNG_OPT_RCVMAXSZ, 543) == 0);
+ So(nng_listener_create(&l, s1, addr) == 0);
+ So(nng_listener_getopt_size(
+ l, NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 543);
+
+ Convey("Endpoint option can be overridden", {
+ So(nng_listener_setopt_size(
+ l, NNG_OPT_RCVMAXSZ, 678) == 0);
+ So(nng_listener_getopt_size(
+ l, NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 678);
+ So(nng_getopt_size(s1,
+ NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 543);
+ });
+
+ Convey("And socket overrides again", {
+ So(nng_setopt_size(s1,
+ NNG_OPT_RCVMAXSZ, 911) == 0);
+ So(nng_listener_getopt_size(
+ l, NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 911);
+ });
+ });
Convey("Short size is not copied", {
sz = 0;
So(nng_getopt(s1, NNG_OPT_SNDTIMEO, &v, &sz) ==
0);
So(sz == sizeof(v));
So(v == 0);
+ sz = 0;
+ So(nng_getopt(
+ s1, NNG_OPT_RECONN_TIME, &v, &sz) == 0);
+
+ So(v == 0);
+ So(nng_getopt(s1, NNG_OPT_RECONN_MAXTIME, &v,
+ &sz) == 0);
+ So(v == 0);
});
Convey("Correct size is copied", {
@@ -126,6 +180,9 @@ TestMain("Socket Operations", {
Convey("Insane buffer size fails", {
So(nng_setopt_int(s1, NNG_OPT_RCVBUF,
0x100000) == NNG_EINVAL);
+ So(nng_setopt_int(s1, NNG_OPT_RCVBUF, -200) ==
+ NNG_EINVAL);
+
});
Convey("Negative timeout fails", {
@@ -138,6 +195,8 @@ TestMain("Socket Operations", {
sz = sizeof(to) - 1;
So(nng_setopt(s1, NNG_OPT_RCVTIMEO, &to, sz) ==
NNG_EINVAL);
+ So(nng_setopt(s1, NNG_OPT_RECONN_TIME, &to,
+ sz) == NNG_EINVAL);
});
Convey("Bogus raw fails", {
@@ -146,6 +205,8 @@ TestMain("Socket Operations", {
So(nng_setopt_int(s1, NNG_OPT_RAW, -42) ==
NNG_EINVAL);
So(nng_setopt_int(s1, NNG_OPT_RAW, 0) == 0);
+ So(nng_setopt(s1, NNG_OPT_RAW, "a", 1) ==
+ NNG_EINVAL);
});
Convey("Unsupported options fail", {
@@ -156,6 +217,7 @@ TestMain("Socket Operations", {
Convey("Bogus sizes fail", {
size_t v;
+ int i;
So(nng_setopt_size(
s1, NNG_OPT_RCVMAXSZ, 6550) == 0);
@@ -170,6 +232,10 @@ TestMain("Socket Operations", {
0);
So(v == 6550);
+ i = 42;
+ So(nng_setopt(s1, NNG_OPT_RCVBUF, &i, 1) ==
+ NNG_EINVAL);
+
if (sizeof(size_t) == 8) {
v = 0x10000;
v <<= 30;
@@ -220,15 +286,20 @@ TestMain("Socket Operations", {
});
Convey("Listening works", {
- char *a = "inproc://here";
- rv = nng_listen(s1, a, NULL, 0);
+ char * a = "inproc://here";
+ nng_listener l;
+ rv = nng_listen(s1, a, &l, 0);
So(rv == 0);
+ So(l != 0);
Convey("Second listen fails ADDRINUSE", {
rv = nng_listen(s1, a, NULL, 0);
So(rv == NNG_EADDRINUSE);
});
+ Convey("We cannot try to start a listener again",
+ { So(nng_listener_start(l, 0) == NNG_ESTATE); });
+
Convey("We can connect to it", {
nng_socket s2;
So(nng_pair_open(&s2) == 0);
@@ -238,6 +309,121 @@ TestMain("Socket Operations", {
});
});
+ Convey("Dialer creation ok", {
+ nng_dialer ep;
+ char * a = "tcp://127.0.0.1:2929";
+ So(nng_dialer_create(&ep, s1, a) == 0);
+ Convey("Options work", {
+ size_t sz;
+ So(nng_dialer_setopt_size(
+ ep, NNG_OPT_RCVMAXSZ, 4321) == 0);
+ So(nng_dialer_getopt_size(
+ ep, NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 4321);
+ });
+ Convey("Socket opts not for dialer", {
+ // Not appropriate for dialer.
+ So(nng_dialer_setopt_int(ep, NNG_OPT_RAW, 1) ==
+ NNG_ENOTSUP);
+ So(nng_dialer_setopt_usec(ep,
+ NNG_OPT_RECONN_TIME, 1) == NNG_ENOTSUP);
+ });
+ Convey("Bad size checks", {
+ So(nng_dialer_setopt(ep, NNG_OPT_RCVMAXSZ, "a",
+ 1) == NNG_EINVAL);
+ });
+ Convey("Cannot listen",
+ { So(nng_listener_start(ep, 0) == NNG_ENOTSUP); });
+
+ });
+
+ Convey("Listener creation ok", {
+ nng_listener ep;
+ char * a = "tcp://127.0.0.1:2929";
+ So(nng_listener_create(&ep, s1, a) == 0);
+ Convey("Options work", {
+ size_t sz;
+ So(nng_listener_setopt_size(
+ ep, NNG_OPT_RCVMAXSZ, 4321) == 0);
+ So(nng_listener_getopt_size(
+ ep, NNG_OPT_RCVMAXSZ, &sz) == 0);
+ So(sz == 4321);
+ });
+ Convey("Socket opts not for dialer", {
+ // Not appropriate for dialer.
+ So(nng_listener_setopt_int(
+ ep, NNG_OPT_RAW, 1) == NNG_ENOTSUP);
+ So(nng_listener_setopt_usec(ep,
+ NNG_OPT_RECONN_TIME, 1) == NNG_ENOTSUP);
+ });
+ Convey("Bad size checks", {
+ So(nng_listener_setopt(ep, NNG_OPT_RCVMAXSZ,
+ "a", 1) == NNG_EINVAL);
+ });
+ Convey("Cannot dial",
+ { So(nng_dialer_start(ep, 0) == NNG_ENOTSUP); });
+ });
+
+ Convey("Cannot access absent ep options", {
+ size_t s;
+ int i;
+ uint64_t t;
+
+ So(nng_dialer_setopt_size(
+ 1999, NNG_OPT_RCVMAXSZ, 10) == NNG_ENOENT);
+ So(nng_listener_setopt_size(
+ 1999, NNG_OPT_RCVMAXSZ, 10) == NNG_ENOENT);
+
+ s = 1;
+ So(nng_dialer_getopt(1999, NNG_OPT_RAW, &i, &s) ==
+ NNG_ENOENT);
+ So(nng_listener_getopt(1999, NNG_OPT_RAW, &i, &s) ==
+ NNG_ENOENT);
+
+ So(nng_dialer_getopt_size(
+ 1999, NNG_OPT_RCVMAXSZ, &s) == NNG_ENOENT);
+ So(nng_listener_getopt_size(
+ 1999, NNG_OPT_RCVMAXSZ, &s) == NNG_ENOENT);
+
+ So(nng_dialer_getopt_int(1999, NNG_OPT_RAW, &i) ==
+ NNG_ENOENT);
+ So(nng_listener_getopt_int(1999, NNG_OPT_RAW, &i) ==
+ NNG_ENOENT);
+
+ So(nng_dialer_getopt_usec(1999, NNG_OPT_LINGER, &t) ==
+ NNG_ENOENT);
+ So(nng_listener_getopt_usec(
+ 1999, NNG_OPT_LINGER, &t) == NNG_ENOENT);
+
+ });
+
+ Convey("Cannot set dialer opts when running", {
+ nng_dialer ep;
+ char addr[NNG_MAXADDRLEN];
+
+ trantest_next_address(addr, "ipc:///tmp/sock_test_%u");
+ So(nng_dialer_create(&ep, s1, addr) == 0);
+ So(nng_dialer_start(ep, NNG_FLAG_NONBLOCK) == 0);
+ So(nng_dialer_setopt_size(ep, NNG_OPT_RCVMAXSZ, 10) ==
+ NNG_ESTATE);
+ So(nng_dialer_close(ep) == 0);
+ So(nng_dialer_close(ep) == NNG_ENOENT);
+ });
+
+ Convey("Cannot set listener opts when running", {
+ nng_listener ep;
+ char addr[NNG_MAXADDRLEN];
+
+ trantest_next_address(addr, "ipc:///tmp/sock_test_%u");
+
+ So(nng_listener_create(&ep, s1, addr) == 0);
+ So(nng_listener_start(ep, 0) == 0);
+ So(nng_listener_setopt_size(
+ ep, NNG_OPT_RCVMAXSZ, 10) == NNG_ESTATE);
+ So(nng_listener_close(ep) == 0);
+ So(nng_listener_close(ep) == NNG_ENOENT);
+ });
+
Convey("We can send and receive messages", {
nng_socket s2;
int len;