aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-10-02 13:34:55 -0700
committerGarrett D'Amore <garrett@damore.org>2017-10-02 15:29:43 -0700
commit6e945e18f3f3e9b7f9ee614eac6d3bf681f768d9 (patch)
treefffa3e455ec657ce3205c01c12398076e7ae28f0
parentb9b5c31b19df95d672ddc76cdfde29318f78b5ea (diff)
downloadnng-6e945e18f3f3e9b7f9ee614eac6d3bf681f768d9.tar.gz
nng-6e945e18f3f3e9b7f9ee614eac6d3bf681f768d9.tar.bz2
nng-6e945e18f3f3e9b7f9ee614eac6d3bf681f768d9.zip
Added more complete tests, and changes to property handling.
We allow some properties to be set on endpoints after they are started; transports now responsible for checking that. (The new values will only apply to new connections of course!) We added short-hand functions for pipe properties, and also added uint64_t shorthands across the board. The zerotier documentation got some updates (corrections). We have also added a separate header now for the ZT stuff. Also, dialers and listeners do not intermix anymore -- we test that only a dialer can be used with setting dialer options, and likewise for listeners.
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/core/endpt.c12
-rw-r--r--src/core/endpt.h1
-rw-r--r--src/nng.c118
-rw-r--r--src/nng.h11
-rw-r--r--src/transport/zerotier/zerotier.adoc4
-rw-r--r--src/transport/zerotier/zerotier.c71
-rw-r--r--src/transport/zerotier/zerotier.h110
-rw-r--r--tests/sock.c27
-rw-r--r--tests/zt.c203
10 files changed, 407 insertions, 157 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ffcb2b7b..2f2f54ff 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -144,7 +144,12 @@ if (NNG_PLATFORM_WINDOWS)
endif()
if (NNG_ENABLE_ZEROTIER)
- set (NNG_SOURCES ${NNG_SOURCES} transport/zerotier/zerotier.c)
+ set (NNG_SOURCES ${NNG_SOURCES}
+ transport/zerotier/zerotier.c
+ transport/zerotier/zerotier.h
+ )
+ install(FILES transport/zerotier/zerotier.h
+ DESTINATION include/nng/transport/zerotier)
endif()
include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src
diff --git a/src/core/endpt.c b/src/core/endpt.c
index e6216ba3..fa30bf77 100644
--- a/src/core/endpt.c
+++ b/src/core/endpt.c
@@ -605,21 +605,21 @@ nni_ep_setopt(nni_ep *ep, const char *name, const void *val, size_t sz)
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 (rv);
}
- // XXX: socket fallback
return (NNG_ENOTSUP);
}
int
+nni_ep_mode(nni_ep *ep)
+{
+ return (ep->ep_mode);
+}
+
+int
nni_ep_getopt(nni_ep *ep, const char *name, void *valp, size_t *szp)
{
nni_tran_ep_option *eo;
diff --git a/src/core/endpt.h b/src/core/endpt.h
index d12d661f..f5ad09ee 100644
--- a/src/core/endpt.h
+++ b/src/core/endpt.h
@@ -32,6 +32,7 @@ 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 *);
+extern int nni_ep_mode(nni_ep *);
// Endpoint modes. Currently used by transports. Remove this when we make
// transport dialers and listeners explicit.
diff --git a/src/nng.c b/src/nng.c
index 7a78357e..85be6b26 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -328,7 +328,8 @@ nng_dialer_start(nng_dialer id, int flags)
}
static int
-nng_ep_setopt(uint32_t id, const char *name, const void *val, size_t sz)
+nng_ep_setopt(
+ uint32_t id, const char *name, const void *val, size_t sz, int mode)
{
nni_ep *ep;
int rv;
@@ -339,13 +340,17 @@ nng_ep_setopt(uint32_t id, const char *name, const void *val, size_t sz)
if ((rv = nni_ep_find(&ep, id)) != 0) {
return (rv);
}
- rv = nni_ep_setopt(ep, name, val, sz);
+ if (nni_ep_mode(ep) == mode) {
+ rv = nni_ep_setopt(ep, name, val, sz);
+ } else {
+ rv = NNG_ENOENT;
+ }
nni_ep_rele(ep);
return (rv);
}
static int
-nng_ep_getopt(uint32_t id, const char *name, void *val, size_t *szp)
+nng_ep_getopt(uint32_t id, const char *name, void *val, size_t *szp, int mode)
{
nni_ep *ep;
int rv;
@@ -356,7 +361,11 @@ nng_ep_getopt(uint32_t id, const char *name, void *val, size_t *szp)
if ((rv = nni_ep_find(&ep, id)) != 0) {
return (rv);
}
- rv = nni_ep_getopt(ep, name, val, szp);
+ if (nni_ep_mode(ep) == mode) {
+ rv = nni_ep_getopt(ep, name, val, szp);
+ } else {
+ rv = NNG_ENOENT;
+ }
nni_ep_rele(ep);
return (rv);
}
@@ -364,104 +373,128 @@ nng_ep_getopt(uint32_t id, const char *name, void *val, size_t *szp)
int
nng_dialer_setopt(nng_dialer id, const char *name, const void *v, size_t sz)
{
- return (nng_ep_setopt(id, name, v, sz));
+ return (nng_ep_setopt(id, name, v, sz, NNI_EP_MODE_DIAL));
}
int
nng_dialer_setopt_int(nng_dialer id, const char *name, int val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_dialer_setopt(id, name, &val, sizeof(val)));
}
int
nng_dialer_setopt_size(nng_dialer id, const char *name, size_t val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_dialer_setopt(id, name, &val, sizeof(val)));
}
int
nng_dialer_setopt_usec(nng_dialer id, const char *name, uint64_t val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_dialer_setopt(id, name, &val, sizeof(val)));
+}
+
+int
+nng_dialer_setopt_uint64(nng_dialer id, const char *name, uint64_t val)
+{
+ return (nng_dialer_setopt(id, name, &val, sizeof(val)));
}
int
nng_dialer_getopt(nng_dialer id, const char *name, void *val, size_t *szp)
{
- return (nng_ep_getopt(id, name, val, szp));
+ return (nng_ep_getopt(id, name, val, szp, NNI_EP_MODE_DIAL));
}
int
nng_dialer_getopt_int(nng_dialer id, const char *name, int *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_dialer_getopt(id, name, valp, &sz));
}
int
nng_dialer_getopt_size(nng_dialer id, const char *name, size_t *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_dialer_getopt(id, name, valp, &sz));
}
int
-nng_dialer_getopt_usec(nng_dialer id, const char *name, uint64_t *valp)
+nng_dialer_getopt_uint64(nng_dialer id, const char *name, uint64_t *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_dialer_getopt(id, name, valp, &sz));
+}
+
+int
+nng_dialer_getopt_usec(nng_dialer id, const char *name, uint64_t *valp)
+{
+ return (nng_dialer_getopt_uint64(id, name, valp));
}
int
nng_listener_setopt(
nng_listener id, const char *name, const void *v, size_t sz)
{
- return (nng_ep_setopt(id, name, v, sz));
+ return (nng_ep_setopt(id, name, v, sz, NNI_EP_MODE_LISTEN));
}
int
nng_listener_setopt_int(nng_listener id, const char *name, int val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_listener_setopt(id, name, &val, sizeof(val)));
}
int
nng_listener_setopt_size(nng_listener id, const char *name, size_t val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_listener_setopt(id, name, &val, sizeof(val)));
}
int
nng_listener_setopt_usec(nng_listener id, const char *name, uint64_t val)
{
- return (nng_ep_setopt(id, name, &val, sizeof(val)));
+ return (nng_listener_setopt(id, name, &val, sizeof(val)));
+}
+
+int
+nng_listener_setopt_uint64(nng_listener id, const char *name, uint64_t val)
+{
+ return (nng_listener_setopt(id, name, &val, sizeof(val)));
}
int
nng_listener_getopt(nng_listener id, const char *name, void *val, size_t *szp)
{
- return (nng_ep_getopt(id, name, val, szp));
+ return (nng_ep_getopt(id, name, val, szp, NNI_EP_MODE_LISTEN));
}
int
nng_listener_getopt_int(nng_listener id, const char *name, int *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_listener_getopt(id, name, valp, &sz));
}
int
nng_listener_getopt_size(nng_listener id, const char *name, size_t *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_listener_getopt(id, name, valp, &sz));
}
int
-nng_listener_getopt_usec(nng_listener id, const char *name, uint64_t *valp)
+nng_listener_getopt_uint64(nng_listener id, const char *name, uint64_t *valp)
{
size_t sz = sizeof(*valp);
- return (nng_ep_getopt(id, name, valp, &sz));
+ return (nng_listener_getopt(id, name, valp, &sz));
+}
+
+int
+nng_listener_getopt_usec(nng_listener id, const char *name, uint64_t *valp)
+{
+ return (nng_listener_getopt_uint64(id, name, valp));
}
static int
@@ -543,6 +576,12 @@ nng_setopt_usec(nng_socket sid, const char *name, uint64_t val)
}
int
+nng_setopt_uint64(nng_socket sid, const char *name, uint64_t val)
+{
+ return (nng_setopt(sid, name, &val, sizeof(val)));
+}
+
+int
nng_getopt_int(nng_socket sid, const char *name, int *valp)
{
size_t sz = sizeof(*valp);
@@ -557,12 +596,18 @@ nng_getopt_size(nng_socket sid, const char *name, size_t *valp)
}
int
-nng_getopt_usec(nng_socket sid, const char *name, uint64_t *valp)
+nng_getopt_uint64(nng_socket sid, const char *name, uint64_t *valp)
{
size_t sz = sizeof(*valp);
return (nng_getopt(sid, name, valp, &sz));
}
+int
+nng_getopt_usec(nng_socket sid, const char *name, uint64_t *valp)
+{
+ return (nng_getopt_uint64(sid, name, valp));
+}
+
nng_notify *
nng_setnotify(nng_socket sid, int mask, nng_notify_func fn, void *arg)
{
@@ -709,6 +754,33 @@ nng_pipe_getopt(nng_pipe id, const char *name, void *val, size_t *sizep)
}
int
+nng_pipe_getopt_int(nng_pipe id, const char *name, int *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_pipe_getopt(id, name, valp, &sz));
+}
+
+int
+nng_pipe_getopt_size(nng_pipe id, const char *name, size_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_pipe_getopt(id, name, valp, &sz));
+}
+
+int
+nng_pipe_getopt_uint64(nng_pipe id, const char *name, uint64_t *valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_pipe_getopt(id, name, valp, &sz));
+}
+
+int
+nni_pipe_getopt_usec(nng_pipe id, const char *name, uint64_t *valp)
+{
+ return (nng_pipe_getopt_uint64(id, name, valp));
+}
+
+int
nng_pipe_close(nng_pipe id)
{
int rv;
diff --git a/src/nng.h b/src/nng.h
index 362e324b..f9ed54b0 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -90,12 +90,14 @@ NNG_DECL int nng_setopt(nng_socket, const char *, const void *, size_t);
NNG_DECL int nng_setopt_int(nng_socket, const char *, int);
NNG_DECL int nng_setopt_usec(nng_socket, const char *, uint64_t);
NNG_DECL int nng_setopt_size(nng_socket, const char *, size_t);
+NNG_DECL int nng_setopt_uint64(nng_socket, const char *, uint64_t);
// nng_socket_getopt obtains the option for a socket.
NNG_DECL int nng_getopt(nng_socket, const char *, void *, size_t *);
NNG_DECL int nng_getopt_int(nng_socket, const char *, int *);
NNG_DECL int nng_getopt_usec(nng_socket, const char *, uint64_t *);
NNG_DECL int nng_getopt_size(nng_socket, const char *, size_t *);
+NNG_DECL int nng_getopt_uint64(nng_socket, const char *, uint64_t *);
// nng_notify_func is a user function that is executed upon certain
// events. See below.
@@ -203,6 +205,7 @@ NNG_DECL int nng_dialer_setopt(nng_dialer, const char *, const void *, size_t);
NNG_DECL int nng_dialer_setopt_int(nng_dialer, const char *, int);
NNG_DECL int nng_dialer_setopt_usec(nng_dialer, const char *, uint64_t);
NNG_DECL int nng_dialer_setopt_size(nng_dialer, const char *, size_t);
+NNG_DECL int nng_dialer_setopt_uint64(nng_dialer, const char *, uint64_t);
// nng_dialer_getopt obtains the option for a dialer. This will
// fail for options that a particular dialer is not interested in,
@@ -211,6 +214,7 @@ NNG_DECL int nng_dialer_getopt(nng_dialer, const char *, void *, size_t *);
NNG_DECL int nng_dialer_getopt_int(nng_dialer, const char *, int *);
NNG_DECL int nng_dialer_getopt_usec(nng_dialer, const char *, uint64_t *);
NNG_DECL int nng_dialer_getopt_size(nng_dialer, const char *, size_t *);
+NNG_DECL int nng_dialer_getopt_uint64(nng_dialer, const char *, uint64_t *);
// nng_listener_setopt sets an option for a dialer. This value is
// not stored in the socket. Subsequent setopts on the socket may
@@ -221,6 +225,7 @@ NNG_DECL int nng_listener_setopt(
NNG_DECL int nng_listener_setopt_int(nng_listener, const char *, int);
NNG_DECL int nng_listener_setopt_usec(nng_listener, const char *, uint64_t);
NNG_DECL int nng_listener_setopt_size(nng_listener, const char *, size_t);
+NNG_DECL int nng_listener_setopt_uint64(nng_listener, const char *, uint64_t);
// nng_listener_getopt obtains the option for a listener. This will
// fail for options that a particular listener is not interested in,
@@ -229,6 +234,8 @@ NNG_DECL int nng_listener_getopt(nng_listener, const char *, void *, size_t *);
NNG_DECL int nng_listener_getopt_int(nng_listener, const char *, int *);
NNG_DECL int nng_listener_getopt_usec(nng_listener, const char *, uint64_t *);
NNG_DECL int nng_listener_getopt_size(nng_listener, const char *, size_t *);
+NNG_DECL int nng_listener_getopt_uint64(
+ nng_listener, const char *, uint64_t *);
// nng_strerror returns a human readable string associated with the error
// code supplied.
@@ -322,6 +329,10 @@ NNG_DECL const char *nng_option_name(int);
// example during a connection notification, to disconnect a pipe that
// is associated with an invalid or untrusted remote peer.
NNG_DECL int nng_pipe_getopt(nng_pipe, const char *, void *, size_t *);
+NNG_DECL int nng_pipe_getopt_int(nng_pipe, const char *, int *);
+NNG_DECL int nng_pipe_getopt_usec(nng_pipe, const char *, uint64_t *);
+NNG_DECL int nng_pipe_getopt_size(nng_pipe, const char *, size_t *);
+NNG_DECL int nng_pipe_getopt_uint64(nng_pipe, const char *, uint64_t *);
NNG_DECL int nng_pipe_close(nng_pipe);
// Flags.
diff --git a/src/transport/zerotier/zerotier.adoc b/src/transport/zerotier/zerotier.adoc
index dc838420..84501807 100644
--- a/src/transport/zerotier/zerotier.adoc
+++ b/src/transport/zerotier/zerotier.adoc
@@ -357,10 +357,10 @@ ZeroTier IDs, ZeroTier network IDs, and our own 24-bit ports.
The format shall be `zt://<nwid>/<ztid>:<port>`, where the `<nwid>`
component represents the 64-bit hexadecimal ZeroTier network ID,
the `<ztid>` represents the 40-bit hexadecimal ZeroTier Device ID,
-and the `<port>` is the 24-bit port number previously described.
+and the `<port>` is the 24-bit port number (decimal) previously described.
A responder may elide the `<ztid>/` portion, to just bind to itself,
-in which case the format will be `zt://<nwid>/<ztid>:<port>`.
+in which case the format will be `zt://<nwid>:<port>`.
A port number of 0 may be used when listening to indicate that a random
ephemeral port should be chosen.
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index 46423b80..56acce03 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -15,6 +15,7 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "zerotier.h"
#ifndef _WIN32
#include <unistd.h>
@@ -22,31 +23,16 @@
#include <ZeroTierOne.h>
-#define NNG_ZT_OPT_HOME "zt:home"
-#define NNG_ZT_OPT_NWID "zt:nwid"
-#define NNG_ZT_OPT_NODE "zt:node"
-#define NNG_ZT_OPT_STATUS "zt:status"
-#define NNG_ZT_OPT_NETWORK_NAME "zt:network-name"
-#define NNG_ZT_OPT_PING_TIME "zt:ping-time"
-#define NNG_ZT_OPT_PING_COUNT "zt:ping-count"
-#define NNG_ZT_OPT_MTU "zt:mtu"
-
-const char *nng_opt_zt_home = NNG_ZT_OPT_HOME;
-const char *nng_opt_zt_nwid = NNG_ZT_OPT_NWID;
-const char *nng_opt_zt_node = NNG_ZT_OPT_NODE;
-const char *nng_opt_zt_status = NNG_ZT_OPT_STATUS;
-const char *nng_opt_zt_network_name = NNG_ZT_OPT_NETWORK_NAME;
-const char *nng_opt_zt_ping_time = NNG_ZT_OPT_PING_TIME;
-const char *nng_opt_zt_ping_count = NNG_ZT_OPT_PING_COUNT;
-
// These values are supplied to help folks checking status. They are the
-// return values from zt_opt_status.
-int nng_zt_status_configuring = ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION;
-int nng_zt_status_ok = ZT_NETWORK_STATUS_OK;
-int nng_zt_status_denied = ZT_NETWORK_STATUS_ACCESS_DENIED;
-int nng_zt_status_notfound = ZT_NETWORK_STATUS_NOT_FOUND;
-int nng_zt_status_error = ZT_NETWORK_STATUS_PORT_ERROR;
-int nng_zt_status_obsolete = ZT_NETWORK_STATUS_CLIENT_TOO_OLD;
+// return values from zt_opt_status. It's important that the status values
+// here match what the underlying ZeroTier core gives us.
+int nng_zt_network_status_configuring =
+ ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION;
+int nng_zt_network_status_ok = ZT_NETWORK_STATUS_OK;
+int nng_zt_network_status_denied = ZT_NETWORK_STATUS_ACCESS_DENIED;
+int nng_zt_network_status_notfound = ZT_NETWORK_STATUS_NOT_FOUND;
+int nng_zt_network_status_error = ZT_NETWORK_STATUS_PORT_ERROR;
+int nng_zt_network_status_obsolete = ZT_NETWORK_STATUS_CLIENT_TOO_OLD;
// ZeroTier Transport. This sits on the ZeroTier L2 network, which itself
// is implemented on top of UDP. This requires the 3rd party
@@ -248,6 +234,7 @@ struct zt_ep {
zt_node * ze_ztn;
uint64_t ze_nwid;
int ze_mode;
+ int ze_running;
nni_sockaddr ze_addr;
uint64_t ze_raddr; // remote node address
uint64_t ze_laddr; // local node address
@@ -1932,7 +1919,7 @@ zt_pipe_peer(void *arg)
}
static int
-zt_getopt_status(zt_node *ztn, uint64_t nwid, void *buf, size_t *szp)
+zt_getopt_network_status(zt_node *ztn, uint64_t nwid, void *buf, size_t *szp)
{
ZT_VirtualNetworkConfig *vcfg;
int status;
@@ -1990,13 +1977,6 @@ zt_pipe_get_node(void *arg, void *buf, size_t *szp)
return (nni_getopt_u64(p->zp_laddr >> 24, buf, szp));
}
-static int
-zt_pipe_get_status(void *arg, void *buf, size_t *szp)
-{
- zt_pipe *p = arg;
- return (zt_getopt_status(p->zp_ztn, p->zp_nwid, buf, szp));
-}
-
static void
zt_pipe_cancel_ping(nni_aio *aio, int rv)
{
@@ -2308,6 +2288,7 @@ zt_ep_bind_locked(zt_ep *ep)
ep->ze_laddr = ztn->zn_self;
ep->ze_laddr <<= 24;
ep->ze_laddr |= port;
+ ep->ze_running = 1;
if ((rv = nni_idhash_insert(ztn->zn_eps, ep->ze_laddr, ep)) != 0) {
nni_idhash_remove(ztn->zn_ports, port);
@@ -2498,6 +2479,7 @@ zt_ep_connect(void *arg, nni_aio *aio)
nni_aio_list_append(&ep->ze_aios, aio);
ep->ze_creq_try = 1;
+ ep->ze_running = 1;
nni_aio_set_timeout(ep->ze_creq_aio, now + zt_conn_interval);
// This can't fail -- the only way the ze_creq_aio gets
@@ -2543,6 +2525,9 @@ zt_ep_setopt_home(void *arg, const void *data, size_t sz)
return (NNG_EINVAL);
}
if (ep != NULL) {
+ if (ep->ze_running) {
+ return (NNG_ESTATE);
+ }
nni_mtx_lock(&zt_lk);
nni_strlcpy(ep->ze_home, data, sizeof(ep->ze_home));
if ((rv = zt_node_find(ep)) != 0) {
@@ -2584,10 +2569,10 @@ zt_ep_getopt_network_name(void *arg, void *buf, size_t *szp)
}
static int
-zt_ep_getopt_status(void *arg, void *buf, size_t *szp)
+zt_ep_getopt_network_status(void *arg, void *buf, size_t *szp)
{
zt_ep *ep = arg;
- return (zt_getopt_status(ep->ze_ztn, ep->ze_nwid, buf, szp));
+ return (zt_getopt_network_status(ep->ze_ztn, ep->ze_nwid, buf, szp));
}
static int
@@ -2658,7 +2643,7 @@ zt_pipe_getopt_mtu(void *arg, void *data, size_t *szp)
static nni_tran_pipe_option zt_pipe_options[] = {
{ NNG_OPT_LOCADDR, zt_pipe_getopt_locaddr },
{ NNG_OPT_REMADDR, zt_pipe_getopt_remaddr },
- { NNG_ZT_OPT_MTU, zt_pipe_getopt_mtu },
+ { NNG_OPT_ZT_MTU, zt_pipe_getopt_mtu },
// terminate list
{ NULL, NULL },
};
@@ -2680,37 +2665,37 @@ static nni_tran_ep_option zt_ep_options[] = {
.eo_setopt = zt_ep_setopt_recvmaxsz,
},
{
- .eo_name = NNG_ZT_OPT_HOME,
+ .eo_name = NNG_OPT_ZT_HOME,
.eo_getopt = zt_ep_getopt_home,
.eo_setopt = zt_ep_setopt_home,
},
{
- .eo_name = NNG_ZT_OPT_NODE,
+ .eo_name = NNG_OPT_ZT_NODE,
.eo_getopt = zt_ep_getopt_node,
.eo_setopt = NULL,
},
{
- .eo_name = NNG_ZT_OPT_NWID,
+ .eo_name = NNG_OPT_ZT_NWID,
.eo_getopt = zt_ep_getopt_nwid,
.eo_setopt = NULL,
},
{
- .eo_name = NNG_ZT_OPT_STATUS,
- .eo_getopt = zt_ep_getopt_status,
+ .eo_name = NNG_OPT_ZT_NETWORK_STATUS,
+ .eo_getopt = zt_ep_getopt_network_status,
.eo_setopt = NULL,
},
{
- .eo_name = NNG_ZT_OPT_NETWORK_NAME,
+ .eo_name = NNG_OPT_ZT_NETWORK_NAME,
.eo_getopt = zt_ep_getopt_network_name,
.eo_setopt = NULL,
},
{
- .eo_name = NNG_ZT_OPT_PING_TIME,
+ .eo_name = NNG_OPT_ZT_PING_TIME,
.eo_getopt = zt_ep_getopt_ping_time,
.eo_setopt = zt_ep_setopt_ping_time,
},
{
- .eo_name = NNG_ZT_OPT_PING_COUNT,
+ .eo_name = NNG_OPT_ZT_PING_COUNT,
.eo_getopt = zt_ep_getopt_ping_count,
.eo_setopt = zt_ep_setopt_ping_count,
},
diff --git a/src/transport/zerotier/zerotier.h b/src/transport/zerotier/zerotier.h
new file mode 100644
index 00000000..ff33609e
--- /dev/null
+++ b/src/transport/zerotier/zerotier.h
@@ -0,0 +1,110 @@
+//
+// 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
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef NNG_TRANSPORT_ZEROTIER_ZEROTIER_H
+#define NNG_TRANSPORT_ZEROTIER_ZEROTIER_H
+
+// ZeroTier Transport. This sits on the ZeroTier L2 network, which itself
+// is implemented on top of UDP. This requires the 3rd party
+// libzerotiercore library (which is GPLv3!) and platform specific UDP
+// functionality to be built in. Note that care must be taken to link
+// dynamically if one wishes to avoid making your entire application GPL3.
+// (Alternatively ZeroTier offers commercial licenses which may prevent
+// this particular problem.) This implementation does not make use of
+// certain advanced capabilities in ZeroTier such as more sophisticated
+// route management and TCP fallback. You need to have connectivity
+// to the Internet to use this. (Or at least to your Planetary root.)
+//
+// The ZeroTier URL format we support is zt://<nwid>/<ztid>:<port> where
+// the <nwid> component represents the 64-bit hexadecimal ZeroTier
+// network ID,the <ztid> represents the 40-bit hexadecimal ZeroTier
+// node (device) ID, and the <port> is a 24-bit (decimal) port number.
+//
+// A listener may elide the <ztid>/ portion, to just bind to itself,
+// in which case the format will be zt://<nwid>:<port>
+//
+// A listener may also use either 0 or * for the <port> to indicate that
+// a random local ephemeral port should be used.
+//
+// Because ZeroTier takes a while to establish connectivity, it is even
+// more important that applications using the ZeroTier transport not
+// assume that a connection will be immediately available. It can take
+// quite a few seconds for peer-to-peer connectivity to be established.
+//
+// The ZeroTier transport was funded by Capitar IT Group, BV.
+//
+// This transport is highly experimental.
+
+// ZeroTier transport-specific options.
+
+// NNG_OPT_ZT_HOME is a string containing a directory, where persistent
+// state (key files, etc.) will be stored. It should be protected from
+// unauthorized viewing and modification. This option must be set on an
+// endpoint or socket before the endpoint(s) are started. If the unset,
+// or an empty string, then no persistence is used and an ephemeral node
+// will be created instead. Note that different endpoints may use different
+// values for this option, and that will lead to each endpoint having a
+// different ZeroTier identity -- however only one ephemeral node will
+// be created for the application.
+#define NNG_OPT_ZT_HOME "zt:home"
+
+// NNG_OPT_ZT_NWID is the 64-bit network ID, represented using a uint64_t in
+// native byte order. This is a read-only option; it is derived automatically
+// from the URL.
+#define NNG_OPT_ZT_NWID "zt:nwid"
+
+// NNG_OPT_ZT_NODE is the 40-bit node ID, stored in native order in the low
+// 40-bits of a uint64_t, of the node. This is a read-only option.
+#define NNG_OPT_ZT_NODE "zt:node"
+
+// NNG_OPT_ZT_NETWORK_STATUS represents the status of the ZeroTier virtual
+// network. The option is a read-only value, stored as an integer, which
+// takes of the nng_zt_network_status_xxx values listed below.
+#define NNG_OPT_ZT_NETWORK_STATUS "zt:network-status"
+
+// NNG_OPT_ZT_NETWORK_NAME is a human-readable name for the ZeroTier virtual
+// network. This will only be set once the ZeroTier network has come up
+// as the name comes from the network controller. This is read-only, and
+// is presented as an ASCIIZ string.
+#define NNG_OPT_ZT_NETWORK_NAME "zt:network-name"
+
+// NNG_OPT_ZT_PING_TIME and NNG_OPT_ZT_PING_COUNT are used to send ping
+// requests when a connection appears to be idled. If a logical session
+// has not received traffic from it's peer for ping-time, then a ping packet
+// is sent. This will be done up to ping-count times. If no traffic from
+// the remote peer is seen after all ping requests are sent, then the peer
+// is assumed to be dead or offline, and the session is closed. The
+// NNG_OPT_ZT_PING_TIME is a duration (usec, stored as an nng_duration, and
+// NNG_OPT_ZT_PING_COUNT is an integer.) This ping process can be disabled
+// by setting either ping-time or ping-count to zero.
+#define NNG_OPT_ZT_PING_TIME "zt:ping-time"
+#define NNG_OPT_ZT_PING_COUNT "zt:ping-count"
+
+// NNG_OPT_ZT_MTU is a read-only size_t and contains the ZeroTier virtual
+// network MTU (i.e. the L2 payload MTU). Messages that are larger than this
+// (including our 20-byte header data) will be fragmented into multiple
+// virtual L2 frames.
+#define NNG_OPT_ZT_MTU "zt:mtu"
+
+// Network status values.
+// These values are supplied to help folks checking status. They are the
+// return values from zt_opt_status. We avoid hard coding them as defines,
+// to keep applications from baking in values that may change if the
+// underlying ZeroTier transport changes.
+extern int nng_zt_network_status_configuring;
+extern int nng_zt_network_status_ok;
+extern int nng_zt_network_status_denied;
+extern int nng_zt_network_status_notfound;
+extern int nng_zt_network_status_error;
+extern int nng_zt_network_status_obsolete;
+
+extern int nng_zt_register(void);
+
+#endif // NNG_TRANSPORT_ZEROTIER_ZEROTIER_H
diff --git a/tests/sock.c b/tests/sock.c
index ca125214..f2afde4c 100644
--- a/tests/sock.c
+++ b/tests/sock.c
@@ -426,33 +426,6 @@ TestMain("Socket Operations", {
});
- 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_RECVMAXSZ, 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_RECVMAXSZ, 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;
diff --git a/tests/zt.c b/tests/zt.c
index b57d0f5b..1e6992b4 100644
--- a/tests/zt.c
+++ b/tests/zt.c
@@ -11,12 +11,7 @@
#include "convey.h"
#include "trantest.h"
-extern int nng_zt_register(void);
-extern const char *nng_opt_zt_home;
-extern const char *nng_opt_zt_node;
-extern const char *nng_opt_zt_status;
-extern const char *nng_opt_zt_network_name;
-extern int nng_zt_status_ok;
+#include "transport/zerotier/zerotier.h"
// zerotier tests.
@@ -24,6 +19,10 @@ extern int nng_zt_status_ok;
// Do not attach to it in production.
#define NWID "a09acf02337b057b"
+// This network is a closed network, which nothing can join. We use it for
+// testing permission denied.
+#define CLOSED_NWID "17d709436ce162a3"
+
#ifdef _WIN32
int
@@ -42,49 +41,143 @@ check_props(nng_msg *msg, nng_listener l, nng_dialer d)
nng_sockaddr la, ra;
nng_pipe p;
size_t z;
- size_t mtu;
- uint64_t nwid;
p = nng_msg_get_pipe(msg);
So(p > 0);
// Check local address.
- z = sizeof(nng_sockaddr);
- So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0);
- So(z == sizeof(la));
- So(la.s_un.s_family == NNG_AF_ZT);
- So(la.s_un.s_zt.sa_port == (trantest_port - 1));
- So(la.s_un.s_zt.sa_nwid == 0xa09acf02337b057bull);
- So(la.s_un.s_zt.sa_nodeid != 0);
-
- // Check remote address.
- z = sizeof(nng_sockaddr);
- So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0);
- So(z == sizeof(ra));
- So(ra.s_un.s_family == NNG_AF_ZT);
- So(ra.s_un.s_zt.sa_port != 0);
- So(ra.s_un.s_zt.sa_nwid == 0xa09acf02337b057bull);
- So(ra.s_un.s_zt.sa_nodeid == la.s_un.s_zt.sa_nodeid);
-
- // Check network ID.
- z = sizeof(nwid);
- nwid = 0;
- So(nng_pipe_getopt(p, "zt:nwid", &nwid, &z) == 0);
- So(nwid = 0xa09acf02337b057bull);
-
- z = sizeof(nwid);
- nwid = 0;
- So(nng_dialer_getopt(d, "zt:nwid", &nwid, &z) == 0);
- So(nwid = 0xa09acf02337b057bull);
-
- z = sizeof(nwid);
- nwid = 0;
- So(nng_listener_getopt(l, "zt:nwid", &nwid, &z) == 0);
- So(nwid = 0xa09acf02337b057bull);
-
- // Check MTU
- z = sizeof(mtu);
- So(nng_pipe_getopt(p, "zt:mtu", &mtu, &z) == 0);
- So(mtu >= 1000 && mtu <= 10000);
+ Convey("Local address property works", {
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0);
+ So(z == sizeof(la));
+ So(la.s_un.s_family == NNG_AF_ZT);
+ So(la.s_un.s_zt.sa_port == (trantest_port - 1));
+ So(la.s_un.s_zt.sa_nwid == 0xa09acf02337b057bull);
+ So(la.s_un.s_zt.sa_nodeid != 0);
+ });
+
+ Convey("Remote address property works", {
+ // Check remote address.
+ uint64_t mynode;
+
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0);
+ So(z == sizeof(ra));
+ So(ra.s_un.s_family == NNG_AF_ZT);
+ So(ra.s_un.s_zt.sa_port != 0);
+ So(ra.s_un.s_zt.sa_nwid == 0xa09acf02337b057bull);
+
+ z = sizeof(mynode);
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_NODE, &mynode, &z) == 0);
+ So(mynode != 0);
+ So(ra.s_un.s_zt.sa_nodeid == mynode);
+
+ So(nng_dialer_getopt(d, NNG_OPT_REMADDR, &ra, &z) != 0);
+ });
+
+ Convey("NWID property works", {
+ uint64_t nwid;
+
+ z = sizeof(nwid);
+ nwid = 0;
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_NWID, &nwid, &z) == 0);
+ So(nwid = 0xa09acf02337b057bull);
+
+ z = sizeof(nwid);
+ nwid = 0;
+ So(nng_dialer_getopt(d, NNG_OPT_ZT_NWID, &nwid, &z) == 0);
+ So(nwid = 0xa09acf02337b057bull);
+
+ z = sizeof(nwid);
+ nwid = 0;
+ So(nng_listener_getopt(l, NNG_OPT_ZT_NWID, &nwid, &z) == 0);
+ So(nwid = 0xa09acf02337b057bull);
+ });
+
+ Convey("Network status property works", {
+ int s;
+ z = sizeof(s);
+ s = 0;
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_NETWORK_STATUS, &s, &z) == 0);
+ So(s == nng_zt_network_status_ok);
+
+ z = sizeof(s);
+ s = 0;
+ So(nng_dialer_getopt(d, NNG_OPT_ZT_NETWORK_STATUS, &s, &z) ==
+ 0);
+ So(s == nng_zt_network_status_ok);
+
+ z = sizeof(s);
+ s = 0;
+ So(nng_listener_getopt(l, NNG_OPT_ZT_NETWORK_STATUS, &s, &z) ==
+ 0);
+ So(s == nng_zt_network_status_ok);
+
+ So(nng_dialer_setopt(d, NNG_OPT_ZT_NETWORK_STATUS, &s, z) ==
+ NNG_EREADONLY);
+ So(nng_listener_setopt(l, NNG_OPT_ZT_NETWORK_STATUS, &s, z) ==
+ NNG_EREADONLY);
+ });
+
+ Convey("Ping properties work", {
+ int c;
+ uint64_t u;
+ z = sizeof(c);
+ c = 0;
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_PING_COUNT, &c, &z) == 0);
+ So(c > 0 && c < 10); // actually 5...
+
+ z = sizeof(u);
+ u = 0;
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_PING_TIME, &u, &z) == 0);
+ So(u > 1000000 && u < 3600000000ull); // 1 sec - 1 hour
+
+ c = 0;
+ So(nng_dialer_getopt_int(d, NNG_OPT_ZT_PING_COUNT, &c) == 0);
+ So(c > 0 && c < 10); // actually 5...
+
+ z = sizeof(u);
+ u = 0;
+ So(nng_dialer_getopt_usec(d, NNG_OPT_ZT_PING_TIME, &u) == 0);
+ So(u > 1000000 && u < 3600000000ull); // 1 sec - 1 hour
+
+ int rv = nng_dialer_setopt_int(d, NNG_OPT_ZT_PING_COUNT, 20);
+
+ So(nng_dialer_setopt_int(d, NNG_OPT_ZT_PING_COUNT, 20) == 0);
+ So(nng_dialer_setopt_usec(d, NNG_OPT_ZT_PING_TIME, 2000000) ==
+ 0);
+ So(nng_listener_setopt_int(l, NNG_OPT_ZT_PING_COUNT, 0) == 0);
+ So(nng_listener_setopt_usec(l, NNG_OPT_ZT_PING_TIME, 0) == 0);
+ });
+
+ Convey("Home property works", {
+ char v[256];
+ z = sizeof(v);
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_HOME, v, &z) == 0);
+ So(strlen(v) < sizeof(v));
+
+ z = sizeof(v);
+ So(nng_dialer_getopt(d, NNG_OPT_ZT_HOME, v, &z) == 0);
+ So(strlen(v) < sizeof(v));
+
+ z = sizeof(v);
+ So(nng_listener_getopt(l, NNG_OPT_ZT_HOME, v, &z) == 0);
+ So(strlen(v) < sizeof(v));
+
+ z = strlen("/tmp/bogus") + 1;
+ So(nng_dialer_setopt(d, NNG_OPT_ZT_HOME, "/tmp/bogus", z) ==
+ NNG_ESTATE);
+ So(nng_listener_setopt(l, NNG_OPT_ZT_HOME, "/tmp/bogus", z) ==
+ NNG_ESTATE);
+ });
+
+ Convey("MTU property works", {
+ size_t mtu;
+
+ // Check MTU
+ z = sizeof(mtu);
+ So(nng_pipe_getopt(p, NNG_OPT_ZT_MTU, &mtu, &z) == 0);
+ So(mtu >= 1000 && mtu <= 10000);
+ });
return (0);
}
@@ -117,7 +210,7 @@ TestMain("ZeroTier Transport", {
mkdir(path1, 0700);
- So(nng_listener_setopt(l, nng_opt_zt_home, path1,
+ So(nng_listener_setopt(l, NNG_OPT_ZT_HOME, path1,
strlen(path1) + 1) == 0);
So(nng_listener_start(l, 0) == 0);
@@ -157,7 +250,7 @@ TestMain("ZeroTier Transport", {
So(nng_listener_create(&l, s, addr) == 0);
- So(nng_listener_getopt_usec(l, nng_opt_zt_node, &node1) == 0);
+ So(nng_listener_getopt_usec(l, NNG_OPT_ZT_NODE, &node1) == 0);
So(node1 != 0);
Convey("Network name & status options work", {
@@ -167,19 +260,19 @@ TestMain("ZeroTier Transport", {
namesz = sizeof(name);
nng_usleep(10000000);
- So(nng_listener_getopt(l, nng_opt_zt_network_name,
+ So(nng_listener_getopt(l, NNG_OPT_ZT_NETWORK_NAME,
name, &namesz) == 0);
So(strcmp(name, "nng_test_open") == 0);
So(nng_listener_getopt_int(
- l, nng_opt_zt_status, &status) == 0);
- So(status == nng_zt_status_ok);
+ l, NNG_OPT_ZT_NETWORK_STATUS, &status) == 0);
+ So(status == nng_zt_network_status_ok);
});
Convey("Connection refused works", {
snprintf(addr, sizeof(addr), "zt://" NWID "/%llx:%u",
(unsigned long long) node1, 42u);
So(nng_dialer_create(&d, s, addr) == 0);
So(nng_dialer_getopt_usec(
- d, nng_opt_zt_node, &node2) == 0);
+ d, NNG_OPT_ZT_NODE, &node2) == 0);
So(node2 == node1);
So(nng_dialer_start(d, 0) == NNG_ECONNREFUSED);
});
@@ -206,24 +299,24 @@ TestMain("ZeroTier Transport", {
nng_close(s1);
// This sleep allows us to ensure disconnect
// messages work.
- nng_usleep(1000000);
+ nng_usleep(500000);
nng_close(s2);
});
So(nng_listener_create(&l, s1, addr1) == 0);
So(nng_listener_setopt(
- l, nng_opt_zt_home, path1, strlen(path1) + 1) == 0);
+ l, NNG_OPT_ZT_HOME, path1, strlen(path1) + 1) == 0);
So(nng_listener_start(l, 0) == 0);
node = 0;
- So(nng_listener_getopt_usec(l, nng_opt_zt_node, &node) == 0);
+ So(nng_listener_getopt_usec(l, NNG_OPT_ZT_NODE, &node) == 0);
So(node != 0);
snprintf(addr2, sizeof(addr2), "zt://" NWID "/%llx:%u",
(unsigned long long) node, port);
So(nng_dialer_create(&d, s2, addr2) == 0);
So(nng_dialer_setopt(
- d, nng_opt_zt_home, path2, strlen(path2) + 1) == 0);
+ d, NNG_OPT_ZT_HOME, path2, strlen(path2) + 1) == 0);
So(nng_dialer_start(d, 0) == 0);
});