spring cleaning

This commit is contained in:
Joseph Henry
2017-04-14 17:23:28 -07:00
parent 3052f55d12
commit c65b609fb4
26 changed files with 1539 additions and 1330 deletions

View File

@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
/*
* 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;
}
/**
* 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

View File

@@ -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)

View File

@@ -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,16 +107,11 @@ 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 \
SDK_OBJS+= SocketTap.o \
picoTCP.o \
SDKService.o
ZeroTierSDK.o
PICO_OBJS+= ext/picotcp/build/lib/pico_device.o \
ext/picotcp/build/lib/pico_frame.o \
@@ -120,6 +124,8 @@ 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)

73
src/Connection.hpp Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef ZT_CONNECTION_HPP
#define ZT_CONNECTION_HPP
#include <sys/socket.h>
#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<Connection*> _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

345
src/RPC.c
View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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 <sys/syscall.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdint.h>
#include <strings.h>
#include <stdlib.h>
#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(&timestamp));
#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], &timestring, 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

144
src/RPC.h
View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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 <sys/socket.h>
#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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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 <algorithm>
@@ -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<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (i == _ips.end())
@@ -177,6 +140,7 @@ std::vector<InetAddress> 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<PhySocket*, void*> 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<PhySocket*, void*>(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);
DEBUG_INFO();
Connection *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;
if(len) {
conn->txsz += len;
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;
}
/****************************************************************************/
/* SDK Socket API */
/****************************************************************************/
int SocketTap::Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) {
Mutex::Lock _l(_tcpconns_m);
closeConnection(sockdata.first); // close RPC after sending retval, no longer needed
jobmap.erase(CANARY_num);
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){
@@ -467,41 +327,10 @@ 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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <queue>
#include <utility>
#include <stdexcept>
#include <stdint.h>
@@ -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"
*/
@@ -160,17 +129,6 @@ namespace ZeroTier {
*/
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &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<Connection*> _Connections;
std::map<uint64_t, std::pair<PhySocket*, void*> > jobmap;
pid_t rpcCounter;
Thread _thread;
std::string _dev; // path to Unix domain socket
std::vector<MulticastGroup> _multicastGroups;
Mutex _multicastGroups_m;
Mutex _ips_m, _tcpconns_m, _rx_buf_m, _close_m;
};
} // namespace ZeroTier

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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 <dlfcn.h>
@@ -53,10 +44,16 @@ extern "C" {
static ZeroTier::OneService *zt1Service;
std::string localHomeDir; // Local shortened path
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<int, Connection*> UnassignedConnections;
std::map<int, std::pair<Connection*,SocketTap*>*> 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<int, Connection*> 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)
// set up Unix Domain socketpair (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;
}
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<ZeroTier::Connection*,ZeroTier::SocketTap*>(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;
_multiplexer_lock.unlock();
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);
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<ZeroTier::Connection*,ZeroTier::SocketTap*>(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<std::string> hpsp(ZeroTier::OSUtils::split(homeDir.c_str(),
if (ZeroTier::homeDir.length()) {
std::vector<std::string> 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<std::string>::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());
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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,79 +432,20 @@ 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;
if(sz)
@@ -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)
int picoTCP::pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{
if(conn->picosock) {
struct sockaddr_in *addr = (struct sockaddr_in *) &connect_rpc->addr;
int ret;
// TODO: Rewrite this
int err;
#if defined(SDK_IPV4)
struct pico_ip4 zaddr;
struct sockaddr_in *in4 = (struct sockaddr_in*)&connect_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", 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
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);
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
#if defined(SDK_IPV4)
struct pico_ip4 zaddr;
struct sockaddr_in *in4 = (struct sockaddr_in*)&bind_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, 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));
#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)
{
if(ret == PICO_ERR_EINVAL) {
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");
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL);
errno = EINVAL;
return -1;
}
if(ret == PICO_ERR_EISCONN) {
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(err == PICO_ERR_EINVAL) {
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
errno = EINVAL;
return -1;
}
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) {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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);
/*
* 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);
};
}

62
test/dumb/tcpclient4.c Normal file
View File

@@ -0,0 +1,62 @@
// TCP Client test program
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
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 <addr> <port>\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;
}

72
test/dumb/tcpclient6.c Normal file
View File

@@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
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;
}

61
test/dumb/tcpserver4.c Normal file
View File

@@ -0,0 +1,61 @@
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int atoi(const char *str);
int main(int argc , char *argv[])
{
if(argc < 2) {
printf("usage: tcp_server <port>\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<bytes_read; i++) {
printf("%c", client_message[i]);
}
// TX
int bytes_written = write(client_sock, "Server here!", 12);
printf("\t\nTX = %d\n", bytes_written);
}
return 0;
}

83
test/dumb/tcpserver6.c Normal file
View File

@@ -0,0 +1,83 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
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;
}

88
test/dumb/udpclient4.c Executable file
View File

@@ -0,0 +1,88 @@
/*
* udpclient.c - A simple UDP client
* usage: udpclient <host> <port>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#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 <hostname> <port>\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;
}

43
test/dumb/udpclient6.c Executable file
View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#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;
}

86
test/dumb/udpserver4.c Executable file
View File

@@ -0,0 +1,86 @@
// UDP Server test program
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#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 <port>\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);
}

44
test/dumb/udpserver6.c Executable file
View File

@@ -0,0 +1,44 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#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;
}

64
test/unit/client.cpp Normal file
View File

@@ -0,0 +1,64 @@
// Comprehensive stress test for socket-like API
#include <stdio.h>
/****************************************************************************/
/* 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;
}

View File

@@ -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,6 +67,8 @@ int main()
printf("sockfd = %d\n", sockfd);
// connect() IPv6
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));
@@ -74,21 +76,45 @@ int main()
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)
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");
return -1;
}
}
// connect() IPv4
addr.sin_addr.s_addr = inet_addr("10.9.9.4");
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)
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");
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);
}
*/
// ---
/*