diff --git a/ext/picotcp/stack/pico_socket.c b/ext/picotcp/stack/pico_socket.c
index a9df66d..f36cb80 100644
--- a/ext/picotcp/stack/pico_socket.c
+++ b/ext/picotcp/stack/pico_socket.c
@@ -1568,7 +1568,7 @@ int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
}
-int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t remote_port)
+extern int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t remote_port)
{
int ret = -1;
pico_err = PICO_ERR_EPROTONOSUPPORT;
diff --git a/include/ZeroTierSDK.h b/include/ZeroTierSDK.h
index d9f8eaf..c41049a 100644
--- a/include/ZeroTierSDK.h
+++ b/include/ZeroTierSDK.h
@@ -1,5 +1,5 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
+ * ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
@@ -16,10 +16,6 @@
* along with this program. If not, see .
*/
-/*
- * This defines the external C++ API for the ZeroTier SDK's service
- */
-
#ifndef ZT_ZEROTIERSDK_H
#define ZT_ZEROTIERSDK_H
@@ -29,21 +25,21 @@
/* Defines */
/****************************************************************************/
-#define SDK_MTU 1200 // FIXME: ZT_MAX_MTU, usually
-#define UNIX_SOCK_BUF_SIZE 1024*1024
-#define ZT_PHY_POLL_INTERVAL 50 // in ms
+#define ZT_SDK_MTU ZT_MAX_MTU
+#define ZT_PHY_POLL_INTERVAL 50 // ms
+#define ZT_ACCEPT_RECHECK_DELAY 250 // ms (for blocking zts_accept() calls)
// picoTCP
#define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128
// TCP
-#define DEFAULT_TCP_TX_BUF_SZ 1024 * 1024
-#define DEFAULT_TCP_RX_BUF_SZ 1024 * 1024
-#define DEFAULT_TCP_TX_BUF_SOFTMAX DEFAULT_TCP_TX_BUF_SZ * 0.80
-#define DEFAULT_TCP_TX_BUF_SOFTMIN DEFAULT_TCP_TX_BUF_SZ * 0.20
-#define DEFAULT_TCP_RX_BUF_SOFTMAX DEFAULT_TCP_RX_BUF_SZ * 0.80
-#define DEFAULT_TCP_RX_BUF_SOFTMIN DEFAULT_TCP_RX_BUF_SZ * 0.20
+#define ZT_TCP_TX_BUF_SZ 1024 * 1024
+#define ZT_TCP_RX_BUF_SZ 1024 * 1024
+#define ZT_TCP_TX_BUF_SOFTMAX ZT_TCP_TX_BUF_SZ * 0.80
+#define ZT_TCP_TX_BUF_SOFTMIN ZT_TCP_TX_BUF_SZ * 0.20
+#define ZT_TCP_RX_BUF_SOFTMAX ZT_TCP_RX_BUF_SZ * 0.80
+#define ZT_TCP_RX_BUF_SOFTMIN ZT_TCP_RX_BUF_SZ * 0.20
// UDP
-#define DEFAULT_UDP_TX_BUF_SZ ZT_MAX_MTU
-#define DEFAULT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10
+#define ZT_UDP_TX_BUF_SZ ZT_MAX_MTU
+#define ZT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10
#define ZT_SDK_RPC_DIR_PREFIX "rpc.d"
@@ -56,6 +52,8 @@
#define ZT_VER_STR_LEN 6
#define ZT_HOME_PATH_MAX_LEN 128
+#define ZT_ERR_OK 0
+
/****************************************************************************/
/* Socket API Signatures */
/****************************************************************************/
@@ -68,8 +66,8 @@
#define ZT_RECVFROM_SIG int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen
#define ZT_RECVMSG_SIG int fd, struct msghdr *msg,int flags
#define ZT_SEND_SIG int fd, const void *buf, size_t len, int flags
-#define ZT_WRITE_SIG int fd, const void *buf, size_t len
#define ZT_READ_SIG int fd, void *buf, size_t len
+#define ZT_WRITE_SIG int fd, const void *buf, size_t len
#define ZT_SOCKET_SIG int socket_family, int socket_type, int protocol
#define ZT_CONNECT_SIG int fd, const struct sockaddr *addr, socklen_t addrlen
#define ZT_BIND_SIG int fd, const struct sockaddr *addr, socklen_t addrlen
@@ -230,16 +228,23 @@ int zts_socket(ZT_SOCKET_SIG);
int zts_connect(ZT_CONNECT_SIG);
/**
- * Bind a socket to a local address
+ * Binds a socket to a specific address
+ * - To accept connections on a specific ZeroTier network you must
+ * use this bind call with an address which is associated with that network
+ *
+ * For instance, given the following networks:
+ * - nwid = 97afaf1963cc6a90 (10.9.0.0/24)
+ * - nwid = 23bfae5663c8b188 (192.168.0.0/24)
+ *
+ * In order to accept a connection on 97afaf1963cc6a90, you
+ * should bind to 10.9.0.0
*/
int zts_bind(ZT_BIND_SIG);
/**
- * Accept a connection
+ * Listen for incoming connections
*/
-#if defined(__linux__)
- int zts_accept4(ZT_ACCEPT4_SIG);
-#endif
+int zts_listen(ZT_LISTEN_SIG);
/**
* Accept a connection
@@ -247,9 +252,11 @@ int zts_bind(ZT_BIND_SIG);
int zts_accept(ZT_ACCEPT_SIG);
/**
- * Listen for incoming connections
+ * Accept a connection
*/
-int zts_listen(ZT_LISTEN_SIG);
+#if defined(__linux__)
+ int zts_accept4(ZT_ACCEPT4_SIG);
+#endif
/**
* Set socket options
@@ -301,46 +308,32 @@ ssize_t zts_recvfrom(ZT_RECVFROM_SIG);
*/
ssize_t zts_recvmsg(ZT_RECVMSG_SIG);
+/**
+ * Read bytes from socket onto buffer
+ * - Note, this function isn't strictly necessary, you can
+ * use a regular read() call as long as the socket fd was
+ * created via a zts_socket() call.
+ */
+int zts_read(ZT_READ_SIG);
+
+/**
+ * Write bytes from buffer to socket
+ * - Note, this function isn't strictly necessary, you can
+ * use a regular write() call as long as the socket fd was
+ * created via a zts_socket() call.
+ */
+int zts_write(ZT_WRITE_SIG);
+
/****************************************************************************/
-/* SocketTap Multiplexer Functionality --- DONT CALL THESE DIRECTLY */
-/* - This section of the API is used to implement the general socket */
-/* controls. Basically this is designed to handle socket provisioning */
-/* requests when no SocketTap is yet initialized, and as a way to */
-/* determine which SocketTap is to be used for a particular connect() or */
-/* bind() call */
+/* SDK Socket API Helper functions/objects --- DONT CALL THESE DIRECTLY */
/****************************************************************************/
namespace ZeroTier
{
- class picoTCP;
- struct Connection;
- extern ZeroTier::picoTCP *picostack;
+ class picoTCP;
+ extern ZeroTier::picoTCP *picostack;
}
-/**
- * Creates a new Connection objects and keeps it in UnassignedConnections
- * until a connect() or bind() call is made, at which point it is assigned
- * to the appropriate SocketTap.
- */
-int zts_multiplex_new_socket(ZT_SOCKET_SIG);
-
-/**
- * Given a file descriptor, looks up the relevant Connection object and then
- * searches for a SocketTap with an appropriate route. Once found, the
- * Connection object will be assigned to that SocketTap and a connection
- * to the remote host will be attempted.
- */
-int zts_multiplex_new_connect(ZT_CONNECT_SIG);
-
-/**
- *
- */
-int zts_multiplex_new_bind(ZT_BIND_SIG);
-
-/****************************************************************************/
-/* SDK Socket API Helper functions --- DONT CALL THESE DIRECTLY */
-/****************************************************************************/
-
/**
* Don't call this directly, use 'zts_start()'
*/
@@ -423,22 +416,22 @@ void *_start_service(void *thread_id);
#if ZT_DEBUG_LEVEL >= ZT_MSG_INFO
#if defined(__ANDROID__)
#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_INFO : %14s:%4d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_INFO : %16s:%4d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#define DEBUG_BLANK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_INFO : %14s:%4d:" fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_INFO : %16s:%4d:" fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#define DEBUG_ATTN(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_INFO : %14s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_INFO : %16s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#define DEBUG_STACK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_STACK: %14s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_STACK: %16s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else
#define DEBUG_INFO(fmt, args...) fprintf(stderr, \
- "ZT_INFO [%ld] : %14s:%4d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
+ "ZT_INFO [%ld] : %16s:%4d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ATTN(fmt, args...) fprintf(stderr, ZT_CYN \
- "ZT_ATTN [%ld] : %14s:%4d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
+ "ZT_ATTN [%ld] : %16s:%4d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_STACK(fmt, args...) fprintf(stderr, ZT_YEL \
- "ZT_STACK[%ld] : %14s:%4d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
+ "ZT_STACK[%ld] : %16s:%4d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_BLANK(fmt, args...) fprintf(stderr, \
- "ZT_INFO [%ld] : %14s:%4d:" fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, ##args)
+ "ZT_INFO [%ld] : %16s:%4d:" fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, ##args)
#endif
#else
#define DEBUG_INFO(fmt, args...)
@@ -450,9 +443,9 @@ void *_start_service(void *thread_id);
#if ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER
#if defined(__ANDROID__)
#define DEBUG_TRANS(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_TRANS : %14s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_TRANS : %16s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else
- #define DEBUG_TRANS(fmt, args...) fprintf(stderr, ZT_GRN "ZT_TRANS[%ld] : %14s:%4d:%25s: " fmt \
+ #define DEBUG_TRANS(fmt, args...) fprintf(stderr, ZT_GRN "ZT_TRANS[%ld] : %16s:%4d:%25s: " fmt \
"\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#endif
#else
@@ -462,10 +455,10 @@ void *_start_service(void *thread_id);
#if ZT_DEBUG_LEVEL >= ZT_MSG_EXTRA
#if defined(__ANDROID__)
#define DEBUG_EXTRA(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_EXTRA : %14s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_EXTRA : %16s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else
#define DEBUG_EXTRA(fmt, args...) fprintf(stderr, \
- "ZT_EXTRA[%ld] : %14s:%4d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
+ "ZT_EXTRA[%ld] : %16s:%4d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#endif
#else
#define DEBUG_EXTRA(fmt, args...)
@@ -474,9 +467,9 @@ void *_start_service(void *thread_id);
#if ZT_DEBUG_LEVEL >= ZT_MSG_FLOW
#if defined(__ANDROID__)
#define DEBUG_FLOW(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
- "ZT_FLOW : %14s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+ "ZT_FLOW : %16s:%4d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else
- #define DEBUG_FLOW(fmt, args...) fprintf(stderr, "ZT_FLOW [%ld] : %14s:%4d:%25s: " fmt "\n", \
+ #define DEBUG_FLOW(fmt, args...) fprintf(stderr, "ZT_FLOW [%ld] : %16s:%4d:%25s: " fmt "\n", \
ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#endif
#else
diff --git a/make-linux.mk b/make-linux.mk
index 0b57e52..0b84006 100644
--- a/make-linux.mk
+++ b/make-linux.mk
@@ -8,8 +8,189 @@ ifeq ($(origin CXX),default)
CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi)
endif
+##############################################################################
+## VARIABLES ##
+##############################################################################
+include objects.mk
+
+# Target output filenames
+STATIC_LIB_NAME = libzt.a
+INTERCEPT_NAME = libztintercept.so
+SDK_SERVICE_NAME = zerotier-sdk-service
+ONE_SERVICE_NAME = zerotier-one
+PICO_LIB_NAME = libpicotcp.a
+#
+STATIC_LIB = $(BUILD)/$(STATIC_LIB_NAME)
+SDK_INTERCEPT = $(BUILD)/$(INTERCEPT_NAME)
+SDK_SERVICE = $(BUILD)/$(SDK_SERVICE_NAME)
+ONE_SERVICE = $(BUILD)/$(ONE_SERVICE_NAME)
+PICO_LIB = ext/picotcp/build/lib/$(PICO_LIB_NAME)
+
+TEST_BUILD_DIR = build/test
+UNIT_TEST_SRC_DIR = test/unit
+DUMB_TEST_SRC_DIR = test/dumb
+
+
+##############################################################################
+## General Configuration ##
+##############################################################################
+
+# Debug output for ZeroTier service
+ifeq ($(ZT_DEBUG),1)
+ DEFS+=-DZT_TRACE
+ #CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) $(DEFS)
+ CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
+ STRIP=echo
+ # The following line enables optimization for the crypto code, since
+ # C25519 in particular is almost UNUSABLE in heavy testing without it.
+#ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
+else
+ CFLAGS?=-Ofast -fstack-protector
+ CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) $(DEFS)
+ #CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIC -pthread -mmacosx-version-min=10.7 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS)
+ STRIP=strip
+endif
+
+CXXFLAGS=$(CFLAGS) -Wno-format -fno-rtti -std=c++11 -DZT_SDK
+
+INCLUDES+= -Iext \
+ -I$(ZTO)/osdep \
+ -I$(ZTO)/node \
+ -I$(ZTO)/service \
+ -I$(ZTO)/include \
+ -I../$(ZTO)/osdep \
+ -I../$(ZTO)/node \
+ -I../$(ZTO)/service \
+ -I. \
+ -Isrc \
+ -Iinclude \
+ -Iext/picotcp/include \
+ -Iext/picotcp/build/include
+
+##############################################################################
+## User Build Flags ##
+##############################################################################
+
+# Debug option, prints filenames, lines, functions, arguments, etc
+# Also enables debug symbols for debugging with tools like gdb, etc
+ifeq ($(SDK_DEBUG),1)
+ SDK_FLAGS+=-DSDK_PICOTCP
+ CXXFLAGS+=-g
+ INCLUDES+= -I$(PICOTCP_DIR)/include \
+ -I$(PICOTCP_DIR)/build/include \
+ -Isrc/stack_drivers/picotcp
+endif
+
+##############################################################################
+## Stack Configuration ##
+##############################################################################
+
+# Stack config flags
+ifeq ($(SDK_PICOTCP),1)
+ SDK_FLAGS+=-DSDK_PICOTCP
+ INCLUDES+= -I$(PICOTCP_DIR)/include \
+ -I$(PICOTCP_DIR)/build/include \
+ -Isrc/stack_drivers/picotcp
+endif
+ifeq ($(SDK_IPV4),1)
+ SDK_FLAGS+=-DSDK_IPV4
+endif
+ifeq ($(SDK_IPV6),1)
+ SDK_FLAGS+=-DSDK_IPV6
+endif
+
+
+##############################################################################
+## Files ##
+##############################################################################
+
+STACK_DRIVER_FILES:=src/picoTCP.cpp
+TAP_FILES:=src/SocketTap.cpp \
+ src/ZeroTierSDK.cpp
+
+SDK_OBJS+= SocketTap.o \
+ Socket.o \
+ picoTCP.o \
+ ZeroTierSDK.o
+
+PICO_OBJS+= ext/picotcp/build/lib/pico_device.o \
+ ext/picotcp/build/lib/pico_frame.o \
+ ext/picotcp/build/lib/pico_md5.o \
+ ext/picotcp/build/lib/pico_protocol.o \
+ ext/picotcp/build/lib/pico_socket_multicast.o \
+ ext/picotcp/build/lib/pico_socket.o \
+ ext/picotcp/build/lib/pico_stack.o \
+ ext/picotcp/build/lib/pico_tree.o
all:
-static_lib: $(OBJS)
+tests: dumb_tests unit_tests
+
+##############################################################################
+## User-Space Stack ##
+##############################################################################
+
+picotcp:
+ cd ext/picotcp; make lib ARCH=shared IPV4=1 IPV6=1
+
+##############################################################################
+## Static Libraries ##
+##############################################################################
+
+static_lib: picotcp $(ZTO_OBJS)
+ $(CXX) $(CXXFLAGS) $(SDK_FLAGS) $(TAP_FILES) $(STACK_DRIVER_FILES) -c -DSDK_STATIC
+ libtool -static -o $(STATIC_LIB) $(ZTO_OBJS) $(SDK_OBJS) $(PICO_LIB)
+
+jni_static_lib: picotcp $(ZTO_OBJS)
+
+##############################################################################
+## Unit Tests ##
+##############################################################################
+
+UNIT_TEST_SRC_FILES:=$(wildcard $(UNIT_TEST_SRC_DIR)/*.cpp)
+UNIT_TEST_OBJ_FILES:=$(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_FILES:.cpp=.out)))
+UNIT_TEST_INCLUDES:=-Iinclude
+UNIT_TEST_LIBS:=-Lbuild -lzt
+
+$(TEST_BUILD_DIR)/%.out: $(UNIT_TEST_SRC_DIR)/%.cpp
+ @mkdir -p $(TEST_BUILD_DIR)
+ @-$(CXX) $(UNIT_TEST_INCLUDES) -o $@ $< $(UNIT_TEST_LIBS)
+ @-./check.sh $@
+
+unit_tests: $(UNIT_TEST_OBJ_FILES)
+
+##############################################################################
+## Non-ZT Client/Server Tests ##
+##############################################################################
+
+DUMB_TEST_SRC_FILES=$(wildcard $(DUMB_TEST_SRC_DIR)/*.c)
+DUMB_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(DUMB_TEST_SRC_FILES:.c=.out)))
+
+$(TEST_BUILD_DIR)/%.out: $(DUMB_TEST_SRC_DIR)/%.c
+ @mkdir -p $(TEST_BUILD_DIR)
+ @-$(CC) -o $@ $<
+ @-./check.sh $@
+
+dumb_tests: $(DUMB_TEST_OBJ_FILES)
+
+##############################################################################
+## Misc ##
+##############################################################################
+
+clean:
+ -rm -rf $(BUILD)/*
+ -rm -rf zerotier-cli zerotier-idtool
+ -find . -type f \( -name $(ONE_SERVICE_NAME) -o -name $(SDK_SERVICE_NAME) \) -delete
+ -find . -type f \( -name '*.o' -o -name '*.so' -o -name '*.o.d' -o -name '*.out' -o -name '*.log' -o -name '*.dSYM' \) -delete
+
+# Check for the presence of built frameworks/bundles/libaries
+check:
+ -./check.sh $(PICO_LIB)
+ -./check.sh $(SDK_INTERCEPT)
+ -./check.sh $(ONE_SERVICE)
+ -./check.sh $(SDK_SERVICE)
+ -./check.sh $(STATIC_LIB)
+ -./check.sh $(STATIC_LIB)
+
+
\ No newline at end of file
diff --git a/make-mac.mk b/make-mac.mk
index 5fed7a9..c3f48e0 100644
--- a/make-mac.mk
+++ b/make-mac.mk
@@ -9,7 +9,7 @@ ifeq ($(origin CXX),default)
endif
##############################################################################
-## General Configuration ##
+## VARIABLES ##
##############################################################################
include objects.mk
@@ -27,6 +27,15 @@ SDK_SERVICE = $(BUILD)/$(SDK_SERVICE_NAME)
ONE_SERVICE = $(BUILD)/$(ONE_SERVICE_NAME)
PICO_LIB = ext/picotcp/build/lib/$(PICO_LIB_NAME)
+TEST_BUILD_DIR = build/test
+UNIT_TEST_SRC_DIR = test/unit
+DUMB_TEST_SRC_DIR = test/dumb
+
+
+##############################################################################
+## General Configuration ##
+##############################################################################
+
# Debug output for ZeroTier service
ifeq ($(ZT_DEBUG),1)
DEFS+=-DZT_TRACE
@@ -98,28 +107,25 @@ endif
STACK_DRIVER_FILES:=src/picoTCP.cpp
TAP_FILES:=src/SocketTap.cpp \
- src/SDKService.cpp
+ src/ZeroTierSDK.cpp \
-RPC_FILES:=src/RPC.c
-SOCKET_API_FILES:=src/Socket.c
-
-SDK_OBJS+= RPC.o \
- SocketTap.o \
- Socket.o \
- picoTCP.o \
- SDKService.o
+SDK_OBJS+= SocketTap.o \
+ picoTCP.o \
+ ZeroTierSDK.o
PICO_OBJS+= ext/picotcp/build/lib/pico_device.o \
-ext/picotcp/build/lib/pico_frame.o \
-ext/picotcp/build/lib/pico_md5.o \
-ext/picotcp/build/lib/pico_protocol.o \
-ext/picotcp/build/lib/pico_socket_multicast.o \
-ext/picotcp/build/lib/pico_socket.o \
-ext/picotcp/build/lib/pico_stack.o \
-ext/picotcp/build/lib/pico_tree.o
+ ext/picotcp/build/lib/pico_frame.o \
+ ext/picotcp/build/lib/pico_md5.o \
+ ext/picotcp/build/lib/pico_protocol.o \
+ ext/picotcp/build/lib/pico_socket_multicast.o \
+ ext/picotcp/build/lib/pico_socket.o \
+ ext/picotcp/build/lib/pico_stack.o \
+ ext/picotcp/build/lib/pico_tree.o
all:
+tests: dumb_tests unit_tests
+
##############################################################################
## User-Space Stack ##
##############################################################################
@@ -132,7 +138,7 @@ picotcp:
##############################################################################
static_lib: picotcp $(ZTO_OBJS)
- $(CXX) $(CXXFLAGS) $(SDK_FLAGS) $(RPC_FILES) $(TAP_FILES) $(STACK_DRIVER_FILES) $(SOCKET_API_FILES) -c -DSDK_STATIC
+ $(CXX) $(CXXFLAGS) $(SDK_FLAGS) $(TAP_FILES) $(STACK_DRIVER_FILES) -c -DSDK_STATIC
libtool -static -o $(STATIC_LIB) $(ZTO_OBJS) $(SDK_OBJS) $(PICO_LIB)
jni_static_lib: picotcp $(ZTO_OBJS)
@@ -141,8 +147,31 @@ jni_static_lib: picotcp $(ZTO_OBJS)
## Unit Tests ##
##############################################################################
-static_lib_test:
- $(CXX) -Iinclude tests/socket/simple.cpp -o build/simple.out -Lbuild -lzt
+UNIT_TEST_SRC_FILES:=$(wildcard $(UNIT_TEST_SRC_DIR)/*.cpp)
+UNIT_TEST_OBJ_FILES:=$(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_FILES:.cpp=.out)))
+UNIT_TEST_INCLUDES:=-Iinclude
+UNIT_TEST_LIBS:=-Lbuild -lzt
+
+$(TEST_BUILD_DIR)/%.out: $(UNIT_TEST_SRC_DIR)/%.cpp
+ @mkdir -p $(TEST_BUILD_DIR)
+ @-$(CXX) $(UNIT_TEST_INCLUDES) -o $@ $< $(UNIT_TEST_LIBS)
+ @-./check.sh $@
+
+unit_tests: $(UNIT_TEST_OBJ_FILES)
+
+##############################################################################
+## Non-ZT Client/Server Tests ##
+##############################################################################
+
+DUMB_TEST_SRC_FILES=$(wildcard $(DUMB_TEST_SRC_DIR)/*.c)
+DUMB_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(DUMB_TEST_SRC_FILES:.c=.out)))
+
+$(TEST_BUILD_DIR)/%.out: $(DUMB_TEST_SRC_DIR)/%.c
+ @mkdir -p $(TEST_BUILD_DIR)
+ @-$(CC) -o $@ $<
+ @-./check.sh $@
+
+dumb_tests: $(DUMB_TEST_OBJ_FILES)
##############################################################################
## Misc ##
@@ -161,4 +190,6 @@ check:
-./check.sh $(ONE_SERVICE)
-./check.sh $(SDK_SERVICE)
-./check.sh $(STATIC_LIB)
+ -./check.sh $(STATIC_LIB)
+
\ No newline at end of file
diff --git a/src/Connection.hpp b/src/Connection.hpp
new file mode 100644
index 0000000..fcf1979
--- /dev/null
+++ b/src/Connection.hpp
@@ -0,0 +1,73 @@
+/*
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef ZT_CONNECTION_HPP
+#define ZT_CONNECTION_HPP
+
+#include
+
+#include "pico_socket.h"
+
+#include "Phy.hpp"
+
+#include "ZeroTierSDK.h"
+#include "SocketTap.hpp"
+
+namespace ZeroTier {
+
+ /*
+ * Connection object
+ */
+ struct Connection
+ {
+ int pid;
+ PhySocket *sock;
+ struct pico_socket *picosock;
+
+ // TODO: For getsockname, etc
+ struct sockaddr_storage *local_addr; // Address we've bound to locally
+ struct sockaddr_storage *peer_addr; // Address of connection call to remote host
+
+ // RX/TX buffers
+ int txsz, rxsz;
+ unsigned char txbuf[ZT_TCP_TX_BUF_SZ];
+ unsigned char rxbuf[ZT_TCP_RX_BUF_SZ];
+
+ int data_sock;
+ int socket_family, socket_type;
+
+ int app_fd; // provided to app for I/O
+ int sdk_fd; // provided to SDK for I/O
+
+ std::queue _AcceptedConnections;
+ SocketTap *tap; // Reference to SocketTap
+
+ Connection() {
+ ZT_PHY_SOCKFD_TYPE fdpair[2];
+ if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fdpair) < 0) {
+ if(errno < 0) {
+ DEBUG_ERROR("unable to create socketpair");
+ return;
+ }
+ }
+ sdk_fd = fdpair[0];
+ app_fd = fdpair[1];
+ }
+ };
+}
+#endif
\ No newline at end of file
diff --git a/src/RPC.c b/src/RPC.c
deleted file mode 100644
index ad101c4..0000000
--- a/src/RPC.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifdef USE_GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#if defined(__linux__)
- #include
-#endif
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "ZeroTierSDK.h"
-#include "RPC.h"
-
-// externs common between SDK_Intercept and SDK_Socket from SDK.h
-int (*realsocket)(ZT_SOCKET_SIG);
-int (*realconnect)(ZT_CONNECT_SIG);
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SERVICE_CONNECT_ATTEMPTS 30
-
-ssize_t sock_fd_write(int sock, int fd);
-ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
-
-static int rpc_count;
-
-static pthread_mutex_t lock;
-void rpc_mutex_init() {
- if(pthread_mutex_init(&lock, NULL) != 0) {
- }
-}
-void rpc_mutex_destroy() {
- pthread_mutex_destroy(&lock);
-}
-
-/*
- * Reads a new file descriptor from the service
- */
-int get_new_fd(int sock)
-{
- char buf[BUF_SZ];
- int newfd;
- ssize_t size = sock_fd_read(sock, buf, sizeof(buf), &newfd);
- if(size > 0)
- return newfd;
- return -1;
-}
-
-/*
- * Reads a return value from the service and sets errno (if applicable)
- */
-int get_retval(int rpc_sock)
-{
- if(rpc_sock >= 0) {
- int retval;
- int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
- char retbuf[BUF_SZ];
- memset(&retbuf, 0, sz);
- long n_read = read(rpc_sock, &retbuf, sz);
- if(n_read > 0) {
- memcpy(&retval, &retbuf[1], sizeof(retval));
- memcpy(&errno, &retbuf[1+sizeof(retval)], sizeof(errno));
- return retval;
- }
- }
- return -1;
-}
-
-int load_symbols_rpc()
-{
-#if defined(__IOS__) || defined(__UNITY_3D__)
- realsocket = dlsym(RTLD_NEXT, "socket");
- realconnect = dlsym(RTLD_NOW, "connect");
- if(!realconnect || !realsocket)
- return -1;
-#endif
- return 1;
-}
-
-int rpc_join(char * sockname)
-{
- if(sockname == NULL) {
- DEBUG_ERROR("warning, rpc netpath is NULL. Exiting.");
- exit(0);
- }
- if(!load_symbols_rpc())
- return -1;
- struct sockaddr_un addr;
- int conn_err = -1, attempts = 0;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)-1);
- int sock;
-
-#if defined(SDK_INTERCEPT)
- if((sock = realsocket(AF_UNIX, SOCK_STREAM, 0)) < 0){
-#else
- if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
-#endif
- DEBUG_ERROR("error creating RPC socket");
- return -1;
- }
- while((conn_err != 0) /* && (attempts < SERVICE_CONNECT_ATTEMPTS) */){
- #if defined(SDK_INTERCEPT)
- if((conn_err = realconnect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) {
- #else
- if((conn_err = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) {
- #endif
- DEBUG_ERROR("error connecting to RPC socket (%s). Re-attempting...", sockname);
- usleep(100000);
- }
- else
- return sock;
- attempts++;
- }
- return -1;
-}
-
-/*
- * Send a command to the service
- */
-int rpc_send_command(char *path, int cmd, int forfd, void *data, int len)
-{
- pthread_mutex_lock(&lock);
- char c, padding[] = {PADDING};
- char cmdbuf[BUF_SZ], CANARY[CANARY_SZ+PADDING_SZ], metabuf[BUF_SZ];
-
- memcpy(CANARY+CANARY_SZ, padding, sizeof(padding));
- uint64_t canary_num;
- // ephemeral RPC socket used only for this command
- int rpc_sock = rpc_join(path);
-
- // Generate token
- int fdrand = open("/dev/urandom", O_RDONLY);
- if(read(fdrand, &CANARY, CANARY_SZ) < 0) {
- DEBUG_ERROR("unable to read from /dev/urandom for RPC canary data");
- return -1;
- }
-
- close(fdrand);
- memcpy(&canary_num, CANARY, CANARY_SZ);
- cmdbuf[CMD_ID_IDX] = cmd;
- memcpy(&cmdbuf[CANARY_IDX], &canary_num, CANARY_SZ);
- memcpy(&cmdbuf[STRUCT_IDX], data, len);
-
- rpc_count++;
- memset(metabuf, 0, BUF_SZ);
-#if defined(__linux__)
- #if !defined(__ANDROID__)
- pid_t pid = 5; //syscall(SYS_getpid);
- pid_t tid = 4;//syscall(SYS_gettid);
- #else
- // Dummy values
- pid_t pid = 5;
- pid_t tid = gettid();
- #endif
-#endif
- char timestring[20];
- time_t timestamp;
- timestamp = time(NULL);
- strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(×tamp));
-#if defined(__linux__)
- memcpy(&metabuf[IDX_PID], &pid, sizeof(pid_t) ); /* pid */
- memcpy(&metabuf[IDX_TID], &tid, sizeof(pid_t) ); /* tid */
-#endif
- memcpy(&metabuf[IDX_TIME], ×tring, 20 ); /* timestamp */
-
- /* Combine command flag+payload with RPC metadata */
- memcpy(metabuf, RPC_PHRASE, RPC_PHRASE_SZ); // Write signal phrase
- memcpy(&metabuf[IDX_PAYLOAD], cmdbuf, len + 1 + CANARY_SZ);
-
- // Write RPC
- long n_write = write(rpc_sock, &metabuf, BUF_SZ);
- if(n_write < 0) {
- DEBUG_ERROR("error writing command to service (CMD = %d)", cmdbuf[CMD_ID_IDX]);
- errno = 0;
- }
- // Write token to corresponding data stream
- if(read(rpc_sock, &c, 1) < 0) {
- DEBUG_ERROR("unable to read RPC ACK byte from service.");
- close(rpc_sock);
- return -1;
- }
- if(c == 'z' && n_write > 0 && forfd > -1){
- if(send(forfd, &CANARY, CANARY_SZ+PADDING_SZ, 0) < 0) {
- perror("send: \n");
- DEBUG_ERROR("unable to write canary to stream (fd=%d)", forfd);
- close(rpc_sock);
- return -1;
- }
- }
- // Process response from service
- int ret = ERR_OK;
- if(n_write > 0) {
- if(cmdbuf[CMD_ID_IDX]==RPC_SOCKET) {
- pthread_mutex_unlock(&lock);
- return rpc_sock; // Used as new socket
- }
- if(cmdbuf[CMD_ID_IDX]==RPC_CONNECT
- || cmdbuf[CMD_ID_IDX]==RPC_BIND
- || cmdbuf[CMD_ID_IDX]==RPC_LISTEN) {
- ret = get_retval(rpc_sock);
- }
- if(cmdbuf[CMD_ID_IDX]==RPC_GETSOCKNAME || cmdbuf[CMD_ID_IDX]==RPC_GETPEERNAME) {
- pthread_mutex_unlock(&lock);
- return rpc_sock; // Don't close rpc here, we'll use it to read getsockopt_st
- }
- }
- else
- ret = -1;
- close(rpc_sock); // We're done with this RPC socket, close it (if type-R)
- pthread_mutex_unlock(&lock);
- return ret;
-}
-
-/*
- * Send file descriptor
- */
-ssize_t sock_fd_write(int sock, int fd)
-{
- ssize_t size;
- struct msghdr msg;
- struct iovec iov;
- char buf = '\0';
- int buflen = 1;
- union {
- struct cmsghdr cmsghdr;
- char control[CMSG_SPACE(sizeof (int))];
- } cmsgu;
- struct cmsghdr *cmsg;
- iov.iov_base = &buf;
- iov.iov_len = buflen;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- if (fd != -1) {
- msg.msg_control = cmsgu.control;
- msg.msg_controllen = sizeof(cmsgu.control);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof (int));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- *((int *) CMSG_DATA(cmsg)) = fd;
- } else {
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- }
- size = sendmsg(sock, &msg, 0);
- if (size < 0)
- perror ("sendmsg");
- return size;
-}
-/*
- * Read a file descriptor
- */
-ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
-{
- ssize_t size;
- if (fd) {
- struct msghdr msg;
- struct iovec iov;
- union {
- struct cmsghdr cmsghdr;
- char control[CMSG_SPACE(sizeof (int))];
- } cmsgu;
-
- struct cmsghdr *cmsg;
- iov.iov_base = buf;
- iov.iov_len = bufsize;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
-
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsgu.control;
- msg.msg_controllen = sizeof(cmsgu.control);
- size = recvmsg (sock, &msg, 0);
-
- if (size < 0)
- return -1;
- cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- if (cmsg->cmsg_level != SOL_SOCKET) {
- DEBUG_ERROR("invalid cmsg_level %d",cmsg->cmsg_level);
- return -1;
- }
- if (cmsg->cmsg_type != SCM_RIGHTS) {
- DEBUG_ERROR("invalid cmsg_type %d",cmsg->cmsg_type);
- return -1;
- }
- *fd = *((int *) CMSG_DATA(cmsg));
- } else {
-*fd = -1;}
- } else {
- size = read (sock, buf, bufsize);
- if (size < 0) {
- DEBUG_ERROR("sock_fd_read(): read: Error");
- return -1;
- }
- }
- return size;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/RPC.h b/src/RPC.h
deleted file mode 100644
index 1385577..0000000
--- a/src/RPC.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef __RPCLIB_H_
-#define __RPCLIB_H_
-
-#include
-
-#define CANARY_SZ sizeof(uint64_t)
-#define PADDING_SZ 12
-#define PADDING 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
-
-#define RPC_PHRASE "zerotier\0"
-#define RPC_PHRASE_SZ 9
-#define RPC_TIMESTAMP_SZ 20
-// 1st RPC section (metdata)
-#define IDX_SIGNAL_PHRASE 0
-#define IDX_PID IDX_SIGNAL_PHRASE + RPC_PHRASE_SZ
-#define IDX_TID sizeof(pid_t) + IDX_PID
-#define IDX_TIME IDX_TID + sizeof(int)
-#define IDX_PAYLOAD IDX_TIME + RPC_TIMESTAMP_SZ
-// 2nd RPC section (payload and canary)
-#define CMD_ID_IDX 0
-#define CANARY_IDX 1
-#define STRUCT_IDX CANARY_IDX+CANARY_SZ
-
-#define BUF_SZ 512
-
-#define ERR_OK 0
-
-/* RPC codes */
-#define RPC_UNDEFINED 0
-#define RPC_CONNECT 1
-#define RPC_CONNECT_SOCKARG 2
-#define RPC_CLOSE 3
-#define RPC_READ 4
-#define RPC_WRITE 5
-#define RPC_BIND 6
-#define RPC_ACCEPT 7
-#define RPC_LISTEN 8
-#define RPC_SOCKET 9
-#define RPC_SHUTDOWN 10
-#define RPC_GETSOCKNAME 11
-#define RPC_GETPEERNAME 12
-#define RPC_RETVAL 13
-#define RPC_IS_CONNECTED 14
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int get_retval(int);
-int rpc_join( char * sockname);
-int rpc_send_command(char *path, int cmd, int forfd, void *data, int len);
-
-int get_new_fd(int sock);
-ssize_t sock_fd_write(int sock, int fd);
-ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
-
-void rpc_mutex_destroy();
-void rpc_mutex_init();
-
-
-/* Structures used for sending commands via RPC mechanism */
-
-struct bind_st {
- int fd;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int tid;
-};
-
-struct connect_st {
- int fd;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int tid;
-};
-
-struct close_st {
- int fd;
-};
-
-struct listen_st {
- int fd;
- int backlog;
- int tid;
-};
-
-struct socket_st {
- int socket_family;
- int socket_type;
- int protocol;
- int tid;
-};
-
-struct accept_st {
- int fd;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int tid;
-};
-
-struct shutdown_st {
- int socket;
- int how;
-};
-
-struct getsockname_st {
- int fd;
- struct sockaddr_storage addr;
- socklen_t addrlen;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
\ No newline at end of file
diff --git a/src/Socket.c b/src/Socket.c
deleted file mode 100644
index a18a4d6..0000000
--- a/src/Socket.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if defined(__linux__)
- #define SOCK_MAX (SOCK_PACKET + 1)
-#endif
-
-#include "ZeroTierSDK.h"
-#include "RPC.h"
-
-char *api_netpath;
-
-/****************************************************************************/
-/* zts_init_rpc() */
-/****************************************************************************/
-
-int service_initialized = 0;
-
-// Assembles (and/or) sets the RPC path for communication with the ZeroTier service
-void zts_init_rpc(const char *path, const char *nwid)
-{
- // If no path, construct one or get it fron system env vars
- if(!api_netpath) {
- rpc_mutex_init();
- // Provided by user
- #if defined(SDK_BUNDLED)
- // Get the path/nwid from the user application
- // netpath = [path + "/nc_" + nwid]
- char *fullpath = (char *)malloc(strlen(path)+strlen(nwid)+1+4);
- if(fullpath) {
- zts_join_network_soft(path, nwid);
- strcpy(fullpath, path);
- strcat(fullpath, "/nc_");
- strcat(fullpath, nwid);
- api_netpath = fullpath;
- }
- // Provided by Env
- #else
- // Get path/nwid from environment variables
- if (!api_netpath) {
- api_netpath = getenv("ZT_NC_NETWORK");
- DEBUG_INFO("$ZT_NC_NETWORK=%s", api_netpath);
- }
- #endif
- }
-
- // start the SDK service if this is bundled
- #if defined(SDK_BUNDLED)
- if(!service_initialized) {
- DEBUG_ATTN("api_netpath = %s", api_netpath);
- pthread_t service_thread;
- pthread_create(&service_thread, NULL, zts_start_core_service, (void *)(path));
- service_initialized = 1;
- DEBUG_ATTN("waiting for service to assign address to network stack");
- // wait for zt service to assign the network stack an address
- sleep(1);
- while(!zts_has_address(nwid)) { usleep(1000); }
- }
- #endif
-}
-
-void get_api_netpath() { zts_init_rpc("",""); }
-
-/****************************************************************************/
-/* socket() */
-/****************************************************************************/
-
- int zts_socket(ZT_SOCKET_SIG)
- {
- DEBUG_INFO("");
-#ifdef SDK_STATIC
- return zts_multiplex_new_socket(socket_family, socket_type, protocol);
-#endif
- }
-
-
- int zts_connect(ZT_CONNECT_SIG)
- {
- DEBUG_INFO("");
-#ifdef SDK_STATIC
- return zts_multiplex_new_connect(fd, addr, addrlen);
-#endif
- }
-
-
-
-#ifdef __cplusplus
- }
-#endif
\ No newline at end of file
diff --git a/src/SocketTap.cpp b/src/SocketTap.cpp
index 3c363f9..c622adb 100644
--- a/src/SocketTap.cpp
+++ b/src/SocketTap.cpp
@@ -1,6 +1,6 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,15 +14,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
*/
#include
@@ -37,7 +28,6 @@
#include "SocketTap.hpp"
#include "ZeroTierSDK.h"
-#include "RPC.h"
#include "picoTCP.hpp"
#include "Utils.hpp"
@@ -57,32 +47,11 @@ void SocketTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
void SocketTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
void SocketTap::phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked) {}
-int SocketTap::sendReturnValue(int fd, int retval, int _errno)
-{
- //DEBUG_INFO("fd=%d, retval=%d, errno=%d", fd, retval, _errno);
- int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
- char retmsg[sz];
- memset(&retmsg, 0, sizeof(retmsg));
- retmsg[0]=RPC_RETVAL;
- memcpy(&retmsg[1], &retval, sizeof(retval));
- memcpy(&retmsg[1]+sizeof(retval), &_errno, sizeof(_errno));
- return write(fd, &retmsg, sz);
-}
-// Unpacks the buffer from an RPC command
-void SocketTap::unloadRPC(void *data, pid_t &pid, pid_t &tid,
- char (timestamp[RPC_TIMESTAMP_SZ]), char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload)
- {
- unsigned char *buf = (unsigned char*)data;
- memcpy(&pid, &buf[IDX_PID], sizeof(pid_t));
- memcpy(&tid, &buf[IDX_TID], sizeof(pid_t));
- memcpy(timestamp, &buf[IDX_TIME], RPC_TIMESTAMP_SZ);
- memcpy(&cmd, &buf[IDX_PAYLOAD], sizeof(char));
- memcpy(CANARY, &buf[IDX_PAYLOAD+1], CANARY_SZ);
-}
-
-/*------------------------------------------------------------------------------
--------------------------------- Tap Service ----------------------------------
-------------------------------------------------------------------------------*/
+/****************************************************************************/
+/* SocketTap Service */
+/* - For each joined network a SocketTap will be created to administer I/O */
+/* calls to the stack and the ZT virtual wire */
+/****************************************************************************/
SocketTap::SocketTap(
const char *homePath,
@@ -105,7 +74,7 @@ SocketTap::SocketTap(
_enabled(true),
_run(true)
{
-
+ /*
char sockPath[4096];
Utils::snprintf(sockPath,sizeof(sockPath),"%s%s" ZT_SDK_RPC_DIR_PREFIX "/%.16llx",
homePath,ZT_PATH_SEPARATOR_S,_nwid,ZT_PATH_SEPARATOR_S,(unsigned long long)nwid);
@@ -116,21 +85,13 @@ SocketTap::SocketTap(
DEBUG_ERROR("unable to bind to: rpc = %s", sockPath);
else
DEBUG_INFO("rpc = %s", sockPath);
-
- char ver[6];
- zts_core_version(ver);
- DEBUG_INFO("zts_core_version = %s", ver);
- zts_sdk_version(ver);
- DEBUG_INFO("zts_sdk_version = %s", ver);
- char id[11];
- zts_get_device_id(id);
- DEBUG_INFO("id = %s", id);
-
+ */
_thread = Thread::start(this);
}
SocketTap::~SocketTap()
{
+ // TODO: Verify deletion of all objects
_run = false;
_phy.whack();
Thread::join(_thread);
@@ -149,6 +110,7 @@ bool SocketTap::enabled() const
bool SocketTap::addIp(const InetAddress &ip)
{
+ DEBUG_INFO();
picotap = this;
picostack->pico_init_interface(this, ip);
_ips.push_back(ip);
@@ -157,6 +119,7 @@ bool SocketTap::addIp(const InetAddress &ip)
bool SocketTap::removeIp(const InetAddress &ip)
{
+ DEBUG_INFO();
Mutex::Lock _l(_ips_m);
std::vector::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (i == _ips.end())
@@ -177,6 +140,7 @@ std::vector SocketTap::ips() const
void SocketTap::put(const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
+ DEBUG_INFO();
// RX packet
picostack->pico_rx(this, from,to,etherType,data,len);
@@ -223,6 +187,7 @@ void SocketTap::threadMain()
Connection *SocketTap::getConnection(PhySocket *sock)
{
+ DEBUG_INFO();
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i]->sock == sock)
return _Connections[i];
@@ -232,6 +197,7 @@ Connection *SocketTap::getConnection(PhySocket *sock)
Connection *SocketTap::getConnection(struct pico_socket *sock)
{
+ DEBUG_INFO();
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i]->picosock == sock)
return _Connections[i];
@@ -241,6 +207,7 @@ Connection *SocketTap::getConnection(struct pico_socket *sock)
void SocketTap::closeConnection(PhySocket *sock)
{
+ DEBUG_INFO();
Mutex::Lock _l(_close_m);
// Here we assume _tcpconns_m is already locked by caller
if(!sock) {
@@ -265,6 +232,7 @@ void SocketTap::closeConnection(PhySocket *sock)
}
void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr) {
+ DEBUG_INFO();
//Mutex::Lock _l(_tcpconns_m);
//closeConnection(sock);
// FIXME:
@@ -272,167 +240,57 @@ void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr) {
void SocketTap::handleRead(PhySocket *sock,void **uptr,bool stack_invoked)
{
+ DEBUG_INFO();
picostack->pico_handleRead(sock, uptr, stack_invoked);
}
void SocketTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool stack_invoked)
{
+ DEBUG_INFO();
handleRead(sock,uptr,stack_invoked);
}
void SocketTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
{
- //DEBUG_INFO("physock=%p, len=%d", sock, (int)len);
- uint64_t CANARY_num;
- pid_t pid, tid;
- ssize_t wlen = len;
- char tmpbuf[SDK_MTU];
- char cmd, timestamp[20], CANARY[CANARY_SZ], padding[] = {PADDING};
- void *payload;
- unsigned char *buf = (unsigned char*)data;
- std::pair sockdata;
- PhySocket *rpcSock;
- bool foundJob = false, detected_rpc = false;
- Connection *conn;
- // RPC
- char phrase[RPC_PHRASE_SZ];
- memset(phrase, 0, RPC_PHRASE_SZ);
- if(len == BUF_SZ) {
- memcpy(phrase, buf, RPC_PHRASE_SZ);
- if(strcmp(phrase, RPC_PHRASE) == 0)
- detected_rpc = true;
- }
- if(detected_rpc) {
- unloadRPC(data, pid, tid, timestamp, CANARY, cmd, payload);
- memcpy(&CANARY_num, CANARY, CANARY_SZ);
- // DEBUG_EXTRA(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd);
-
- if(cmd == RPC_SOCKET) {
- // DEBUG_INFO("RPC_SOCKET, physock=%p", sock);
- // Create new stack socket and associate it with this sock
- struct socket_st socket_rpc;
- memcpy(&socket_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct socket_st));
- Connection * new_conn;
- if((new_conn = handleSocket(sock, uptr, &socket_rpc))) {
- new_conn->pid = pid; // Merely kept to look up application path/names later, not strictly necessary
- }
- } else {
- memcpy(&tmpbuf,data,len);
- jobmap[CANARY_num] = std::pair(sock, tmpbuf);
-
- }
- write(_phy.getDescriptor(sock), "z", 1); // RPC ACK byte to maintain order
- }
- // STREAM
- else {
- int data_start = -1, data_end = -1, canary_pos = -1, padding_pos = -1;
- // Look for padding
- std::string padding_pattern(padding, padding+PADDING_SZ);
- std::string buffer(buf, buf + len);
- padding_pos = buffer.find(padding_pattern);
- canary_pos = padding_pos-CANARY_SZ;
- // Grab token, next we'll use it to look up an RPC job
- if(canary_pos > -1) {
- memcpy(&CANARY_num, buf+canary_pos, CANARY_SZ);
- if(CANARY_num != 0) {
- // Find job
- sockdata = jobmap[CANARY_num];
- if(!sockdata.first) {
- return;
- } else
- foundJob = true;
- }
- }
- conn = getConnection(sock);
- if(!conn)
- return;
-
- if(padding_pos == -1) { // [DATA]
- memcpy(&conn->txbuf[conn->txsz], buf, wlen);
- } else { // Padding found, implies a canary is present
- // [CANARY]
- if(len == CANARY_SZ+PADDING_SZ && canary_pos == 0) {
- wlen = 0; // Nothing to write
- } else {
- // [CANARY] + [DATA]
- if(len > CANARY_SZ+PADDING_SZ && canary_pos == 0) {
- wlen = len - CANARY_SZ+PADDING_SZ;
- data_start = padding_pos+PADDING_SZ;
- memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen);
- }
- // [DATA] + [CANARY]
- if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0
- && canary_pos == len - CANARY_SZ+PADDING_SZ) {
- wlen = len - CANARY_SZ+PADDING_SZ;
- data_start = 0;
- memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen);
- }
- // [DATA] + [CANARY] + [DATA]
- if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0
- && len > (canary_pos + CANARY_SZ+PADDING_SZ)) {
- wlen = len - CANARY_SZ+PADDING_SZ;
- data_start = 0;
- data_end = padding_pos-CANARY_SZ;
- memcpy((&conn->txbuf)+conn->txsz, buf+data_start, (data_end-data_start)+1);
- memcpy((&conn->txbuf)+conn->txsz, buf+(padding_pos+PADDING_SZ), len-(canary_pos+CANARY_SZ+PADDING_SZ));
- }
- }
- }
-
- // Write data from stream
- if(wlen) {
- conn->txsz += wlen;
- handleWrite(conn);
- }
- }
- // Process RPC if we have a corresponding jobmap entry
- if(foundJob) {
- rpcSock = sockdata.first;
- buf = (unsigned char*)sockdata.second;
- unloadRPC(buf, pid, tid, timestamp, CANARY, cmd, payload);
- //DEBUG_ERROR(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd);
- switch(cmd) {
- case RPC_BIND:
- //DEBUG_INFO("RPC_BIND, physock=%p", sock);
- struct bind_st bind_rpc;
- memcpy(&bind_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct bind_st));
- handleBind(sock, rpcSock, uptr, &bind_rpc);
- break;
- case RPC_LISTEN:
- //DEBUG_INFO("RPC_LISTEN, physock=%p", sock);
- struct listen_st listen_rpc;
- memcpy(&listen_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct listen_st));
- handleListen(sock, rpcSock, uptr, &listen_rpc);
- break;
- case RPC_GETSOCKNAME:
- //DEBUG_INFO("RPC_GETSOCKNAME, physock=%p", sock);
- struct getsockname_st getsockname_rpc;
- memcpy(&getsockname_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st));
- handleGetsockname(sock, rpcSock, uptr, &getsockname_rpc);
- break;
- case RPC_GETPEERNAME:
- //DEBUG_INFO("RPC_GETPEERNAME, physock=%p", sock);
- struct getsockname_st getpeername_rpc;
- memcpy(&getpeername_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st));
- handleGetpeername(sock, rpcSock, uptr, &getpeername_rpc);
- break;
- case RPC_CONNECT:
- //DEBUG_INFO("RPC_CONNECT, physock=%p", sock);
- struct connect_st connect_rpc;
- memcpy(&connect_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct connect_st));
- handleConnect(sock, rpcSock, conn, &connect_rpc);
- jobmap.erase(CANARY_num);
- return; // Keep open RPC, we'll use it once in nc_connected to send retval
- default:
- return;
- break;
- }
- Mutex::Lock _l(_tcpconns_m);
- closeConnection(sockdata.first); // close RPC after sending retval, no longer needed
- jobmap.erase(CANARY_num);
- }
+ DEBUG_INFO();
+ Connection *conn = getConnection(sock);
+ if(!conn)
+ return;
+ if(len) {
+ conn->txsz += len;
+ handleWrite(conn);
+ }
+ return;
}
+/****************************************************************************/
+/* SDK Socket API */
+/****************************************************************************/
+
+int SocketTap::Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) {
+ Mutex::Lock _l(_tcpconns_m);
+ return picostack->pico_Connect(conn, fd, addr, addrlen);
+}
+
+int SocketTap::Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) {
+ Mutex::Lock _l(_tcpconns_m);
+ return picostack->pico_Bind(conn, fd, addr, addrlen);
+}
+
+void SocketTap::Listen(Connection *conn, int fd, int backlog) {
+ Mutex::Lock _l(_tcpconns_m);
+ picostack->pico_Listen(conn, fd, backlog);
+}
+
+int SocketTap::Accept(Connection *conn) {
+ Mutex::Lock _l(_tcpconns_m);
+ return picostack->pico_Accept(conn);
+}
+
+
+
+
+
/*------------------------------------------------------------------------------
----------------------------- RPC Handler functions ----------------------------
------------------------------------------------------------------------------*/
@@ -440,6 +298,7 @@ void SocketTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t
void SocketTap::handleGetsockname(PhySocket *sock, PhySocket *rpcSock,
void **uptr, struct getsockname_st *getsockname_rpc)
{
+ DEBUG_INFO();
Mutex::Lock _l(_tcpconns_m);
Connection *conn = getConnection(sock);
if(conn->local_addr == NULL){
@@ -455,6 +314,7 @@ void SocketTap::handleGetsockname(PhySocket *sock, PhySocket *rpcSock,
void SocketTap::handleGetpeername(PhySocket *sock, PhySocket *rpcSock,
void **uptr, struct getsockname_st *getsockname_rpc)
{
+ DEBUG_INFO();
Mutex::Lock _l(_tcpconns_m);
Connection *conn = getConnection(sock);
if(conn->peer_addr == NULL){
@@ -466,42 +326,11 @@ void SocketTap::handleGetpeername(PhySocket *sock, PhySocket *rpcSock,
}
write(_phy.getDescriptor(rpcSock), conn->peer_addr, sizeof(struct sockaddr_storage));
}
-
-Connection * SocketTap::handleSocket(PhySocket *sock, void **uptr,
- struct socket_st* socket_rpc)
-{
- return picostack->pico_handleSocket(sock, uptr, socket_rpc);
-}
-
-void SocketTap::handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn,
- struct connect_st* connect_rpc)
-{
- Mutex::Lock _l(_tcpconns_m);
- picostack->pico_handleConnect(sock, rpcSock, conn, connect_rpc);
-}
-
-void SocketTap::handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr,
- struct bind_st *bind_rpc)
-{
- Mutex::Lock _l(_tcpconns_m);
- if(!_ips.size()) {
- DEBUG_ERROR("cannot bind yet. ZT address hasn't been provided");
- sendReturnValue(_phy.getDescriptor(rpcSock), -1, ENOMEM);
- return;
- }
- picostack->pico_handleBind(sock,rpcSock,uptr,bind_rpc);
-}
-
-void SocketTap::handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr,
- struct listen_st *listen_rpc)
-{
- Mutex::Lock _l(_tcpconns_m);
- picostack->pico_handleListen(sock, rpcSock, uptr, listen_rpc);
-}
// Write to the network stack (and thus out onto the network)
void SocketTap::handleWrite(Connection *conn)
{
+ DEBUG_INFO();
picostack->pico_handleWrite(conn);
}
diff --git a/src/SocketTap.hpp b/src/SocketTap.hpp
index 904867f..cd40d13 100644
--- a/src/SocketTap.hpp
+++ b/src/SocketTap.hpp
@@ -1,6 +1,6 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,24 +14,16 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
*/
-#ifndef ZT_SocketTap_HPP
-#define ZT_SocketTap_HPP
+#ifndef ZT_SOCKETTAP_HPP
+#define ZT_SOCKETTAP_HPP
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -44,8 +36,8 @@
#include "Phy.hpp"
#include "ZeroTierSDK.h"
-#include "RPC.h"
#include "picoTCP.hpp"
+#include "Connection.hpp"
#include "pico_protocol.h"
#include "pico_stack.h"
@@ -69,31 +61,8 @@ struct pico_socket;
namespace ZeroTier {
- class SocketTap;
-
extern SocketTap *picotap;
- /*
- * Connection object
- */
- struct Connection
- {
- bool listening, probation, disabled;
- int pid, txsz, rxsz;
- PhySocket *rpcSock, *sock;
- struct tcp_pcb *TCP_pcb;
- struct udp_pcb *UDP_pcb;
- struct sockaddr_storage *local_addr; // Address we've bound to locally
- struct sockaddr_storage *peer_addr; // Address of connection call to remote host
- unsigned short port;
- unsigned char txbuf[DEFAULT_TCP_TX_BUF_SZ];
- unsigned char rxbuf[DEFAULT_TCP_RX_BUF_SZ];
- struct pico_socket *picosock;
-
- int data_sock;
- int socket_family, socket_type;
- };
-
/*
* A helper for passing a reference to _phy to stackrpc callbacks as a "state"
*/
@@ -159,18 +128,7 @@ namespace ZeroTier {
*
*/
void scanMulticastGroups(std::vector &added,std::vector &removed);
-
- /*
- *
- */
- int sendReturnValue(int fd, int retval, int _errno);
-
- /*
- *
- */
- void unloadRPC(void *data, pid_t &pid, pid_t &tid, char (timestamp[RPC_TIMESTAMP_SZ]),
- char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload);
-
+
/*
*
*/
@@ -199,12 +157,20 @@ namespace ZeroTier {
int pico_frame_rxbuf_tot;
Mutex _pico_frame_rxbuf_m;
- void handleBind(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct bind_st *bind_rpc);
- void handleListen(PhySocket *sock, PhySocket *rpcsock, void **uptr,
- struct listen_st *listen_rpc);
- Connection * handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
- void handleConnect(PhySocket *sock, PhySocket *rpcsock, Connection *conn,
- struct connect_st* connect_rpc);
+
+
+
+ /****************************************************************************/
+ /* In these, we will call the stack's corresponding functions, this is *
+ * where one would put logic to select between different stacks */
+ /****************************************************************************/
+
+ int Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
+ int Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
+ void Listen(Connection *conn, int fd, int backlog);
+ int Accept(Connection *conn);
+
+
/*
* Return the address that the socket is bound to
@@ -269,15 +235,11 @@ namespace ZeroTier {
std::vector _Connections;
- std::map > jobmap;
- pid_t rpcCounter;
-
Thread _thread;
std::string _dev; // path to Unix domain socket
std::vector _multicastGroups;
Mutex _multicastGroups_m;
-
Mutex _ips_m, _tcpconns_m, _rx_buf_m, _close_m;
};
} // namespace ZeroTier
diff --git a/src/SDKService.cpp b/src/ZeroTierSDK.cpp
similarity index 66%
rename from src/SDKService.cpp
rename to src/ZeroTierSDK.cpp
index c779784..6625f0d 100644
--- a/src/SDKService.cpp
+++ b/src/ZeroTierSDK.cpp
@@ -1,6 +1,6 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,15 +14,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
*/
#include
@@ -53,10 +44,16 @@ extern "C" {
static ZeroTier::OneService *zt1Service;
-std::string localHomeDir; // Local shortened path
-std::string homeDir; // The resultant platform-specific dir we *must* use internally
-std::string netDir; // Where network .conf files are to be written
+namespace ZeroTier {
+ std::string homeDir; // The resultant platform-specific dir we *must* use internally
+ std::string netDir; // Where network .conf files are to be written
+ picoTCP *picostack = NULL;
+ std::map UnassignedConnections;
+ std::map*> AssignedFileDescriptors;
+ Mutex _multiplexer_lock;
+ Mutex _accepted_connection_lock;
+}
/****************************************************************************/
/* SDK Socket API - Language Bindings are written in terms of these */
@@ -74,7 +71,7 @@ void zts_start(const char *path)
DEBUG_INFO("path=%s", path);
if(path)
- homeDir = path;
+ ZeroTier::homeDir = path;
pthread_t service_thread;
pthread_create(&service_thread, NULL, _start_service, (void *)(path));
}
@@ -89,13 +86,11 @@ void zts_stop() {
void zts_join_network(const char * nwid) {
if(zt1Service) {
std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf";
- if(!ZeroTier::OSUtils::mkdir(netDir))
- DEBUG_ERROR("unable to create: %s", netDir.c_str());
+ if(!ZeroTier::OSUtils::mkdir(ZeroTier::netDir))
+ DEBUG_ERROR("unable to create: %s", ZeroTier::netDir.c_str());
if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), ""))
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
zt1Service->join(nwid);
- // Provide the API with the RPC information
- // zts_init_rpc(homeDir.c_str(), nwid);
}
}
@@ -123,8 +118,10 @@ void zts_leave_network_soft(const char * filepath, const char * nwid) {
}
void zts_get_homepath(char *homePath, int len) {
- if(homeDir.length())
- memcpy(homePath, homeDir.c_str(), len < homeDir.length() ? len : homeDir.length());
+ if(ZeroTier::homeDir.length()) {
+ memset(homePath, 0, len);
+ memcpy(homePath, ZeroTier::homeDir.c_str(), len < ZeroTier::homeDir.length() ? len : ZeroTier::homeDir.length());
+ }
}
void zts_core_version(char *ver) {
@@ -147,7 +144,7 @@ int zts_get_device_id(char *devID) {
else // Service isn't online, try to read ID from file
{
std::string fname("identity.public");
- std::string fpath(homeDir);
+ std::string fpath(ZeroTier::homeDir);
if(ZeroTier::OSUtils::fileExists((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),false)) {
std::string oldid;
@@ -272,111 +269,98 @@ void zts_disable_http_control_plane()
}
/****************************************************************************/
-/* SocketTap Multiplexer Functionality --- DONT CALL THESE DIRECTLY */
+/* SocketTap Multiplexer Functionality */
/* - This section of the API is used to implement the general socket */
/* controls. Basically this is designed to handle socket provisioning */
/* requests when no SocketTap is yet initialized, and as a way to */
/* determine which SocketTap is to be used for a particular connect() or */
-/* bind() call */
+/* bind() call. This enables multi-network support */
/****************************************************************************/
-namespace ZeroTier
-{
- picoTCP *picostack = NULL;
- std::map UnassignedConnections;
-}
-
-ZeroTier::Mutex _multiplexer_lock;
-
-int zts_multiplex_new_socket(ZT_SOCKET_SIG)
-{
+int zts_socket(ZT_SOCKET_SIG) {
DEBUG_INFO();
- _multiplexer_lock.lock();
+ ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = new ZeroTier::Connection();
- int err;
+ int err, protocol_version;
// set up pico_socket
struct pico_socket * psock;
- int pico_protocol, protocol_version;
#if defined(SDK_IPV4)
protocol_version = PICO_PROTO_IPV4;
#elif defined(SDK_IPV6)
protocol_version = PICO_PROTO_IPV6;
#endif
if(socket_type == SOCK_DGRAM) {
- pico_protocol = PICO_PROTO_UDP;
- psock = pico_socket_open(protocol_version, pico_protocol, &ZeroTier::picoTCP::pico_cb_socket_activity);
+ psock = pico_socket_open(
+ protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
if(socket_type == SOCK_STREAM) {
- pico_protocol = PICO_PROTO_TCP;
- psock = pico_socket_open(protocol_version, pico_protocol, &ZeroTier::picoTCP::pico_cb_socket_activity);
+ psock = pico_socket_open(
+ protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
- // set up Unix Domain socket (used for data later on)
- if(psock) {
- int unix_data_sock;
- if((unix_data_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- DEBUG_ERROR("unable to create unix domain socket for data");
- // errno = ?
- err = -1;
- }
- else {
- conn->socket_family = socket_family;
- conn->socket_type = socket_type;
- conn->data_sock = unix_data_sock;
- conn->picosock = psock;
- memset(conn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ);
- ZeroTier::UnassignedConnections[unix_data_sock] = conn;
- err = unix_data_sock;
- }
+ // set up Unix Domain socketpair (used for data later on)
+ if(psock) {
+ conn->socket_family = socket_family;
+ conn->socket_type = socket_type;
+ conn->picosock = psock;
+ memset(conn->rxbuf, 0, ZT_UDP_RX_BUF_SZ);
+ ZeroTier::UnassignedConnections[conn->app_fd] = conn;
+ err = conn->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create pico_socket");
err = -1;
}
- _multiplexer_lock.unlock();
+ ZeroTier::_multiplexer_lock.unlock();
return err;
}
-int zts_multiplex_new_connect(ZT_CONNECT_SIG)
-{
- DEBUG_INFO();
+int zts_connect(ZT_CONNECT_SIG) {
if(!zt1Service) {
+ DEBUG_ERROR("zt1Service = NULL");
// errno = ?
return -1;
}
-
- _multiplexer_lock.lock();
+ ZeroTier::_multiplexer_lock.lock();
int err;
ZeroTier::Connection *conn = ZeroTier::UnassignedConnections[fd];
+ ZeroTier::SocketTap *tap;
- if(conn != NULL) {
+ if(conn) {
char ipstr[INET6_ADDRSTRLEN];//, nm_str[INET6_ADDRSTRLEN];
memset(ipstr, 0, INET6_ADDRSTRLEN);
ZeroTier::InetAddress iaddr;
if(conn->socket_family == AF_INET) {
// FIXME: Fix this typecast mess
- inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET,
+ (const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
}
if(conn->socket_family == AF_INET6) {
// FIXME: Fix this typecast mess
- inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6,
+ (const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
}
-
iaddr.fromString(ipstr);
DEBUG_INFO("ipstr= %s", ipstr);
DEBUG_INFO("iaddr= %s", iaddr.toString().c_str());
- ZeroTier::SocketTap *tap = zt1Service->getTap(iaddr);
+ tap = zt1Service->getTap(iaddr);
if(!tap) {
+ // TODO: More canonical error?
DEBUG_ERROR("no route to host");
// errno = ?
err = -1;
}
else {
+ conn->sock = tap->_phy.wrapSocket(conn->sdk_fd, conn); // wrap the socketpair we created earlier
+ conn->picosock->priv = new ZeroTier::Larg(tap, conn); // pointer to tap we use in callbacks from the stack
DEBUG_INFO("found appropriate SocketTap");
- err = 0;
+ // TODO: Perhaps move this connect call outside of the lock
+ tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
+ err = tap->Connect(conn, fd, addr, addrlen); // Semantically: tap->stack->connect
+ conn->tap = tap;
}
}
else {
@@ -384,22 +368,178 @@ int zts_multiplex_new_connect(ZT_CONNECT_SIG)
// errno = ?
err = -1;
}
- _multiplexer_lock.unlock();
+ ZeroTier::AssignedFileDescriptors[fd] = new std::pair(conn, tap);
+ ZeroTier::_multiplexer_lock.unlock();
return err;
}
-int zts_multiplex_new_bind(ZT_BIND_SIG)
-{
- DEBUG_INFO();
- _multiplexer_lock.lock();
+int zts_bind(ZT_BIND_SIG) {
+ if(!zt1Service) {
+ DEBUG_ERROR("zt1Service = NULL");
+ // errno = ?
+ return -1;
+ }
+ ZeroTier::_multiplexer_lock.lock();
int err;
+ ZeroTier::Connection *conn = ZeroTier::UnassignedConnections[fd];
+ ZeroTier::SocketTap *tap;
+
+ if(conn) {
+ char ipstr[INET6_ADDRSTRLEN];//, nm_str[INET6_ADDRSTRLEN];
+ memset(ipstr, 0, INET6_ADDRSTRLEN);
+ ZeroTier::InetAddress iaddr;
- // ?
+ if(conn->socket_family == AF_INET) {
+ // FIXME: Fix this typecast mess
+ inet_ntop(AF_INET,
+ (const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
+ }
+ if(conn->socket_family == AF_INET6) {
+ // FIXME: Fix this typecast mess
+ inet_ntop(AF_INET6,
+ (const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
+ }
+ iaddr.fromString(ipstr);
- _multiplexer_lock.unlock();
+ DEBUG_INFO("ipstr= %s", ipstr);
+ DEBUG_INFO("iaddr= %s", iaddr.toString().c_str());
+
+ tap = zt1Service->getTap(iaddr);
+
+ if(!tap) {
+ // TODO: More canonical error?
+ DEBUG_ERROR("no appropriate interface to bind to");
+ // errno = ?
+ err = -1;
+ }
+ else {
+ DEBUG_INFO("found appropriate SocketTap");
+ DEBUG_INFO("conn->picosock = %p", conn->picosock);
+ conn->picosock->priv = new ZeroTier::Larg(tap, conn);
+ // TODO: Perhaps move this connect call outside of the lock
+ tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
+ err = tap->Bind(conn, fd, addr, addrlen); // Semantically: tap->stack->connect
+ conn->tap = tap;
+ }
+ }
+ else {
+ DEBUG_ERROR("unable to locate connection");
+ // errno = ?
+ err = -1;
+ }
+ ZeroTier::AssignedFileDescriptors[fd] = new std::pair(conn, tap);
+ ZeroTier::_multiplexer_lock.unlock();
return err;
}
+int zts_listen(ZT_LISTEN_SIG) {
+ if(!zt1Service) {
+ DEBUG_ERROR("zt1Service = NULL");
+ // errno = ?
+ return -1;
+ }
+ int err;
+ ZeroTier::_multiplexer_lock.lock();
+ ZeroTier::Connection *conn = ZeroTier::AssignedFileDescriptors[fd]->first;
+ ZeroTier::SocketTap *tap = ZeroTier::AssignedFileDescriptors[fd]->second;
+
+ if(!tap || !conn) {
+ DEBUG_ERROR("unable to locate tap interface for file descriptor");
+ err = -1;
+ }
+ tap->Listen(conn, fd, backlog);
+ err = 0;
+ DEBUG_INFO("put %p into LISTENING state", conn);
+ ZeroTier::_multiplexer_lock.unlock();
+ return err;
+}
+
+int zts_accept(ZT_ACCEPT_SIG) {
+ int err;
+ ZeroTier::Connection *conn = ZeroTier::AssignedFileDescriptors[fd]->first;
+ ZeroTier::SocketTap *tap = ZeroTier::AssignedFileDescriptors[fd]->second;
+ // BLOCKING: loop and keep checking until we find a newly accepted connection
+ if(true) {
+ while(true) {
+ usleep(ZT_ACCEPT_RECHECK_DELAY * 1000);
+ err = tap->Accept(conn);
+ if(err >= 0)
+ return err;
+ }
+ }
+ // NON-BLOCKING: only check for a new connection once
+ else
+ err = tap->Accept(conn);
+ return err;
+}
+
+#if defined(__linux__)
+ int zts_accept4(ZT_ACCEPT4_SIG)
+ {
+ return 0;
+ }
+#endif
+
+int zts_setsockopt(ZT_SETSOCKOPT_SIG)
+{
+ return 0;
+}
+
+int zts_getsockopt(ZT_GETSOCKOPT_SIG)
+{
+ return 0;
+}
+
+int zts_getsockname(ZT_GETSOCKNAME_SIG)
+{
+ return 0;
+}
+
+int zts_getpeername(ZT_GETPEERNAME_SIG)
+{
+ return 0;
+}
+
+int zts_close(ZT_CLOSE_SIG)
+{
+ return 0;
+}
+
+int zts_fcntl(ZT_FCNTL_SIG)
+{
+ return 0;
+}
+
+ssize_t zts_sendto(ZT_SENDTO_SIG)
+{
+ return 0;
+}
+
+ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
+{
+ return 0;
+}
+
+ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
+{
+ return 0;
+}
+
+ssize_t zts_recvmsg(ZT_RECVMSG_SIG)
+{
+ return 0;
+}
+
+int zts_read(ZT_READ_SIG) {
+ return read(fd, buf, len);
+}
+
+int zts_write(ZT_WRITE_SIG) {
+ return write(fd, buf, len);
+}
+
+
+
/****************************************************************************/
/* SDK Socket API (Java Native Interface JNI) */
/* JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME */
@@ -489,17 +629,17 @@ int zts_multiplex_new_bind(ZT_BIND_SIG)
// Starts a ZeroTier service in the background
void *_start_service(void *thread_id) {
- DEBUG_INFO("homeDir=%s", homeDir.c_str());
+ DEBUG_INFO("homeDir=%s", ZeroTier::homeDir.c_str());
// Where network .conf files will be stored
- netDir = homeDir + "/networks.d";
+ ZeroTier::netDir = ZeroTier::homeDir + "/networks.d";
zt1Service = (ZeroTier::OneService *)0;
// Construct path for network config and supporting service files
- if (homeDir.length()) {
- std::vector hpsp(ZeroTier::OSUtils::split(homeDir.c_str(),
+ if (ZeroTier::homeDir.length()) {
+ std::vector hpsp(ZeroTier::OSUtils::split(ZeroTier::homeDir.c_str(),
ZT_PATH_SEPARATOR_S,"",""));
std::string ptmp;
- if (homeDir[0] == ZT_PATH_SEPARATOR)
+ if (ZeroTier::homeDir[0] == ZT_PATH_SEPARATOR)
ptmp.push_back(ZT_PATH_SEPARATOR);
for(std::vector::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
if (ptmp.length() > 0)
@@ -518,7 +658,7 @@ void *_start_service(void *thread_id) {
return NULL;
}
// rpc dir
- if(!ZeroTier::OSUtils::mkdir(homeDir + "/" + ZT_SDK_RPC_DIR_PREFIX)) {
+ if(!ZeroTier::OSUtils::mkdir(ZeroTier::homeDir + "/" + ZT_SDK_RPC_DIR_PREFIX)) {
DEBUG_ERROR("unable to create dir: " ZT_SDK_RPC_DIR_PREFIX);
return NULL;
}
@@ -530,7 +670,7 @@ void *_start_service(void *thread_id) {
DEBUG_ERROR("servicePort = %d", servicePort);
for(;;) {
- zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort);
+ zt1Service = ZeroTier::OneService::newInstance(ZeroTier::homeDir.c_str(),servicePort);
switch(zt1Service->run()) {
case ZeroTier::OneService::ONE_STILL_RUNNING:
case ZeroTier::OneService::ONE_NORMAL_TERMINATION:
@@ -542,14 +682,14 @@ void *_start_service(void *thread_id) {
delete zt1Service;
zt1Service = (ZeroTier::OneService *)0;
std::string oldid;
- ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S
+ ZeroTier::OSUtils::readFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret").c_str(),oldid);
if (oldid.length()) {
- ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S
+ ZeroTier::OSUtils::writeFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret.saved_after_collision").c_str(),oldid);
- ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S
+ ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret").c_str());
- ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S
+ ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.public").c_str());
}
}
diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp
index 47a4962..4843060 100644
--- a/src/picoTCP.cpp
+++ b/src/picoTCP.cpp
@@ -1,6 +1,6 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,15 +14,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
*/
#include "pico_eth.h"
@@ -70,7 +61,7 @@ int pico_socket_recv(PICO_SOCKET_RECV_SIG);
extern "C" int pico_socket_recvfrom(PICO_SOCKET_RECVFROM_SIG);
extern "C" struct pico_socket * pico_socket_open(PICO_SOCKET_OPEN_SIG);
int pico_socket_bind(PICO_SOCKET_BIND_SIG);
-int pico_socket_connect(PICO_SOCKET_CONNECT_SIG);
+extern "C" int pico_socket_connect(PICO_SOCKET_CONNECT_SIG);
extern "C" int pico_socket_listen(PICO_SOCKET_LISTEN_SIG);
int pico_socket_read(PICO_SOCKET_READ_SIG);
extern "C" int pico_socket_write(PICO_SOCKET_WRITE_SIG);
@@ -98,6 +89,7 @@ namespace ZeroTier {
void picoTCP::pico_init_interface(SocketTap *tap, const InetAddress &ip)
{
+ DEBUG_INFO();
if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) {
tap->_ips.push_back(ip);
std::sort(tap->_ips.begin(),tap->_ips.end());
@@ -158,7 +150,8 @@ namespace ZeroTier {
void picoTCP::pico_cb_tcp_read(ZeroTier::SocketTap *tap, struct pico_socket *s)
{
- Connection *conn = tap->getConnection(s);
+ DEBUG_INFO();
+ Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
if(conn) {
int r;
uint16_t port = 0;
@@ -167,9 +160,9 @@ namespace ZeroTier {
struct pico_ip6 ip6;
} peer;
do {
- int avail = DEFAULT_TCP_RX_BUF_SZ - conn->rxsz;
+ int avail = ZT_TCP_RX_BUF_SZ - conn->rxsz;
if(avail) {
- r = pico_socket_recvfrom(s, conn->rxbuf + (conn->rxsz), SDK_MTU,
+ r = pico_socket_recvfrom(s, conn->rxbuf + (conn->rxsz), ZT_SDK_MTU,
(void *)&peer.ip4.addr, &port);
tap->_phy.setNotifyWritable(conn->sock, true);
if (r > 0)
@@ -186,7 +179,8 @@ namespace ZeroTier {
void picoTCP::pico_cb_udp_read(SocketTap *tap, struct pico_socket *s)
{
- Connection *conn = tap->getConnection(s);
+ DEBUG_INFO();
+ Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
if(conn) {
uint16_t port = 0;
@@ -195,14 +189,14 @@ namespace ZeroTier {
struct pico_ip6 ip6;
} peer;
- char tmpbuf[SDK_MTU];
+ char tmpbuf[ZT_SDK_MTU];
unsigned char *addr_pos, *sz_pos, *payload_pos;
struct sockaddr_in addr_in;
addr_in.sin_addr.s_addr = peer.ip4.addr;
addr_in.sin_port = port;
// RX
- int r = pico_socket_recvfrom(s, tmpbuf, SDK_MTU, (void *)&peer.ip4.addr, &port);
+ int r = pico_socket_recvfrom(s, tmpbuf, ZT_SDK_MTU, (void *)&peer.ip4.addr, &port);
//DEBUG_FLOW(" [ RXBUF <- STACK] Receiving (%d) from stack, copying to receving buffer", r);
// Mutex::Lock _l2(tap->_rx_buf_m);
@@ -211,12 +205,12 @@ namespace ZeroTier {
// addr_in6.sin6_port = Utils::ntoh(s->remote_port);
// DEBUG_ATTN("remote_port=%d, local_port=%d", s->remote_port, Utils::ntoh(s->local_port));
tap->_rx_buf_m.lock();
- if(conn->rxsz == DEFAULT_UDP_RX_BUF_SZ) { // if UDP buffer full
+ if(conn->rxsz == ZT_UDP_RX_BUF_SZ) { // if UDP buffer full
//DEBUG_FLOW(" [ RXBUF <- STACK] UDP RX buffer full. Discarding oldest payload segment");
- memmove(conn->rxbuf, conn->rxbuf + SDK_MTU, DEFAULT_UDP_RX_BUF_SZ - SDK_MTU);
- addr_pos = conn->rxbuf + (DEFAULT_UDP_RX_BUF_SZ - SDK_MTU); // TODO:
+ memmove(conn->rxbuf, conn->rxbuf + ZT_SDK_MTU, ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU);
+ addr_pos = conn->rxbuf + (ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU); // TODO:
sz_pos = addr_pos + sizeof(struct sockaddr_storage);
- conn->rxsz -= SDK_MTU;
+ conn->rxsz -= ZT_SDK_MTU;
}
else {
addr_pos = conn->rxbuf + conn->rxsz; // where we'll prepend the size of the address
@@ -229,7 +223,7 @@ namespace ZeroTier {
// Adjust buffer size
if(r) {
- conn->rxsz += SDK_MTU;
+ conn->rxsz += ZT_SDK_MTU;
memcpy(sz_pos, &r, sizeof(r));
}
if (r < 0) {
@@ -247,14 +241,18 @@ namespace ZeroTier {
void picoTCP::pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s)
{
- Connection *conn = tap->getConnection(s);
- if(!conn)
+ DEBUG_INFO();
+ Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
+
+ if(!conn) {
DEBUG_ERROR("invalid connection");
+ return;
+ }
if(!conn->txsz)
return;
// Only called from a locked context, no need to lock anything
if(conn->txsz > 0) {
- int r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU;
+ int r, max_write_len = conn->txsz < ZT_SDK_MTU ? conn->txsz : ZT_SDK_MTU;
if((r = pico_socket_write(s, &conn->txbuf, max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p", s);
return;
@@ -265,7 +263,7 @@ namespace ZeroTier {
conn->txsz -= r;
#if DEBUG_LEVEL >= MSG_TRANSFER
- int max = conn->socket_type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ;
+ int max = conn->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_UDP_TX_BUF_SZ;
DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
#endif
@@ -276,40 +274,43 @@ namespace ZeroTier {
void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s)
{
+ DEBUG_INFO();
+ // TODO: Test API out of order so this check isn't necessary
+ if(!(SocketTap*)((Larg*)(s->priv)))
+ return;
+ SocketTap *tap = (SocketTap*)((Larg*)(s->priv))->tap;
+ Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
+
int err;
- Mutex::Lock _l(picotap->_tcpconns_m);
- Connection *conn = picotap->getConnection(s);
+ Mutex::Lock _l(tap->_tcpconns_m);
if(!conn) {
DEBUG_ERROR("invalid connection");
}
+
// accept()
if (ev & PICO_SOCK_EV_CONN) {
- DEBUG_INFO("connection established with server, picosock=%p",(conn->picosock));
uint32_t peer;
uint16_t port;
- struct pico_socket *client = pico_socket_accept(s, &peer, &port);
- if(!client) {
+ struct pico_socket *client_psock = pico_socket_accept(s, &peer, &port);
+ DEBUG_INFO("accepted (pico_sock=%p) on (pico_sock=%p)", client_psock, conn->picosock);
+ if(!client_psock) {
DEBUG_EXTRA("unable to accept conn. (event might not be incoming, not necessarily an error), picosock=%p", (conn->picosock));
- }
- ZT_PHY_SOCKFD_TYPE fds[2];
- if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
- if(errno < 0) {
- // FIXME: Return a value to the client
- //tap->sendReturnValue(conn, -1, errno);
- DEBUG_ERROR("unable to create socketpair");
- return;
- }
- }
- Connection *newTcpConn = new Connection();
- picotap->_Connections.push_back(newTcpConn);
- newTcpConn->socket_type = SOCK_STREAM;
- newTcpConn->sock = picotap->_phy.wrapSocket(fds[0], newTcpConn);
- newTcpConn->picosock = client;
- int fd = picotap->_phy.getDescriptor(conn->sock);
- if(sock_fd_write(fd, fds[1]) < 0) {
- DEBUG_ERROR("error sending new fd to client application");
- }
- DEBUG_EXTRA("conn=%p, physock=%p, listen_picosock=%p, new_picosock=%p, fd=%d", newTcpConn, newTcpConn->sock, s, client, fds[1]);
+ }
+
+ // Create a new Connection and add it to the queue,
+ // some time in the future a call to zts_multiplex_accept() will pick up
+ // this new connection, add it to the connection list and return its
+ // Connection->sock to the application
+
+ Connection *newConn = new Connection();
+ newConn->socket_type = SOCK_STREAM;
+ newConn->sock = tap->_phy.wrapSocket(newConn->sdk_fd, newConn);
+ newConn->picosock = client_psock;
+ newConn->tap = tap;
+ newConn->picosock->priv = new Larg(tap,newConn);
+
+ tap->_Connections.push_back(newConn);
+ conn->_AcceptedConnections.push(newConn);
}
if (ev & PICO_SOCK_EV_FIN) {
DEBUG_INFO("socket closed. exit normally. picosock=%p\n\n", s);
@@ -322,7 +323,7 @@ namespace ZeroTier {
err = pico_socket_close(s);
DEBUG_INFO("socket closure = %d, picosock=%p", err, s);
if(err==0) {
- picotap->closeConnection(conn->sock);
+ tap->closeConnection(conn->sock);
}
return;
}
@@ -356,6 +357,7 @@ namespace ZeroTier {
int pico_eth_send(struct pico_device *dev, void *buf, int len)
{
+ DEBUG_INFO();
struct pico_eth_hdr *ethhdr;
ethhdr = (struct pico_eth_hdr *)buf;
MAC src_mac;
@@ -370,6 +372,7 @@ namespace ZeroTier {
void picoTCP::pico_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
+ DEBUG_INFO();
// Since picoTCP only allows the reception of frames from within the polling function, we
// must enqueue each frame into a memory structure shared by both threads. This structure will
Mutex::Lock _l(tap->_pico_frame_rxbuf_m);
@@ -406,7 +409,7 @@ namespace ZeroTier {
// OPTIMIZATION: The copy logic and/or buffer structure should be reworked for better performance after the BETA
// SocketTap *tap = (SocketTap*)netif->state;
Mutex::Lock _l(picotap->_pico_frame_rxbuf_m);
- unsigned char frame[SDK_MTU];
+ unsigned char frame[ZT_SDK_MTU];
int len;
while (picotap->pico_frame_rxbuf_tot > 0 && loop_score > 0) {
//DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", picotap->pico_frame_rxbuf_tot);
@@ -429,78 +432,19 @@ namespace ZeroTier {
return loop_score;
}
- // FIXME: This function's contents should be retired
- // More or less duplicated in zts_multiplex_new_socket()
- Connection *picoTCP::pico_handleSocket(PhySocket *sock, void **uptr,
- struct socket_st* socket_rpc)
- {
- struct pico_socket * psock;
- int protocol, protocol_version;
-
- #if defined(SDK_IPV4)
- protocol_version = PICO_PROTO_IPV4;
- #elif defined(SDK_IPV6)
- protocol_version = PICO_PROTO_IPV6;
- #endif
- if(socket_rpc->socket_type == SOCK_DGRAM) {
- protocol = PICO_PROTO_UDP;
- psock = pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity);
- }
- if(socket_rpc->socket_type == SOCK_STREAM) {
- protocol = PICO_PROTO_TCP;
- psock = pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity);
- }
-
- if(psock) {
- DEBUG_ATTN("physock=%p, picosock=%p", sock, psock);
- Connection * newConn = new Connection();
- *uptr = newConn;
- newConn->socket_type = socket_rpc->socket_type;
- newConn->sock = sock;
- newConn->local_addr = NULL;
- newConn->picosock = psock;
- picotap->_Connections.push_back(newConn);
- memset(newConn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ);
- return newConn;
- }
- else
- DEBUG_ERROR("failed to create pico_socket");
- return NULL;
- }
-
void picoTCP::pico_handleWrite(Connection *conn)
{
+ DEBUG_INFO();
if(!conn || !conn->picosock) {
DEBUG_ERROR(" invalid connection");
return;
}
- int max, r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU;
+ int max, r, max_write_len = conn->txsz < ZT_SDK_MTU ? conn->txsz : ZT_SDK_MTU;
if((r = pico_socket_write(conn->picosock, &conn->txbuf, max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", (conn->picosock), r);
return;
}
-
- // TODO: Errors
-
- /*
- if(pico_err == PICO_ERR_EINVAL)
- DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
- if(pico_err == PICO_ERR_EIO)
- DEBUG_ERROR("PICO_ERR_EIO - input/output error");
- if(pico_err == PICO_ERR_ENOTCONN)
- DEBUG_ERROR("PICO_ERR_ENOTCONN - the socket is not connected");
- if(pico_err == PICO_ERR_ESHUTDOWN)
- DEBUG_ERROR("PICO_ERR_ESHUTDOWN - cannot send after transport endpoint shutdown");
- if(pico_err == PICO_ERR_EADDRNOTAVAIL)
- DEBUG_ERROR("PICO_ERR_EADDRNOTAVAIL - address not available");
- if(pico_err == PICO_ERR_EHOSTUNREACH)
- DEBUG_ERROR("PICO_ERR_EHOSTUNREACH - host is unreachable");
- if(pico_err == PICO_ERR_ENOMEM)
- DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space");
- if(pico_err == PICO_ERR_EAGAIN)
- DEBUG_ERROR("PICO_ERR_EAGAIN - resource temporarily unavailable");
- */
// adjust buffer
int sz = (conn->txsz)-r;
@@ -509,123 +453,130 @@ namespace ZeroTier {
conn->txsz -= r;
if(conn->socket_type == SOCK_STREAM) {
- max = DEFAULT_TCP_TX_BUF_SZ;
+ max = ZT_TCP_TX_BUF_SZ;
DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
}
if(conn->socket_type == SOCK_DGRAM) {
- max = DEFAULT_UDP_TX_BUF_SZ;
+ max = ZT_UDP_TX_BUF_SZ;
DEBUG_TRANS("[UDP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
}
}
- void picoTCP::pico_handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc)
- {
- if(conn->picosock) {
- struct sockaddr_in *addr = (struct sockaddr_in *) &connect_rpc->addr;
- int ret;
- // TODO: Rewrite this
- #if defined(SDK_IPV4)
- struct pico_ip4 zaddr;
- struct sockaddr_in *in4 = (struct sockaddr_in*)&connect_rpc->addr;
- char ipv4_str[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN);
- pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
- //DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh(addr->sin_port));
- ret = pico_socket_connect(conn->picosock, &zaddr, addr->sin_port);
- #elif defined(SDK_IPV6) // "fd56:5799:d8f6:1238:8c99:9322:30ce:418a"
- struct pico_ip6 zaddr;
- struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&connect_rpc->addr;
- char ipv6_str[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
- pico_string_to_ipv6(ipv6_str, zaddr.addr);
- //DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(addr->sin_port));
- ret = pico_socket_connect(conn->picosock, &zaddr, addr->sin_port);
- #endif
-
- memcpy(&(conn->peer_addr), &connect_rpc->addr, sizeof(struct sockaddr_storage));
-
- if(ret == PICO_ERR_EPROTONOSUPPORT)
- DEBUG_ERROR("PICO_ERR_EPROTONOSUPPORT");
- if(ret == PICO_ERR_EINVAL)
- DEBUG_ERROR("PICO_ERR_EINVAL");
- if(ret == PICO_ERR_EHOSTUNREACH)
- DEBUG_ERROR("PICO_ERR_EHOSTUNREACH");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), 0, ERR_OK);
- }
- }
-
- void picoTCP::pico_handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc)
- {
- Connection *conn = picotap->getConnection(sock);
- if(!sock) {
- DEBUG_ERROR("invalid connection");
- return;
- }
- struct sockaddr_in *addr = (struct sockaddr_in *) &bind_rpc->addr;
- int ret;
- // TODO: Rewrite this
+ int picoTCP::pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
+ {
+ int err;
#if defined(SDK_IPV4)
struct pico_ip4 zaddr;
- struct sockaddr_in *in4 = (struct sockaddr_in*)&bind_rpc->addr;
+ struct sockaddr_in *in4 = (struct sockaddr_in*)addr;
char ipv4_str[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN);
pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
- DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv4_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
- ret = pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port));
+ DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh( in4->sin_port ));
+ err = pico_socket_connect(conn->picosock, &zaddr, in4->sin_port);
+ DEBUG_INFO("connect_err = %d", err);
+
#elif defined(SDK_IPV6)
struct pico_ip6 zaddr;
- struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&bind_rpc->addr;
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
char ipv6_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
pico_string_to_ipv6(ipv6_str, zaddr.addr);
- DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv6_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
- ret = pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port));
+ DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(addr->sin_port));
+ err = pico_socket_connect(conn->picosock, &zaddr, (struct sockaddr_in *)&addr->sin_port);
#endif
- if(ret < 0) {
- DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), ret);
- if(ret == PICO_ERR_EINVAL) {
- DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL);
- }
- if(ret == PICO_ERR_ENOMEM) {
- DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENOMEM);
- }
- if(ret == PICO_ERR_ENXIO) {
- DEBUG_ERROR("PICO_ERR_ENXIO - no such device or address");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENXIO);
- }
- }
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success
+
+ memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage));
+
+ if(err == PICO_ERR_EPROTONOSUPPORT)
+ DEBUG_ERROR("PICO_ERR_EPROTONOSUPPORT");
+ if(err == PICO_ERR_EINVAL)
+ DEBUG_ERROR("PICO_ERR_EINVAL");
+ if(err == PICO_ERR_EHOSTUNREACH)
+ DEBUG_ERROR("PICO_ERR_EHOSTUNREACH");
+ return err;
}
- void picoTCP::pico_handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc)
+ int picoTCP::pico_Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{
- Connection *conn = picotap->getConnection(sock);
- DEBUG_ATTN("physock=%p, conn=%p, picosock=%p", sock, conn, conn->picosock);
- if(!sock || !conn) {
- DEBUG_ERROR("invalid connection");
- return;
- }
- int ret, backlog = 100;
- if((ret = pico_socket_listen(conn->picosock, backlog)) < 0)
+ int err;
+ #if defined(SDK_IPV4)
+ struct pico_ip4 zaddr;
+ struct sockaddr_in *in4 = (struct sockaddr_in*)addr;
+ char ipv4_str[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN);
+ pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
+ //DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv4_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
+ err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)&(in4->sin_port));
+ #elif defined(SDK_IPV6)
+ struct pico_ip6 zaddr;
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
+ char ipv6_str[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
+ pico_string_to_ipv6(ipv6_str, zaddr.addr);
+ //DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv6_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
+ err = pico_socket_bind(conn->picosock, &zaddr, (struct sockaddr_in *)&addr->sin_port);
+ #endif
+ if(err < 0) {
+ DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), err);
+ if(err == PICO_ERR_EINVAL) {
+ DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
+ errno = EINVAL;
+ return -1;
+ }
+ if(err == PICO_ERR_ENOMEM) {
+ DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space");
+ errno = ENOMEM;
+ return -1;
+ }
+ if(err == PICO_ERR_ENXIO) {
+ DEBUG_ERROR("PICO_ERR_ENXIO - no such device or address");
+ errno = ENXIO;
+ return -1;
+ }
+ }
+ return err;
+ }
+
+ int picoTCP::pico_Listen(Connection *conn, int fd, int backlog)
+ {
+ DEBUG_INFO();
+ int err;
+ if((err = pico_socket_listen(conn->picosock, backlog)) < 0)
{
- if(ret == PICO_ERR_EINVAL) {
+ if(err == PICO_ERR_EINVAL) {
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL);
+ errno = EINVAL;
+ return -1;
}
- if(ret == PICO_ERR_EISCONN) {
+ if(err == PICO_ERR_EISCONN) {
DEBUG_ERROR("PICO_ERR_EISCONN - socket is connected");
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EISCONN);
+ errno = EISCONN;
+ return -1;
}
}
- picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success
+ return ZT_ERR_OK;
+ }
+
+ int picoTCP::pico_Accept(Connection *conn)
+ {
+ // Retreive queued Connections from parent connection
+ int err;
+ if(!conn->_AcceptedConnections.size()) {
+ err = -1;
+ }
+ else {
+ Connection *new_conn = conn->_AcceptedConnections.front();
+ conn->_AcceptedConnections.pop();
+ err = new_conn->app_fd;
+ }
+ return err;
}
void picoTCP::pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked)
{
+ DEBUG_INFO();
if(!lwip_invoked) {
// The stack thread writes to RXBUF as well
picotap->_tcpconns_m.lock();
@@ -638,17 +589,17 @@ namespace ZeroTier {
//
if(conn->socket_type==SOCK_DGRAM) {
- // Try to write SDK_MTU-sized chunk to app socket
- while(tot < SDK_MTU) {
+ // Try to write ZT_SDK_MTU-sized chunk to app socket
+ while(tot < ZT_SDK_MTU) {
write_attempts++;
- n = picotap->_phy.streamSend(conn->sock, (conn->rxbuf)+tot, SDK_MTU);
+ n = picotap->_phy.streamSend(conn->sock, (conn->rxbuf)+tot, ZT_SDK_MTU);
tot += n;
DEBUG_FLOW(" [ ZTSOCK <- RXBUF] wrote = %d, errno=%d", n, errno);
// If socket is unavailable, attempt to write N times before giving up
if(errno==35) {
if(write_attempts == 1024) {
- n = SDK_MTU; // say we wrote it, even though we didn't (drop packet)
- tot = SDK_MTU;
+ n = ZT_SDK_MTU; // say we wrote it, even though we didn't (drop packet)
+ tot = ZT_SDK_MTU;
}
}
}
@@ -659,15 +610,16 @@ namespace ZeroTier {
// adjust buffer
//DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Copying data from receiving buffer to ZT-controlled app socket (n=%d, payload_sz=%d)", n, payload_sz);
if(conn->rxsz-n > 0) { // If more remains on buffer
- memcpy(conn->rxbuf, conn->rxbuf+SDK_MTU, conn->rxsz - SDK_MTU);
+ memcpy(conn->rxbuf, conn->rxbuf+ZT_SDK_MTU, conn->rxsz - ZT_SDK_MTU);
//DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Data(%d) still on buffer, moving it up by one MTU", conn->rxsz-n);
- ////memset(conn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ);
- ////conn->rxsz=SDK_MTU;
+ ////memset(conn->rxbuf, 0, ZT_UDP_RX_BUF_SZ);
+ ////conn->rxsz=ZT_SDK_MTU;
}
- conn->rxsz -= SDK_MTU;
+ conn->rxsz -= ZT_SDK_MTU;
}
//
if(conn->socket_type==SOCK_STREAM) {
+ DEBUG_TRANS("writing to conn->sock = %p", conn->sock);
n = picotap->_phy.streamSend(conn->sock, conn->rxbuf, conn->rxsz);
if(conn->rxsz-n > 0) // If more remains on buffer
memcpy(conn->rxbuf, conn->rxbuf+n, conn->rxsz - n);
@@ -678,7 +630,7 @@ namespace ZeroTier {
if(conn->socket_type==SOCK_STREAM) {
#if DEBUG_LEVEL >= MSG_TRANSFER
- float max = conn->socket_type == SOCK_STREAM ? (float)DEFAULT_TCP_RX_BUF_SZ : (float)DEFAULT_UDP_RX_BUF_SZ;
+ float max = conn->socket_type == SOCK_STREAM ? (float)ZT_TCP_RX_BUF_SZ : (float)ZT_UDP_RX_BUF_SZ;
DEBUG_TRANS("[TCP RX] <--- :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
(float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n);
#endif
@@ -698,11 +650,13 @@ namespace ZeroTier {
picotap->_tcpconns_m.unlock();
picotap->_rx_buf_m.unlock();
}
+ // FIXME: Re-write debug traces
DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Emitted (%d) from RXBUF(%d) to socket", tot, conn->rxsz);
}
void picoTCP::pico_handleClose(PhySocket *sock)
{
+ DEBUG_INFO();
/*
int ret;
if(conn && conn->picosock) {
diff --git a/src/picoTCP.hpp b/src/picoTCP.hpp
index 31631eb..b128358 100644
--- a/src/picoTCP.hpp
+++ b/src/picoTCP.hpp
@@ -1,6 +1,6 @@
/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
+ * ZeroTier SDK - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,21 +14,11 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
*/
#ifndef ZT_PICOTCP_HPP
#define ZT_PICOTCP_HPP
-
#include "pico_eth.h"
#include "pico_stack.h"
#include "pico_ipv4.h"
@@ -79,26 +69,50 @@ namespace ZeroTier
{
public:
+ /*
+ * Set up an interface in the network stack for the SocketTap
+ */
void pico_init_interface(ZeroTier::SocketTap *tap, const ZeroTier::InetAddress &ip);
+
+ /*
+ * Main stack loop
+ */
void pico_loop(SocketTap *tap);
- //int pico_eth_send(struct pico_device *dev, void *buf, int len);
- //int pico_eth_poll(struct pico_device *dev, int loop_score);
+ /*
+ * Read bytes from the stack to the RX buffer (prepare to be read by app)
+ */
static void pico_cb_tcp_read(SocketTap *tap, struct pico_socket *s);
- static void pico_cb_udp_read(SocketTap *tap, struct pico_socket *s);
- static void pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s);
- static void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s);
+ /*
+ * Read bytes from the stack to the RX buffer (prepare to be read by app)
+ */
+ static void pico_cb_udp_read(SocketTap *tap, struct pico_socket *s);
+
+ /*
+ * Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
+ */
+ static void pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s);
+
+ /*
+ * Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
+ */
+ static void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s);
+
+ /*
+ * Where packets enter the stack
+ */
void pico_rx(SocketTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len);
- Connection *pico_handleSocket(ZeroTier::PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
- void pico_handleWrite(Connection *conn);
- void pico_handleConnect(ZeroTier::PhySocket *sock, ZeroTier::PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc);
- void pico_handleBind(ZeroTier::PhySocket *sock, ZeroTier::PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc);
- void pico_handleListen(ZeroTier::PhySocket *sock, ZeroTier::PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc);
+
void pico_handleRead(ZeroTier::PhySocket *sock,void **uptr,bool lwip_invoked);
void pico_handleClose(ZeroTier::PhySocket *sock);
+ void pico_handleWrite(Connection *conn);
-
+ // common socket operations
+ int pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
+ int pico_Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
+ int pico_Listen(Connection *conn, int fd, int backlog);
+ int pico_Accept(Connection *conn);
};
}
diff --git a/test/dumb/tcpclient4.c b/test/dumb/tcpclient4.c
new file mode 100644
index 0000000..cf4b345
--- /dev/null
+++ b/test/dumb/tcpclient4.c
@@ -0,0 +1,62 @@
+// TCP Client test program
+
+#include
+#include
+#include
+#include
+#include
+
+int atoi(const char *str);
+int close(int filedes);
+
+#define MSG_SZ 128
+
+int main(int argc , char *argv[])
+{
+ if(argc < 3) {
+ printf("usage: client \n");
+ return 1;
+ }
+
+ int sock, port = atoi(argv[2]);
+ struct sockaddr_in server;
+ char message[MSG_SZ] , server_reply[MSG_SZ];
+
+ sock = socket(AF_INET , SOCK_STREAM , 0);
+ if (sock == -1) {
+ printf("could not create socket");
+ }
+ server.sin_addr.s_addr = inet_addr(argv[1]);
+ server.sin_family = AF_INET;
+ server.sin_port = htons( port );
+
+ printf("connecting...\n");
+ if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) {
+ perror("connect failed. Error");
+ return 1;
+ }
+ printf("connected\n");
+
+ char *msg = "welcome to the machine!";
+
+ while(1)
+ {
+ // TX
+ if(send(sock, msg, strlen(msg), 0) < 0) {
+ printf("send failed");
+ return 1;
+ }
+ else {
+ printf("TX: %s\n", msg);
+ printf("len = %ld\n", strlen(msg));
+
+ int bytes_read = read(sock, server_reply, MSG_SZ);
+ if(bytes_read < 0)
+ printf("\tRX: Nothing\n");
+ else
+ printf("\tRX = (%d bytes): %s\n", bytes_read, server_reply);
+ }
+ }
+ close(sock);
+ return 0;
+}
diff --git a/test/dumb/tcpclient6.c b/test/dumb/tcpclient6.c
new file mode 100644
index 0000000..a4aadd4
--- /dev/null
+++ b/test/dumb/tcpclient6.c
@@ -0,0 +1,72 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+void error(char *msg) {
+ perror(msg);
+ exit(0);
+}
+
+int main(int argc, char *argv[]) {
+ int sockfd, portno, n;
+ struct sockaddr_in6 serv_addr;
+ struct hostent *server;
+ char buffer[256] = "This is a string from client!";
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s \n", argv[0]);
+ exit(0);
+ }
+ portno = atoi(argv[2]);
+
+ printf("\nIPv6 TCP Client Started...\n");
+
+ //Sockets Layer Call: socket()
+ sockfd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ error("ERROR opening socket");
+
+ //Sockets Layer Call: gethostbyname2()
+ server = gethostbyname2(argv[1],AF_INET6);
+ if (server == NULL) {
+ fprintf(stderr, "ERROR, no such host\n");
+ exit(0);
+ }
+
+ memset((char *) &serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin6_flowinfo = 0;
+ serv_addr.sin6_family = AF_INET6;
+ memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
+ serv_addr.sin6_port = htons(portno);
+
+ //Sockets Layer Call: connect()
+ if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ error("ERROR connecting");
+
+
+ //Sockets Layer Call: send()
+ n = send(sockfd,buffer, strlen(buffer)+1, 0);
+ if (n < 0)
+ error("ERROR writing to socket");
+
+ printf("sent %d bytes\n", n);
+ memset(buffer, 0, 256);
+
+ //Sockets Layer Call: recv()
+ printf("reading...\n");
+ n = recv(sockfd, buffer, 255, 0);
+ if (n < 0)
+ error("ERROR reading from socket");
+ printf("Message from server: %s\n", buffer);
+
+ //Sockets Layer Call: close()
+ close(sockfd);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/test/dumb/tcpserver4.c b/test/dumb/tcpserver4.c
new file mode 100644
index 0000000..1480dbb
--- /dev/null
+++ b/test/dumb/tcpserver4.c
@@ -0,0 +1,61 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+int atoi(const char *str);
+
+int main(int argc , char *argv[])
+{
+ if(argc < 2) {
+ printf("usage: tcp_server \n");
+ return 0;
+ }
+
+ int comm_fd, sock, client_sock, c, read_size, port = atoi(argv[1]);
+ char client_message[2000];
+
+ struct sockaddr_in servaddr;
+ struct sockaddr_in client;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ bzero( &servaddr, sizeof(servaddr));
+
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htons(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+ bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
+
+ printf("listening\n");
+ listen(sock , 3);
+ printf("waiting to accept\n");
+ c = sizeof(struct sockaddr_in);
+
+ client_sock = accept(sock, (struct sockaddr *)&client, (socklen_t*)&c);
+ if (client_sock < 0) {
+ perror("accept failed");
+ return 0;
+ }
+ printf("connection accepted\n reading...\n");
+
+ // RX
+
+ int msglen = 1024;
+ unsigned long count = 0;
+ while(1)
+ {
+ count++;
+ int bytes_read = read(client_sock, client_message, msglen);
+ printf("[%lu] RX = (%d): ", count, bytes_read);
+ for(int i=0; i
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+void error(char *msg) {
+ perror(msg);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int sockfd, newsockfd, portno;
+ socklen_t clilen;
+ char buffer[256];
+ struct sockaddr_in6 serv_addr, cli_addr;
+ int n;
+ char client_addr_ipv6[100];
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s \n", argv[0]);
+ exit(0);
+ }
+
+ printf("\nIPv6 TCP Server Started...\n");
+
+ //Sockets Layer Call: socket()
+ sockfd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ error("ERROR opening socket");
+
+ bzero((char *) &serv_addr, sizeof(serv_addr));
+ portno = atoi(argv[1]);
+ serv_addr.sin6_flowinfo = 0;
+ serv_addr.sin6_family = AF_INET6;
+ serv_addr.sin6_addr = in6addr_any;
+ serv_addr.sin6_port = htons(portno);
+
+
+ //Sockets Layer Call: bind()
+ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ error("ERROR on binding");
+
+ //Sockets Layer Call: listen()
+ listen(sockfd, 5);
+ clilen = sizeof(cli_addr);
+
+ //Sockets Layer Call: accept()
+ newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
+ if (newsockfd < 0)
+ error("ERROR on accept");
+
+ //Sockets Layer Call: inet_ntop()
+ inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100);
+ printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6);
+
+ memset(buffer,0, 256);
+
+ //Sockets Layer Call: recv()
+ n = recv(newsockfd, buffer, 255, 0);
+ if (n < 0)
+ error("ERROR reading from socket");
+
+ printf("Message from client: %s\n", buffer);
+
+ //Sockets Layer Call: send()
+ printf("sending...\n");
+ n = send(newsockfd, "Server got your message", 23+1, 0);
+ if (n < 0)
+ error("ERROR writing to socket");
+
+ //Sockets Layer Call: close()
+ close(sockfd);
+ close(newsockfd);
+
+ return 0;
+}
diff --git a/test/dumb/udpclient4.c b/test/dumb/udpclient4.c
new file mode 100755
index 0000000..663e69c
--- /dev/null
+++ b/test/dumb/udpclient4.c
@@ -0,0 +1,88 @@
+/*
+ * udpclient.c - A simple UDP client
+ * usage: udpclient
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define BUFSIZE 1024
+
+/*
+ * error - wrapper for perror
+ */
+void error(char *msg) {
+ perror(msg);
+ exit(0);
+}
+
+int main(int argc, char **argv) {
+ int sock, portno, n;
+ int serverlen;
+ struct sockaddr_in serveraddr;
+ struct hostent *server;
+ char *hostname;
+ char buf[BUFSIZE];
+
+ /* check command line arguments */
+ if (argc != 3) {
+ fprintf(stderr,"usage: %s \n", argv[0]);
+ exit(0);
+ }
+ hostname = argv[1];
+ portno = atoi(argv[2]);
+
+ /* socket: create the socket */
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ error("ERROR opening socket");
+
+ /* gethostbyname: get the server's DNS entry */
+ server = gethostbyname(hostname);
+ if (server == NULL) {
+ fprintf(stderr,"ERROR, no such host as %s\n", hostname);
+ exit(0);
+ }
+
+ /* build the server's Internet address */
+ bzero((char *) &serveraddr, sizeof(serveraddr));
+ serveraddr.sin_family = AF_INET;
+ bcopy((char *)server->h_addr,
+ (char *)&serveraddr.sin_addr.s_addr, server->h_length);
+ serveraddr.sin_port = htons(portno);
+
+ /* get a message from the user */
+ char *msg = "A message to the server!\0";
+ fcntl(sock, F_SETFL, O_NONBLOCK);
+ long count = 0;
+ while(1)
+ {
+ count++;
+ printf("\n\n\nTX(%lu)...\n", count);
+ sleep(1);
+ //usleep(10000);
+ //bzero(buf, BUFSIZE);
+ //printf("\nPlease enter msg: ");
+ //fgets(buf, BUFSIZE, stdin);
+
+ /* send the message to the server */
+ serverlen = sizeof(serveraddr);
+ n = sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)&serveraddr, serverlen);
+ //if (n < 0)
+ // error("ERROR in sendto");
+
+ /* print the server's reply */
+ memset(buf, 0, sizeof(buf));
+ n = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *)&serveraddr, (socklen_t *)&serverlen);
+ //if (n < 0)
+ // printf("ERROR in recvfrom: %d", n);
+ printf("Echo from server: %s", buf);
+ }
+ return 0;
+}
diff --git a/test/dumb/udpclient6.c b/test/dumb/udpclient6.c
new file mode 100755
index 0000000..36607fa
--- /dev/null
+++ b/test/dumb/udpclient6.c
@@ -0,0 +1,43 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAXBUF 65536
+
+int main(int argc, char* argv[])
+{
+ int status;
+ struct addrinfo sainfo, *psinfo;
+ struct hostent *server;
+ char buffer[MAXBUF];
+
+ int sock, portno, n;
+ struct sockaddr_in6 serv_addr;
+
+ if(argc < 2)
+ printf("Specify a port number\n"), exit(1);
+
+ sock = socket(PF_INET6, SOCK_DGRAM,0);
+
+ portno = atoi(argv[2]);
+ server = gethostbyname2(argv[1],AF_INET6);
+ memset((char *) &serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin6_flowinfo = 0;
+ serv_addr.sin6_family = AF_INET6;
+ memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
+ serv_addr.sin6_port = htons(portno);
+
+ sprintf(buffer,"Ciao");
+
+ status = sendto(sock, buffer, strlen(buffer), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
+ printf("buffer : %s \t%d\n", buffer, status);
+
+ close(sock);
+ return 0;
+}
\ No newline at end of file
diff --git a/test/dumb/udpserver4.c b/test/dumb/udpserver4.c
new file mode 100755
index 0000000..2280435
--- /dev/null
+++ b/test/dumb/udpserver4.c
@@ -0,0 +1,86 @@
+// UDP Server test program
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAXBUF 1024*1024
+
+void echo(int sock) {
+ char bufin[MAXBUF];
+ struct sockaddr_in remote;
+ int n;
+ socklen_t len = sizeof(remote);
+ long count = 0;
+
+ while (1) {
+ sleep(1);
+ //usleep(50);
+ count++;
+ // read a datagram from the socket (put result in bufin)
+ n=recvfrom(sock,bufin,MAXBUF,0,(struct sockaddr *)&remote,&len);
+ // print out the address of the sender
+ printf("DGRAM from %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
+
+ if (n<0) {
+ perror("Error receiving data");
+ } else {
+ printf("GOT %d BYTES (count = %ld)\n", n, count);
+ // Got something, just send it back
+ // sendto(sock,bufin,n,0,(struct sockaddr *)&remote,len);
+ printf("RX = %s\n", bufin);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+
+ if(argc < 2) {
+ printf("usage: udp_server \n");
+ return 0;
+ }
+ int sock, port = atoi(argv[1]);
+ socklen_t len;
+ struct sockaddr_in skaddr;
+ struct sockaddr_in skaddr2;
+
+ // Create socket
+ if ((sock = socket( PF_INET, SOCK_DGRAM, 0)) < 0) {
+ printf("error creating socket\n");
+ return 0;
+ }
+ // Create address
+ skaddr.sin_family = AF_INET;
+ skaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ skaddr.sin_port = htons(port);
+ // Bind to address
+ if (bind(sock, (struct sockaddr *) &skaddr, sizeof(skaddr))<0) {
+ printf("error binding\n");
+ return 0;
+ }
+ // find out what port we were assigned
+ len = sizeof( skaddr2 );
+ //if (getsockname(sock, (struct sockaddr *) &skaddr2, &len)<0) {
+ // printf("error getsockname\n");
+ // return 0;
+ //}
+ // Display address:port to verify it was sent over RPC correctly
+ /*
+ port = ntohs(skaddr2.sin_port);
+ int ip = skaddr2.sin_addr.s_addr;
+ unsigned char d[4];
+ d[0] = ip & 0xFF;
+ d[1] = (ip >> 8) & 0xFF;
+ d[2] = (ip >> 16) & 0xFF;
+ d[3] = (ip >> 24) & 0xFF;
+ printf("bound to address: %d.%d.%d.%d : %d\n", d[0],d[1],d[2],d[3], port);
+ */
+ // RX
+ echo(sock);
+ return(0);
+}
diff --git a/test/dumb/udpserver6.c b/test/dumb/udpserver6.c
new file mode 100755
index 0000000..4ed977b
--- /dev/null
+++ b/test/dumb/udpserver6.c
@@ -0,0 +1,44 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAXBUF 65536
+
+int main(int argc, char *argv[])
+{
+ int sock;
+ int n;
+ struct sockaddr_in6 sin6;
+ socklen_t sin6len;
+ char buffer[MAXBUF];
+
+ sock = socket(PF_INET6, SOCK_DGRAM,0);
+ sin6len = sizeof(struct sockaddr_in6);
+ memset(&sin6, 0, sin6len);
+
+ sin6.sin6_port = htons(atoi(argv[1]));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6addr_any;
+
+ n = bind(sock, (struct sockaddr *)&sin6, sin6len);
+ if(-1 == n)
+ perror("bind"), exit(1);
+
+ //n = getsockname(sock, (struct sockaddr *)&sin6, &sin6len);
+ //printf("%d\n", ntohs(sin6.sin6_port));
+
+ while (1) {
+ sleep(1);
+ n = recvfrom(sock, buffer, MAXBUF, 0, (struct sockaddr *)&sin6, &sin6len);
+ printf("n = %d, buffer : %s\n", n, buffer);
+ }
+
+ shutdown(sock, 2);
+ close(sock);
+ return 0;
+}
\ No newline at end of file
diff --git a/test/unit/client.cpp b/test/unit/client.cpp
new file mode 100644
index 0000000..c77a68d
--- /dev/null
+++ b/test/unit/client.cpp
@@ -0,0 +1,64 @@
+// Comprehensive stress test for socket-like API
+
+#include
+
+/****************************************************************************/
+/* Test Functions */
+/****************************************************************************/
+
+int test_for_correctness()
+{
+ return 0;
+}
+
+int ipv4_udp_client()
+{
+ return 0;
+}
+
+int ipv6_udp_client()
+{
+ return 0;
+}
+
+int ipv4_tcp_client()
+{
+ return 0;
+}
+
+int ipv6_tcp_client()
+{
+ return 0;
+}
+
+/****************************************************************************/
+/* main */
+/****************************************************************************/
+
+int main()
+{
+ int test_all = 1;
+
+ if(test_all)
+ {
+ printf("Testing API calls for correctness\n");
+ test_for_correctness();
+
+ printf("Testing as IPv4 UDP Client\n");
+ ipv4_udp_client();
+
+ printf("Testing as IPv6 UDP Client\n");
+ ipv6_udp_client();
+
+ printf("Testing as IPv4 TCP Client\n");
+ ipv4_udp_client();
+
+ printf("Testing as IPv6 TCP Client\n");
+ ipv6_udp_client();
+
+ printf("Testing \n");
+ printf("\n");
+ printf("\n");
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/socket/comprehensive.cpp b/test/unit/comprehensive.cpp
similarity index 100%
rename from tests/socket/comprehensive.cpp
rename to test/unit/comprehensive.cpp
diff --git a/tests/socket/server.cpp b/test/unit/server.cpp
similarity index 100%
rename from tests/socket/server.cpp
rename to test/unit/server.cpp
diff --git a/tests/socket/simple.cpp b/test/unit/simple.cpp
similarity index 62%
rename from tests/socket/simple.cpp
rename to test/unit/simple.cpp
index 6b7b425..67a4d6e 100644
--- a/tests/socket/simple.cpp
+++ b/test/unit/simple.cpp
@@ -14,7 +14,7 @@
int main()
{
- char *nwid = "e5cd7a9e1c0fd272";
+ char *nwid = (char *)"e5cd7a9e1c0fd272";
// Get ZeroTier core version
char ver[ZT_VER_STR_LEN];
@@ -34,7 +34,7 @@ int main()
printf("id = %s\n", id);
// Get the home path of this ZeroTier instance, where we store identity keys, conf files, etc
- char homePath[ZT_HOME_PATH_MAX_LEN];
+ char homePath[ZT_HOME_PATH_MAX_LEN+1];
zts_get_homepath(homePath, ZT_HOME_PATH_MAX_LEN);
printf("homePath = %s\n", homePath);
@@ -67,28 +67,54 @@ int main()
printf("sockfd = %d\n", sockfd);
// connect() IPv6
- struct hostent *server = gethostbyname2("fde5:cd7a:9e1c:fd2:7299:932e:e35a:9a03",AF_INET6);
- struct sockaddr_in6 serv_addr;
- memset((char *) &serv_addr, 0, sizeof(serv_addr));
- serv_addr.sin6_flowinfo = 0;
- serv_addr.sin6_family = AF_INET6;
- memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
- serv_addr.sin6_port = htons( port );
-
- if((err = zts_connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))) < 0)
- printf("error connecting to remote host (%d)\n", err);
- else
- printf("connected\n");
-
+ if(false)
+ {
+ struct hostent *server = gethostbyname2("fde5:cd7a:9e1c:fd2:7299:932e:e35a:9a03",AF_INET6);
+ struct sockaddr_in6 serv_addr;
+ memset((char *) &serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin6_flowinfo = 0;
+ serv_addr.sin6_family = AF_INET6;
+ memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
+ serv_addr.sin6_port = htons( port );
+ if((err = zts_connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))) < 0) {
+ printf("error connecting to remote host (%d)\n", err);
+ return -1;
+ }
+ }
// connect() IPv4
- addr.sin_addr.s_addr = inet_addr("10.9.9.4");
- addr.sin_family = AF_INET;
- addr.sin_port = htons( port );
-
- if((err = zts_connect(sockfd, (const struct sockaddr *)&addr, sizeof(addr))) < 0)
- printf("error connecting to remote host (%d)\n", err);
- else
- printf("connected\n");
+ if(true)
+ {
+ addr.sin_addr.s_addr = inet_addr("10.9.9.20");
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons( port );
+ if((err = zts_connect(sockfd, (const struct sockaddr *)&addr, sizeof(addr))) < 0) {
+ printf("error connecting to remote host (%d)\n", err);
+ return -1;
+ }
+ }
+ // bind() ipv4
+ if(false)
+ {
+ //addr.sin_addr.s_addr = INADDR_ANY; // TODO: Requires significant socket multiplexer work
+ addr.sin_addr.s_addr = inet_addr("10.9.9.40");
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons( port );
+ if((err = zts_bind(sockfd, (const struct sockaddr *)&addr, sizeof(addr))) < 0) {
+ printf("error binding to interface (%d)\n", err);
+ return -1;
+ }
+ zts_listen(sockfd, 1);
+ struct sockaddr_in client;
+ int c = sizeof(struct sockaddr_in);
+
+ int accept_fd = zts_accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&c);
+
+ printf("reading from buffer\n");
+ char newbuf[32];
+ memset(newbuf, 0, 32);
+ read(accept_fd, newbuf, 20);
+ printf("newbuf = %s\n", newbuf);
+ }
// End Socket API calls
@@ -103,6 +129,13 @@ int main()
printf("peer_count = %lu\n", zts_get_peer_count());
+/*
+ while(1)
+ {
+ sleep(1);
+ }
+*/
+
// ---
/*
diff --git a/tests/socket/client.cpp b/tests/socket/client.cpp
deleted file mode 100644
index e69de29..0000000