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