Skip to content

Commit

Permalink
ZeroTier transport implementation (work funded by Capitar IT Group BV)
Browse files Browse the repository at this point in the history
The ZeroTier transport is experimental at this point, and not enabled
by default.  It does not work with Windows yet (the Windows platform
needs UDP support first.)

Configure with -DNNG_ENABLE_ZEROTIER=yes -DNNG_ZEROTIER_SOUCE=<path>
The <path> must point to a dev branch of the ZeroTierOne source tree,
checked out, and built with a libzerotiercore.a in the top directory,
and a ZeroTierOne.h header located at include.  The build will add
-lc++ to the compile, as the ZeroTier core functionality is written in
C++ and needs some runtime support (e.g. new, delete, etc.)
  • Loading branch information
gdamore committed Sep 26, 2017
1 parent 52118e4 commit 86a96e5
Show file tree
Hide file tree
Showing 12 changed files with 3,378 additions and 17 deletions.
40 changes: 39 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#
# Copyright 2017 Garrett D'Amore <[email protected]>
# Copyright 2017 Capitar IT Group BV <[email protected]>
# Copyright (c) 2012 Martin Sustrik All rights reserved.
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
# Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved.
Expand Down Expand Up @@ -91,7 +93,8 @@ option (NNG_TESTS "Build and run tests" ON)
option (NNG_TOOLS "Build extra tools" OFF)
option (NNG_ENABLE_NNGCAT "Enable building nngcat utility." ${NNG_TOOLS})
option (NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)

option (NNG_ENABLE_ZEROTIER "Enable ZeroTier transport (requires libzerotiercore)." OFF)
set (NNG_ZEROTIER_SOURCE "" CACHE PATH "Location of ZeroTier source tree.")
# Enable access to private APIs for our own use.
add_definitions (-DNNG_PRIVATE)

Expand Down Expand Up @@ -244,6 +247,39 @@ nng_check_sym (strlcat string.h NNG_HAVE_STRLCAT)
nng_check_sym (strlcpy string.h NNG_HAVE_STRLCPY)
nng_check_sym (strnlen string.h NNG_HAVE_STRNLEN)

# Search for ZeroTier
# We use the libzerotiercore.a library, which is unfortunately a C++ object
# even though it exposes only public C symbols. It would be extremely
# helpful if libzerotiercore didn't make us carry the whole C++ runtime
# behind us. The user must specify the location of the ZeroTier source
# tree (dev branch for now, and already compiled please) by setting the
# NNG_ZEROTIER_SOURCE macro.
# NB: This needs to be the zerotierone tree, not the libzt library.
# This is because we don't access the API, but instead use the low
# level zerotiercore functionality directly.
# NB: As we wind up linking libzerotiercore.a into the application,
# this means that your application will *also* need to either be licensed
# under the GPLv3, or you will need to have a commercial license from
# ZeroTier permitting its use elsewhere.
if (NNG_ENABLE_ZEROTIER)
enable_language(CXX)
find_library(NNG_LIBZTCORE zerotiercore PATHS ${NNG_ZEROTIER_SOURCE})
if (NNG_LIBZTCORE)
set(CMAKE_REQUIRED_INCLUDES ${NNG_ZEROTIER_SOURCE}/include)
# set(CMAKE_REQUIRED_LIBRARIES ${NNG_LIBZTCORE} c++)
# set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} ${NNG_LIBZTCORE} c++)
message(STATUS "C++ ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES ${NNG_LIBZTCORE} ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} ${NNG_LIBZTCORE} ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
set(NNG_REQUIRED_INCLUDES ${NNG_REQUIRED_INCLUDES} ${NNG_ZEROTIER_SOURCE}/include)
nng_check_sym(ZT_Node_join ZeroTierOne.h NNG_HAVE_ZEROTIER)
endif()
if (NOT NNG_HAVE_ZEROTIER)
message (FATAL_ERROR "Cannot find ZeroTier components")
endif()
message(STATUS "Found ZeroTier at ${NNG_LIBZTCORE}")
endif()

add_subdirectory (src)

if (NNG_TESTS)
Expand All @@ -253,6 +289,7 @@ if (NNG_TESTS)
add_subdirectory (perf)
endif()


# Build the tools

if (NNG_ENABLE_NNGCAT)
Expand All @@ -270,6 +307,7 @@ if (NNG_ENABLE_DOC)
endif ()
endif ()


# Build the documenation
if (NNG_ENABLE_DOC)

Expand Down
8 changes: 7 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ set (NNG_SOURCES
transport/ipc/ipc.c

transport/tcp/tcp.c

)

if (NNG_PLATFORM_POSIX)
Expand Down Expand Up @@ -140,7 +141,12 @@ if (NNG_PLATFORM_WINDOWS)
)
endif()

include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src)
if (NNG_ENABLE_ZEROTIER)
set (NNG_SOURCES ${NNG_SOURCES} transport/zerotier/zerotier.c)
endif()

include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src
${NNG_REQUIRED_INCLUDES})

# Provide same folder structure in IDE as on disk
foreach (f ${NNG_SOURCES})
Expand Down
27 changes: 27 additions & 0 deletions src/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,33 @@ extern void nni_plat_pipe_clear(int);
// routine.
extern void nni_plat_pipe_close(int, int);

//
// File/Store Support
//
// Some transports require a persistent storage for things like
// key material, etc. Generally, these are all going to be relatively
// small objects (such as certificates), so we ony require a synchronous
// implementation from platforms. This Key-Value API is intended to
// to support using the Key's as filenames, and keys will consist of
// only these characters: [0-9a-zA-Z._-]. The directory used should be
// determined by using an environment variable (NNG_STATE_DIR), or
// using some other application-specific method.
//

// nni_plat_file_put writes the named file, with the provided data,
// and the given size. If the file already exists it is overwritten.
// The permissions on the file should be limited to read and write
// access by the entity running the application only.
extern int nni_plat_file_put(const char *, const void *, int);

// nni_plat_file_get reads the entire named file, allocating storage
// to receive the data and returning the data and the size in the
// reference arguments.
extern int nni_plat_file_get(const char *, void **, int *);

// nni_plat_file_delete deletes the named file.
extern int nni_plat_file_delete(const char *);

// Actual platforms we support. This is included up front so that we can
// get the specific types that are supplied by the platform.
#if defined(NNG_PLATFORM_POSIX)
Expand Down
13 changes: 12 additions & 1 deletion src/nng.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// Pretty much every function calls the nni_platform_init to check against
// fork related activity.

#include <stdio.h>
#include <string.h>

void
Expand Down Expand Up @@ -650,6 +651,7 @@ static const struct {
const char *
nng_strerror(int num)
{
static char unknownerrbuf[32];
for (int i = 0; nni_errors[i].msg != NULL; i++) {
if (nni_errors[i].code == num) {
return (nni_errors[i].msg);
Expand All @@ -660,7 +662,16 @@ nng_strerror(int num)
return (nni_plat_strerror(num & ~NNG_ESYSERR));
}

return ("Unknown error");
if (num & NNG_ETRANERR) {
static char tranerrbuf[32];
(void) snprintf(tranerrbuf, sizeof(tranerrbuf),
"Transport error #%d", num & ~NNG_ETRANERR);
return (tranerrbuf);
}

(void) snprintf(
unknownerrbuf, sizeof(unknownerrbuf), "Unknown error #%d", num);
return (unknownerrbuf);
}

int
Expand Down
43 changes: 30 additions & 13 deletions src/nng.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,23 @@ NNG_DECL void nng_thread_destroy(void *);

// Error codes. These may happen to align to errnos used on your platform,
// but do not count on this.
//
// NNG_SYSERR is a special code, which allows us to wrap errors from the
// underlying operating system. We generally prefer to map errors to one
// of the above, but if we cannot, then we just encode an error this way.
// The bit is large enough to accommodate all known UNIX and Win32 error
// codes. We try hard to match things semantically to one of our standard
// errors. For example, a connection reset or aborted we treat as a
// closed connection, because that's basically what it means. (The remote
// peer closed the connection.) For certain kinds of resource exhaustion
// we treat it the same as memory. But for files, etc. that's OS-specific,
// and we use the generic below. Some of the above error codes we use
// internally, and the application should never see (e.g. NNG_EINTR).
//
// NNG_ETRANERR is like ESYSERR, but is used to wrap transport specific
// errors, from different transports. It should only be used when none
// of the other options are available.

enum nng_errno_enum {
NNG_EINTR = 1,
NNG_ENOMEM = 2,
Expand All @@ -582,21 +599,11 @@ enum nng_errno_enum {
NNG_ENOSPC = 22,
NNG_EEXIST = 23,
NNG_EINTERNAL = 24,
NNG_ETRANSPORT = 25,
NNG_ESYSERR = 0x10000000,
NNG_ETRANERR = 0x20000000,
};

// NNG_SYSERR is a special code, which allows us to wrap errors from the
// underlyuing operating system. We generally prefer to map errors to one
// of the above, but if we cannot, then we just encode an error this way.
// The bit is large enough to accommodate all known UNIX and Win32 error
// codes. We try hard to match things semantically to one of our standard
// errors. For example, a connection reset or aborted we treat as a
// closed connection, because that's basically what it means. (The remote
// peer closed the connection.) For certain kinds of resource exhaustion
// we treat it the same as memory. But for files, etc. that's OS-specific,
// and we use the generic below. Some of the above error codes we use
// internally, and the application should never see (e.g. NNG_EINTR).
#define NNG_ESYSERR (0x10000000)

// Maximum length of a socket address. This includes the terminating NUL.
// This limit is built into other implementations, so do not change it.
#define NNG_MAXADDRLEN (128)
Expand Down Expand Up @@ -627,16 +634,25 @@ struct nng_sockaddr_in {
uint16_t sa_port;
uint32_t sa_addr;
};

struct nng_sockaddr_zt {
uint64_t sa_nwid;
uint64_t sa_nodeid;
uint32_t sa_port;
};

typedef struct nng_sockaddr_in nng_sockaddr_in;
typedef struct nng_sockaddr_in nng_sockaddr_udp;
typedef struct nng_sockaddr_in nng_sockaddr_tcp;
typedef struct nng_sockaddr_zt nng_sockaddr_zt;

typedef struct nng_sockaddr {
union {
uint16_t s_family;
nng_sockaddr_path s_path;
nng_sockaddr_in6 s_in6;
nng_sockaddr_in s_in;
nng_sockaddr_zt s_zt;
} s_un;
} nng_sockaddr;

Expand All @@ -646,6 +662,7 @@ enum nng_sockaddr_family {
NNG_AF_IPC = 2,
NNG_AF_INET = 3,
NNG_AF_INET6 = 4,
NNG_AF_ZT = 5, // ZeroTier
};

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion src/platform/posix/posix_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ nni_plat_udp_open(nni_plat_udp **upp, nni_sockaddr *bindaddr)
}

// UDP opens can actually run synchronously.
if ((udp = NNI_ALLOC_STRUCT(udp)) != NULL) {
if ((udp = NNI_ALLOC_STRUCT(udp)) == NULL) {
return (NNG_ENOMEM);
}
nni_mtx_init(&udp->udp_mtx);
Expand Down
Loading

0 comments on commit 86a96e5

Please sign in to comment.