significant upgrade to selftest, added echotest, better checks for data in queue before socket closure

This commit is contained in:
Joseph Henry
2017-06-16 16:58:30 -07:00
parent 4403f902a4
commit 195cac6d55
17 changed files with 1038 additions and 658 deletions

View File

@@ -21,13 +21,14 @@ Pre-Built Binaries Here: [zerotier.com/download.shtml](https://zerotier.com/down
char *str = "welcome to the machine"; // test msg char *str = "welcome to the machine"; // test msg
char *nwid = "c7cd7c9e1b0f52a2"; // network to join char *nwid = "c7cd7c9e1b0f52a2"; // network to join
char *pasth = "zt1"; // path where this node's keys and configs will be stored char *path = "zt1"; // path where this node's keys and configs will be stored
char *ip = "10.8.8.42"; // resource on ZeroTier network char *ip = "10.8.8.42"; // host on ZeroTier network
int port = 8080; // resource's port
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip); addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = hton(8080); addr.sin_port = hton(port);
zts_simple_start(path, nwid); zts_simple_start(path, nwid);
int fd = zts_socket(AF_INET, SOCK_STREAM, 0); int fd = zts_socket(AF_INET, SOCK_STREAM, 0);
@@ -42,7 +43,7 @@ Bindings for various [languages](examples)
### Building (linux, macos, bsd, win, ios) ### Building (linux, macos, bsd, win, ios)
All build targets will output to `build/`. Complete instructions [here](BUILDING.md). All targets will output to `build/`. Complete instructions [here](BUILDING.md)
- Static Library (linux, mac, win, bsd): `make static_lib` - Static Library (linux, mac, win, bsd): `make static_lib`
- iOS App Framework: `make ios_app_framework` - iOS App Framework: `make ios_app_framework`

View File

@@ -7,7 +7,11 @@
### 2017-06-30 -- Version 1.1.5 ### 2017-06-30 -- Version 1.1.5
- Improvements in API consistency and coverage - Improvements in API consistency and coverage
- Additional safety checks
- Various bug fixes for socket abstraction layer - Various bug fixes for socket abstraction layer
- Rework of Connection lock scheme
- IPv4 and IPv6 enabled by default
- Performance (RX and TX) upgrades
*** ***

View File

@@ -21,66 +21,59 @@ build
|--darwin |--darwin
| |-libzt.a | |-libzt.a
| |-selftest | |-selftest
| |-echotest
| |
|--linux |--linux
| |-libzt.a
| |-selftest
| |-echotest
|
|--freebsd
| |-libzt.a
| |-selftest
| |-echotest
|
|--win
|-libzt.a |-libzt.a
|-selftest |-selftest
|-echotest
``` ```
### Simple Tests The self test will be performed over the network in the following configuration (addresses and ports are subject to change depending on what you define in your `test/*.conf` files):
![Image](docs/test_diagram.png)
Simple tests merely test one aspect of the library. For instance, its role as an IPv4 server, or IPv6 client. ### Test sets:
To run a single-test IPv4 client/server test: - Test set A: Tests for correctness, error handling, blocking behaviour, on-system performance, etc
- Test set B: Tests RX performance (from non-libzt app)
- Test set C: Tests TX performance (to non-libzt app)
- host-1: `./build/linux/selftest zt1 c7cd7c9e1b0f52a2 simple 4 server 10.9.9.40 8787` ### Types of tests (defined in `selftest.cpp`)
- host-2: `./build/linux/selftest zt2 c7cd7c9e1b0f52a2 simple 4 client 10.9.9.40 8787`
To run a multi-message IPv4 client/server test: #### Simple Tests:
- host-1: `./build/linux/selftest zt1 c7cd7c9e1b0f52a2 simple 4 server 10.9.9.40 8787 n_bytes 100 50` - Simple tests merely test one aspect of the library. For instance, its role as an IPv4 server, or IPv6 client.
- host-2: `./build/linux/selftest zt2 c7cd7c9e1b0f52a2 simple 4 client 10.9.9.40 8787 n_bytes 100 50`
### Sustained Tests #### Sustained Tests
Sustained tests will test the library's ability to support long-duration connections and data transfers. - Sustained tests will test the library's ability to support long-duration connections and data transfers.
- host-1: `./build/linux/selftest sustained test/bob.conf` #### Slam Tests
- host-2: `./build/linux/selftest sustained test/alice.conf`
### Slam Tests - Slam tests will test the library's ability to handle many repeated API calls or repeated common sequences of API calls that a typical application may make. For instance, it will try to create as many sockets as possible, or try to create a socket, bind to an address, listen, and accept over and over. This is useful for detecting memory leaks and architectural limitations in the stack drivers.
Slam tests will test the library's ability to handle many repeated API calls or repeated common sequences of API calls that a typical application may make. For instance, it will try to create as many sockets as possible, or try to create a socket, bind to an address, listen, and accept over and over. This is useful for detecting memory leaks and architectural limitations in the stack drivers. #### Comprehensive Tests
- host-1: `./build/linux/selftest slam test/bob.conf` - A comprehensive test will test each aspect of the library one time.
- host-2: `./build/linux/selftest slam test/alice.conf`
### Comprehensive Tests #### Random Tests
A comprehensive test will test each aspect of the library one time. - Makes random API calls with random (or plausible arguments/data) to test for proper error handling
- host-1: `./build/linux/selftest comprehensive test/bob.conf` #### Performance Tests
- host-2: `./build/linux/selftest comprehensive test/alice.conf`
### Random Tests
Makes random API calls with random (or plausible arguments/data) to test for proper error handling
- host-1: `./build/linux/selftest random test/bob.conf`
### Performance Tests
Test's the library's performance characteristics
- host-1: `./build/linux/selftest performance test/bob.conf`
- host-2: `./build/linux/selftest performance test/alice.conf`
### Correctness Tests
Tests's the library's error handling, address treatment, and blocking/non-blocking behaviour.
- host-1: `./build/linux/selftest correctness test/bob.conf`
- host-2: `./build/linux/selftest correctness test/alice.conf`
- Test's the library's performance characteristics
#### Correctness Tests
- Tests's the library's error handling, address treatment, and blocking/non-blocking behaviour.

BIN
docs/test_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -9,7 +9,7 @@
#include "pico_frame.h" #include "pico_frame.h"
#include "pico_constants.h" #include "pico_constants.h"
#define PICO_MAX_TIMERS 20 #define PICO_MAX_TIMERS 64
#define PICO_ETH_MRU (1514u) #define PICO_ETH_MRU (1514u)
#define PICO_IP_MRU (1500u) #define PICO_IP_MRU (1500u)

View File

@@ -1996,7 +1996,7 @@ int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
return ret; return ret;
if (!IS_BCAST(f)) { if (!IS_BCAST(f)) {
dbg("Socket not found... \n"); DEBUG_EXTRA("Socket not found...");
pico_notify_socket_unreachable(f); pico_notify_socket_unreachable(f);
ret = -1; ret = -1;
pico_err = PICO_ERR_ENOENT; pico_err = PICO_ERR_ENOENT;

View File

@@ -33,6 +33,8 @@
#include "pico_socket.h" #include "pico_socket.h"
#include "heap.h" #include "heap.h"
#include "../../../include/Debug.hpp"
/* Mockables */ /* Mockables */
#if defined UNIT_TEST #if defined UNIT_TEST
# define MOCKABLE __attribute__((weak)) # define MOCKABLE __attribute__((weak))
@@ -831,13 +833,13 @@ pico_timer_ref_add(pico_time expire, struct pico_timer *t, uint32_t id, uint32_t
tref.hash = hash; tref.hash = hash;
if (heap_insert(Timers, &tref) < 0) { if (heap_insert(Timers, &tref) < 0) {
dbg("Error: failed to insert timer(ID %u) into heap\n", id); DEBUG_ERROR("Error: failed to insert timer(ID %u) into heap", id);
PICO_FREE(t); PICO_FREE(t);
pico_err = PICO_ERR_ENOMEM; pico_err = PICO_ERR_ENOMEM;
return 0; return 0;
} }
if (Timers->n > PICO_MAX_TIMERS) { if (Timers->n > PICO_MAX_TIMERS) {
dbg("Warning: I have %d timers\n", (int)Timers->n); DEBUG_ERROR("Warning: I have %d timers", (int)Timers->n);
} }
return tref.id; return tref.id;

View File

@@ -24,21 +24,19 @@
* of your own application. * of your own application.
*/ */
/****************************************************************************/
/* Debug */
/****************************************************************************/
#include <pthread.h> #include <pthread.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/types.h> #include <sys/types.h>
#define ZT_DEBUG_LEVEL 5 // Set this to adjust what you'd like to see in the debug traces #define ZT_DEBUG_LEVEL 6 // Set this to adjust what you'd like to see in the debug traces
#define ZT_MSG_ERROR 1 // Errors #define ZT_MSG_TEST 1 // For use in selftest
#define ZT_MSG_TRANSFER 2 // RX/TX specific statements #define ZT_MSG_ERROR 2 // Errors
#define ZT_MSG_INFO 3 // Information which is generally useful to any developer #define ZT_MSG_INFO 3 // Information which is generally useful to any developer
#define ZT_MSG_EXTRA 4 // If nothing in your world makes sense #define ZT_MSG_EXTRA 4 // If nothing in your world makes sense
#define ZT_MSG_FLOW 5 // High-level flow messages #define ZT_MSG_TRANSFER 5 // RX/TX specific statements
#define ZT_MSG_FLOW 6 // High-level flow messages
#define ZT_COLOR true #define ZT_COLOR true
// Debug output colors // Debug output colors
@@ -87,8 +85,15 @@
#define ZT_LOG_TAG "ZTSDK" #define ZT_LOG_TAG "ZTSDK"
#endif #endif
#if ZT_DEBUG_LEVEL >= ZT_MSG_TEST
#define DEBUG_TEST(fmt, args...) fprintf(stderr, ZT_CYN "ZT_TEST [%d] : %16s:%5d:%25s: " fmt \
"\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#else
#define DEBUG_ERROR(fmt, args...)
#endif
#if ZT_DEBUG_LEVEL >= ZT_MSG_ERROR #if ZT_DEBUG_LEVEL >= ZT_MSG_ERROR
#define DEBUG_ERROR(fmt, args...) fprintf(stderr, ZT_RED "ZT_ERROR[%ld] : %16s:%5d:%25s: " fmt \ #define DEBUG_ERROR(fmt, args...) fprintf(stderr, ZT_RED "ZT_ERROR[%d] : %16s:%5d:%25s: " fmt \
"\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#else #else
#define DEBUG_ERROR(fmt, args...) #define DEBUG_ERROR(fmt, args...)
@@ -106,13 +111,13 @@
"ZT_STACK: %16s:%5d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args)) "ZT_STACK: %16s:%5d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else #else
#define DEBUG_INFO(fmt, args...) fprintf(stderr, \ #define DEBUG_INFO(fmt, args...) fprintf(stderr, \
"ZT_INFO [%ld] : %16s:%5d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) "ZT_INFO [%d] : %16s:%5d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ATTN(fmt, args...) fprintf(stderr, ZT_CYN \ #define DEBUG_ATTN(fmt, args...) fprintf(stderr, ZT_CYN \
"ZT_ATTN [%ld] : %16s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) "ZT_ATTN [%d] : %16s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_STACK(fmt, args...) fprintf(stderr, ZT_YEL \ #define DEBUG_STACK(fmt, args...) fprintf(stderr, ZT_YEL \
"ZT_STACK[%ld] : %16s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) "ZT_STACK[%d] : %16s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#define DEBUG_BLANK(fmt, args...) fprintf(stderr, \ #define DEBUG_BLANK(fmt, args...) fprintf(stderr, \
"ZT_INFO [%ld] : %16s:%5d:" fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, ##args) "ZT_INFO [%d] : %16s:%5d:" fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, ##args)
#endif #endif
#else #else
#define DEBUG_INFO(fmt, args...) #define DEBUG_INFO(fmt, args...)
@@ -139,7 +144,7 @@
"ZT_EXTRA : %16s:%5d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args)) "ZT_EXTRA : %16s:%5d:%25s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
#else #else
#define DEBUG_EXTRA(fmt, args...) fprintf(stderr, \ #define DEBUG_EXTRA(fmt, args...) fprintf(stderr, \
"ZT_EXTRA[%ld] : %16s:%5d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) "ZT_EXTRA[%d] : %16s:%5d:%25s: " fmt "\n", ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#endif #endif
#else #else
#define DEBUG_EXTRA(fmt, args...) #define DEBUG_EXTRA(fmt, args...)

View File

@@ -41,8 +41,8 @@
#define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128 #define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128
#define ZT_TCP_TX_BUF_SZ 1024 * 1024 #define ZT_TCP_TX_BUF_SZ 1024 * 1024 * 5
#define ZT_TCP_RX_BUF_SZ 1024 * 1024 #define ZT_TCP_RX_BUF_SZ 1024 * 1024 * 5
#define ZT_UDP_TX_BUF_SZ ZT_MAX_MTU #define ZT_UDP_TX_BUF_SZ ZT_MAX_MTU
#define ZT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10 #define ZT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10
@@ -50,11 +50,11 @@
#define ZT_CORE_VERSION_MAJOR 1 #define ZT_CORE_VERSION_MAJOR 1
#define ZT_CORE_VERSION_MINOR 2 #define ZT_CORE_VERSION_MINOR 2
#define ZT_CORE_VERSION_REVISION 4 #define ZT_CORE_VERSION_REVISION 5
#define ZT_SDK_VERSION_MAJOR 1 #define ZT_LIB_VERSION_MAJOR 1
#define ZT_SDK_VERSION_MINOR 0 #define ZT_LIB_VERSION_MINOR 1
#define ZT_SDK_VERSION_REVISION 0 #define ZT_LIB_VERSION_REVISION 4
#define ZT_MAX_IPADDR_LEN 64 #define ZT_MAX_IPADDR_LEN 64
#define ZT_ID_LEN 10 #define ZT_ID_LEN 10
@@ -77,6 +77,9 @@
#define ZT_SOCK_BEHAVIOR_LINGER true #define ZT_SOCK_BEHAVIOR_LINGER true
#define ZT_SOCK_BEHAVIOR_LINGER_TIME 3 // s #define ZT_SOCK_BEHAVIOR_LINGER_TIME 3 // s
// Wait time for socket closure if data is still present in the write queue
#define ZT_SDK_CLTIME 60
// After closing a pico_socket, other threads might still try to use the // After closing a pico_socket, other threads might still try to use the
// Connection object for remaining data I/O, as a safety measure we will wait to // Connection object for remaining data I/O, as a safety measure we will wait to
// delete this Connection object until the socket has been closed for some arbitrary // delete this Connection object until the socket has been closed for some arbitrary
@@ -115,7 +118,7 @@
/****************************************************************************/ /****************************************************************************/
/* SDK Socket API (ZeroTier Service Controls) */ /* SDK Socket API (ZeroTier Service Controls) */
/* Implemented in SDKService.cpp */ /* Implemented in libzt.cpp */
/****************************************************************************/ /****************************************************************************/
#ifdef __cplusplus #ifdef __cplusplus
@@ -169,9 +172,9 @@ void zts_get_homepath(char *homePath, const int len);
void zts_core_version(char *ver); void zts_core_version(char *ver);
/** /**
* Provides core SDK service version * Provides core libzt service version
*/ */
void zts_sdk_version(char *ver); void zts_lib_version(char *ver);
/** /**
* Get device ID * Get device ID

View File

@@ -80,6 +80,7 @@ INCLUDES+= -Iext \
-I$(ZTO)/node \ -I$(ZTO)/node \
-I$(ZTO)/service \ -I$(ZTO)/service \
-I$(ZTO)/include \ -I$(ZTO)/include \
-I$(ZTO)/controller \
-I../$(ZTO)/osdep \ -I../$(ZTO)/osdep \
-I../$(ZTO)/node \ -I../$(ZTO)/node \
-I../$(ZTO)/service \ -I../$(ZTO)/service \
@@ -192,7 +193,7 @@ UNIT_TEST_LIBS := -L$(BUILD) -lzt $(COMMON_LIBS)
$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp $(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp
@mkdir -p $(TEST_BUILD_DIR) @mkdir -p $(TEST_BUILD_DIR)
@-$(CXX) $(UNIT_TEST_INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) @-$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS)
@-./check.sh $@ @-./check.sh $@
unit_tests: $(UNIT_TEST_OBJ_FILES) unit_tests: $(UNIT_TEST_OBJ_FILES)

View File

@@ -39,7 +39,6 @@
// SDK // SDK
#include "libzt.h" #include "libzt.h"
#include "SocketTap.hpp" #include "SocketTap.hpp"
//#include "RingBuffer.hpp"
namespace ZeroTier { namespace ZeroTier {
@@ -48,8 +47,7 @@ namespace ZeroTier {
*/ */
struct Connection struct Connection
{ {
//circular_buffer<char> crbuf = circular_buffer<char>(ZT_TCP_RX_BUF_SZ); Mutex _tx_m, _rx_m;
//circular_buffer<char> ctbuf = circular_buffer<char>(ZT_TCP_TX_BUF_SZ);
int pid; int pid;
PhySocket *sock; PhySocket *sock;
@@ -79,7 +77,6 @@ namespace ZeroTier {
Connection() { Connection() {
closure_ts = -1; closure_ts = -1;
// DEBUG_INFO("Connection() this = %p", this);
ZT_PHY_SOCKFD_TYPE fdpair[2]; ZT_PHY_SOCKFD_TYPE fdpair[2];
if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fdpair) < 0) { if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fdpair) < 0) {
if(errno < 0) { if(errno < 0) {

View File

@@ -27,13 +27,10 @@
// picoTCP // picoTCP
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <dlfcn.h>
#include <sys/poll.h> #include <sys/poll.h>
#include <stdint.h> #include <stdint.h>
#include <utility> #include <utility>
#include <string> #include <string>
#include <sys/resource.h>
#include <sys/syscall.h>
// SDK // SDK
#include "SocketTap.hpp" #include "SocketTap.hpp"

View File

@@ -24,8 +24,14 @@
* of your own application. * of your own application.
*/ */
#include <dlfcn.h>
/* This file implements the libzt library API, it talks to the network
stack driver and core ZeroTier service to create a socket-like interface
for applications to use. See also: include/libzt.h */
#include <sys/socket.h> #include <sys/socket.h>
//#include <sys/ioctl.h>
//#include <stropts.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -165,8 +171,8 @@ void zts_core_version(char *ver) {
sprintf(ver, "%d.%d.%d", major, minor, revision); sprintf(ver, "%d.%d.%d", major, minor, revision);
} }
void zts_sdk_version(char *ver) { void zts_lib_version(char *ver) {
sprintf(ver, "%d.%d.%d", ZT_SDK_VERSION_MAJOR, ZT_SDK_VERSION_MINOR, ZT_SDK_VERSION_REVISION); sprintf(ver, "%d.%d.%d", ZT_LIB_VERSION_MAJOR, ZT_LIB_VERSION_MINOR, ZT_LIB_VERSION_REVISION);
} }
int zts_get_device_id(char *devID) { int zts_get_device_id(char *devID) {
@@ -314,11 +320,11 @@ void zts_disable_http_control_plane()
/* /*
socket fd = 0 (nwid=X)---\ /--- SocketTap=A // e.x. 172.27.0.0/? socket fd = 0 (nwid=X)---\ /--- SocketTap=A // e.x. 172.27.0.0 / 16
\ / \ /
socket fd = 1 (nwid=Y)--------Multiplexed z* calls-------- SocketTap=B // e.x. 192.168.0.1/16 socket fd = 1 (nwid=Y)--------Multiplexed z* calls-------- SocketTap=B // e.x. 192.168.0.1 / 16
/ \ / \
socket fd = 2 (nwid=Z)---/ \--- SocketTap=C // e.x. 10.9.9.0/24 socket fd = 2 (nwid=Z)---/ \--- SocketTap=C // e.x. 10.9.9.0 / 24
*/ */
@@ -332,22 +338,26 @@ Darwin:
[NA] [ENFILE] The system file table is full. [NA] [ENFILE] The system file table is full.
[ ] [ENOBUFS] Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed. [ ] [ENOBUFS] Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed.
[ ] [ENOMEM] Insufficient memory was available to fulfill the request. [ ] [ENOMEM] Insufficient memory was available to fulfill the request.
[ ] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain. [--] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain.
[ ] [EPROTOTYPE] The socket type is not supported by the protocol. [ ] [EPROTOTYPE] The socket type is not supported by the protocol.
*/ */
// int socket_family, int socket_type, int protocol // int socket_family, int socket_type, int protocol
int zts_socket(ZT_SOCKET_SIG) { int zts_socket(ZT_SOCKET_SIG) {
DEBUG_INFO();
int err = 0; int err = 0;
if(!zt1Service) { if(!zt1Service) {
DEBUG_ERROR("cannot create socket, no service running. call zts_start() first."); DEBUG_ERROR("cannot create socket, no service running. call zts_start() first.");
errno = EMFILE; // could also be ENFILE errno = EMFILE; // could also be ENFILE
err = -1; return -1;
} }
else { if(socket_type == SOCK_SEQPACKET) {
DEBUG_ERROR("SOCK_SEQPACKET not yet supported.");
errno = EPROTONOSUPPORT; // seemingly closest match
return -1;
}
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
//DEBUG_INFO("unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
//DEBUG_INFO("timers = %d, max = %d", pico_ntimers(), PICO_MAX_TIMERS);
if(pico_ntimers() >= PICO_MAX_TIMERS) { if(pico_ntimers() >= PICO_MAX_TIMERS) {
DEBUG_ERROR("cannot provision additional socket due to limitation of PICO_MAX_TIMERS. current = %d", pico_ntimers()); DEBUG_ERROR("cannot provision additional socket due to limitation of PICO_MAX_TIMERS. current = %d", pico_ntimers());
errno = EMFILE; errno = EMFILE;
@@ -359,19 +369,10 @@ int zts_socket(ZT_SOCKET_SIG) {
int protocol_version = 0; int protocol_version = 0;
struct pico_socket *psock; struct pico_socket *psock;
// TODO: check ifdef logic here if(socket_family == AF_INET)
//#if defined(SDK_IPV4)
if(socket_family == AF_INET){
// DEBUG_ERROR("AF_INET");
protocol_version = PICO_PROTO_IPV4; protocol_version = PICO_PROTO_IPV4;
} if(socket_family == AF_INET6)
//#endif
//#if defined(SDK_IPV6)
if(socket_family == AF_INET6) {
// DEBUG_ERROR("AF_INET6");
protocol_version = PICO_PROTO_IPV6; protocol_version = PICO_PROTO_IPV6;
}
//#endif
if(socket_type == SOCK_DGRAM) { if(socket_type == SOCK_DGRAM) {
psock = pico_socket_open( psock = pico_socket_open(
@@ -395,9 +396,7 @@ int zts_socket(ZT_SOCKET_SIG) {
err = -1; err = -1;
} }
} }
//DEBUG_INFO(" unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
ZeroTier::_multiplexer_lock.unlock(); ZeroTier::_multiplexer_lock.unlock();
}
return err; return err;
} }
@@ -415,7 +414,8 @@ Darwin:
[ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for connections) or explicitly rejected. [ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for connections) or explicitly rejected.
[ ] [EFAULT] The address parameter specifies an area outside the process address space. [ ] [EFAULT] The address parameter specifies an area outside the process address space.
[ ] [EHOSTUNREACH] The target host cannot be reached (e.g., down, disconnected). [ ] [EHOSTUNREACH] The target host cannot be reached (e.g., down, disconnected).
[--] [EINPROGRESS] The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) for completion by selecting the socket for writing. [--] [EINPROGRESS] The socket is non-blocking and the connection cannot be completed immediately.
It is possible to select(2) for completion by selecting the socket for writing.
[NA] [EINTR] Its execution was interrupted by a signal. [NA] [EINTR] Its execution was interrupted by a signal.
[ ] [EINVAL] An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid). [ ] [EINVAL] An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
[ ] [EISCONN] The socket is already connected. [ ] [EISCONN] The socket is already connected.
@@ -427,9 +427,35 @@ Darwin:
[ ] [EPROTOTYPE] address has a different type than the socket that is bound to the specified peer address. [ ] [EPROTOTYPE] address has a different type than the socket that is bound to the specified peer address.
[ ] [ETIMEDOUT] Connection establishment timed out without establishing a connection. [ ] [ETIMEDOUT] Connection establishment timed out without establishing a connection.
[ ] [ECONNRESET] Remote host reset the connection request. [ ] [ECONNRESET] Remote host reset the connection request.
Linux:
[ ] [EACCES] For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket file,
or search permission is denied for one of the directories in the path prefix. (See also path_resolution(7).)
[ ] [EACCES, EPERM] The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the
connection request failed because of a local firewall rule.
[ ] [EADDRINUSE] Local address is already in use.
[ ] [EAFNOSUPPORT] The passed address didn't have the correct address family in its sa_family field.
[ ] [EAGAIN] No more free local ports or insufficient entries in the routing cache. For AF_INET see the description
of /proc/sys/net/ipv4/ip_local_port_range ip(7) for information on how to increase the number of local ports.
[ ] [EALREADY] The socket is nonblocking and a previous connection attempt has not yet been completed.
[ ] [EBADF] The file descriptor is not a valid index in the descriptor table.
[ ] [ECONNREFUSED] No-one listening on the remote address.
[ ] [EFAULT] The socket structure address is outside the user's address space.
[ ] [EINPROGRESS] The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or
poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2)
to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero)
or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
[ ] [EINTR] The system call was interrupted by a signal that was caught; see signal(7).
[ ] [EISCONN] The socket is already connected.
[ ] [ENETUNREACH] Network is unreachable.
[ ] [ENOTSOCK] The file descriptor is not associated with a socket.
[ ] [ETIMEDOUT] Timeout while attempting connection. The server may be too busy to accept new connections. Note that for
IP sockets the timeout may be very long when syncookies are enabled on the server.
*/ */
int zts_connect(ZT_CONNECT_SIG) { int zts_connect(ZT_CONNECT_SIG) {
// DEBUG_INFO("fd = %d", fd); DEBUG_INFO("fd = %d", fd);
int err = 0; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
@@ -566,16 +592,16 @@ Darwin:
address space. address space.
*/ */
int zts_bind(ZT_BIND_SIG) { int zts_bind(ZT_BIND_SIG) {
//DEBUG_EXTRA("fd = %d", fd); DEBUG_EXTRA("fd = %d", fd);
int err = 0; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; return -1;
} }
if(!zt1Service) { if(!zt1Service) {
DEBUG_ERROR("Service not started. Call zts_start(path) first"); DEBUG_ERROR("Service not started. Call zts_start(path) first");
errno = EBADF; errno = EBADF;
err = -1; return -1;
} }
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::unmap[fd]; ZeroTier::Connection *conn = ZeroTier::unmap[fd];
@@ -618,7 +644,6 @@ int zts_bind(ZT_BIND_SIG) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
} }
ZeroTier::_multiplexer_lock.unlock(); ZeroTier::_multiplexer_lock.unlock();
return err; return err;
} }
@@ -629,17 +654,24 @@ Darwin:
[--] [EACCES] The current process has insufficient privileges. [--] [EACCES] The current process has insufficient privileges.
[--] [EBADF] The argument socket is not a valid file descriptor. [--] [EBADF] The argument socket is not a valid file descriptor.
[ ] [EDESTADDRREQ] The socket is not bound to a local address and the protocol does not support listening on an unbound socket. [--] [EDESTADDRREQ] The socket is not bound to a local address and the protocol does not support listening on an unbound socket.
[ ] [EINVAL] socket is already connected. [ ] [EINVAL] socket is already connected.
[ ] [ENOTSOCK] The argument socket does not reference a socket. [ ] [ENOTSOCK] The argument socket does not reference a socket.
[ ] [EOPNOTSUPP] The socket is not of a type that supports the operation listen(). [ ] [EOPNOTSUPP] The socket is not of a type that supports the operation listen().
Linux:
[ ] [EADDRINUSE] Another socket is already listening on the same port.
[--] [EBADF] The argument sockfd is not a valid descriptor.
[ ] [ENOTSOCK] The argument sockfd is not a socket.
[ ] [EOPNOTSUPP] The socket is not of a type that supports the listen() operation.
*/ */
int zts_listen(ZT_LISTEN_SIG) { int zts_listen(ZT_LISTEN_SIG) {
DEBUG_EXTRA("fd = %d", fd); DEBUG_EXTRA("fd = %d", fd);
int err = 0; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; return -1;
} }
if(!zt1Service) { if(!zt1Service) {
DEBUG_ERROR("service not started. call zts_start(path) first"); DEBUG_ERROR("service not started. call zts_start(path) first");
@@ -650,18 +682,21 @@ int zts_listen(ZT_LISTEN_SIG) {
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd]; std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
if(!p) { if(!p) {
DEBUG_ERROR("unable to locate connection pair. did you bind?"); DEBUG_ERROR("unable to locate connection pair. did you bind?");
errno = EDESTADDRREQ;
return -1; return -1;
} }
ZeroTier::Connection *conn = p->first; ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second; ZeroTier::SocketTap *tap = p->second;
if(!tap || !conn) { if(!tap || !conn) {
DEBUG_ERROR("unable to locate tap interface for file descriptor"); DEBUG_ERROR("unable to locate tap interface for file descriptor");
errno = EBADF;
return -1; return -1;
} }
if(!err) {
backlog = backlog > 128 ? 128 : backlog; // See: /proc/sys/net/core/somaxconn
err = tap->Listen(conn, fd, backlog); err = tap->Listen(conn, fd, backlog);
//DEBUG_INFO("put conn=%p into LISTENING state (err=%d)", conn, err);
ZeroTier::_multiplexer_lock.unlock(); ZeroTier::_multiplexer_lock.unlock();
}
return err; return err;
} }
@@ -684,7 +719,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
int err = 0; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; return -1;
} }
else else
{ {
@@ -704,7 +739,6 @@ int zts_accept(ZT_ACCEPT_SIG) {
else { else {
ZeroTier::Connection *conn = p->first; ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second; ZeroTier::SocketTap *tap = p->second;
ZeroTier::Connection *accepted_conn;
// BLOCKING: loop and keep checking until we find a newly accepted connection // BLOCKING: loop and keep checking until we find a newly accepted connection
int f_err, blocking = 1; int f_err, blocking = 1;
@@ -715,15 +749,16 @@ int zts_accept(ZT_ACCEPT_SIG) {
else { else {
blocking = !(f_err & O_NONBLOCK); blocking = !(f_err & O_NONBLOCK);
} }
if(!err && !blocking) { // non-blocking if(!err) {
ZeroTier::Connection *accepted_conn;
if(!blocking) { // non-blocking
DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode"); DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode");
errno = EWOULDBLOCK; errno = EWOULDBLOCK;
err = -1; err = -1;
accepted_conn = tap->Accept(conn); accepted_conn = tap->Accept(conn);
} }
else if (!err && blocking) { // blocking else { // blocking
while(true) { while(true) {
DEBUG_EXTRA("checking...");
usleep(ZT_ACCEPT_RECHECK_DELAY * 1000); usleep(ZT_ACCEPT_RECHECK_DELAY * 1000);
accepted_conn = tap->Accept(conn); accepted_conn = tap->Accept(conn);
if(accepted_conn) if(accepted_conn)
@@ -735,6 +770,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
err = accepted_conn->app_fd; err = accepted_conn->app_fd;
} }
} }
}
ZeroTier::_multiplexer_lock.unlock(); ZeroTier::_multiplexer_lock.unlock();
} }
return err; return err;
@@ -745,19 +781,19 @@ int zts_accept(ZT_ACCEPT_SIG) {
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH. Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.
Errors Errors
[ ] EAGAIN or EWOULDBLOCK The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities. [ ] [EAGAIN or EWOULDBLOCK] The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
[--] EBADF The descriptor is invalid. [--] [EBADF] The descriptor is invalid.
[ ] ECONNABORTED A connection has been aborted. [ ] [ECONNABORTED] A connection has been aborted.
[ ] EFAULT The addr argument is not in a writable part of the user address space. [ ] [EFAULT] The addr argument is not in a writable part of the user address space.
[NA] EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7). [NA] [EINTR] The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).
[ ] EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative). [ ] [EINVAL] Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
[ ] EINVAL (accept4()) invalid value in flags. [ ] [EINVAL] (accept4()) invalid value in flags.
[ ] EMFILE The per-process limit of open file descriptors has been reached. [ ] [EMFILE] The per-process limit of open file descriptors has been reached.
[ ] ENFILE The system limit on the total number of open files has been reached. [ ] [ENFILE] The system limit on the total number of open files has been reached.
[ ] ENOBUFS, ENOMEM Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory. [ ] [ENOBUFS, ENOMEM] Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory.
[ ] ENOTSOCK The descriptor references a file, not a socket. [ ] [ENOTSOCK] The descriptor references a file, not a socket.
[ ] EOPNOTSUPP The referenced socket is not of type SOCK_STREAM. [ ] [EOPNOTSUPP] The referenced socket is not of type SOCK_STREAM.
[ ] EPROTO Protocol error. [ ] [EPROTO] Protocol error.
In addition, Linux accept() may fail if: In addition, Linux accept() may fail if:
@@ -870,7 +906,7 @@ Linux:
See: http://yarchive.net/comp/linux/close_return_value.html See: http://yarchive.net/comp/linux/close_return_value.html
Darwin: Linux / Darwin:
[--] [EBADF] fildes is not a valid, active file descriptor. [--] [EBADF] fildes is not a valid, active file descriptor.
[NA] [EINTR] Its execution was interrupted by a signal. [NA] [EINTR] Its execution was interrupted by a signal.
@@ -881,7 +917,7 @@ Darwin:
int zts_close(ZT_CLOSE_SIG) int zts_close(ZT_CLOSE_SIG)
{ {
//DEBUG_EXTRA("fd = %d", fd); DEBUG_EXTRA("fd = %d", fd);
int err = 0; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
@@ -898,7 +934,6 @@ int zts_close(ZT_CLOSE_SIG)
{ {
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
//DEBUG_INFO("unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size()); //DEBUG_INFO("unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
// First, look for for unassigned connections // First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd]; ZeroTier::Connection *conn = ZeroTier::unmap[fd];
@@ -925,31 +960,44 @@ int zts_close(ZT_CLOSE_SIG)
errno = EBADF; errno = EBADF;
err = -1; err = -1;
} }
else else // found everything, begin closure
{ {
conn = p->first; conn = p->first;
ZeroTier::SocketTap *tap = p->second; ZeroTier::SocketTap *tap = p->second;
//DEBUG_ERROR("close...., conn = %p, fd = %d", conn, fd); // check if socket is blocking
int f_err, blocking = 1;
if ((f_err = fcntl(fd, F_GETFL, 0)) < 0) {
DEBUG_ERROR("fcntl error, err = %s, errno = %d", f_err, errno);
err = -1;
}
else {
blocking = !(f_err & O_NONBLOCK);
}
if(blocking) {
DEBUG_INFO("socket is blocking, waiting for write operations before closure");
for(int i=0; i<ZT_SDK_CLTIME; i++) {
if(conn->txsz == 0)
break;
sleep(1);
}
}
// For cases where data might still need to pass through the library // For cases where data might still need to pass through the library
// before socket closure // before socket closure
if(ZT_SOCK_BEHAVIOR_LINGER) { if(ZT_SOCK_BEHAVIOR_LINGER) {
socklen_t optlen; socklen_t optlen;
struct linger so_linger; struct linger so_linger;
so_linger.l_linger = 0;
zts_getsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, &optlen); zts_getsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, &optlen);
if (so_linger.l_linger != 0) { if (so_linger.l_linger != 0) {
DEBUG_EXTRA("lingering before closure for (%d) seconds...", so_linger.l_linger);
sleep(so_linger.l_linger); // do the linger! sleep(so_linger.l_linger); // do the linger!
} }
} }
// Tell the tap to stop monitoring this PhySocket
//if((err = pico_socket_close(conn->picosock)) < 0)
// DEBUG_ERROR("error calling pico_socket_close()");
tap->Close(conn); tap->Close(conn);
// delete objects
// FIXME: double check this
//delete p;
ZeroTier::fdmap.erase(fd); ZeroTier::fdmap.erase(fd);
err = 0; err = 0;
} }
@@ -964,7 +1012,7 @@ int zts_close(ZT_CLOSE_SIG)
int zts_fcntl(ZT_FCNTL_SIG) int zts_fcntl(ZT_FCNTL_SIG)
{ {
//DEBUG_INFO("fd = %d", fd); //DEBUG_INFO("fd = %d", fd);
int err; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
@@ -979,7 +1027,7 @@ int zts_fcntl(ZT_FCNTL_SIG)
ssize_t zts_sendto(ZT_SENDTO_SIG) ssize_t zts_sendto(ZT_SENDTO_SIG)
{ {
DEBUG_INFO("fd = %d", fd); DEBUG_INFO("fd = %d", fd);
int err; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
@@ -994,7 +1042,7 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
ssize_t zts_sendmsg(ZT_SENDMSG_SIG) ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
{ {
DEBUG_INFO("fd = %d", fd); DEBUG_INFO("fd = %d", fd);
int err; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
@@ -1009,7 +1057,7 @@ ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
ssize_t zts_recvfrom(ZT_RECVFROM_SIG) ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
{ {
DEBUG_INFO("fd = %d", fd); DEBUG_INFO("fd = %d", fd);
int err; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
@@ -1024,7 +1072,7 @@ ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
ssize_t zts_recvmsg(ZT_RECVMSG_SIG) ssize_t zts_recvmsg(ZT_RECVMSG_SIG)
{ {
DEBUG_INFO("fd = %d", fd); DEBUG_INFO("fd = %d", fd);
int err; int err = 0;
if(fd < 0) { if(fd < 0) {
errno = EBADF; errno = EBADF;
err = -1; err = -1;
@@ -1353,10 +1401,10 @@ void *zts_start_service(void *thread_id) {
return NULL; return NULL;
} }
// rpc dir // rpc dir
if(!ZeroTier::OSUtils::mkdir(ZeroTier::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); // DEBUG_ERROR("unable to create dir: " ZT_SDK_RPC_DIR_PREFIX);
return NULL; // return NULL;
} //}
// Generate random port for new service instance // Generate random port for new service instance
unsigned int randp = 0; unsigned int randp = 0;

View File

@@ -175,6 +175,7 @@ namespace ZeroTier {
{ {
DEBUG_INFO(); DEBUG_INFO();
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
Mutex::Lock _l(conn->_rx_m);
if(conn) { if(conn) {
uint16_t port = 0; uint16_t port = 0;
@@ -229,6 +230,7 @@ namespace ZeroTier {
{ {
//DEBUG_INFO(); //DEBUG_INFO();
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
Mutex::Lock _l(conn->_tx_m);
if(!conn) { if(!conn) {
DEBUG_ERROR("invalid connection"); DEBUG_ERROR("invalid connection");
return; return;
@@ -248,18 +250,17 @@ namespace ZeroTier {
if(sz) if(sz)
memmove(&conn->txbuf, (conn->txbuf+r), sz); memmove(&conn->txbuf, (conn->txbuf+r), sz);
conn->txsz -= r; conn->txsz -= r;
//DEBUG_INFO("conn->txsz = %d, r = %d, sz = %d", conn->txsz, r, sz);
#if DEBUG_LEVEL >= MSG_TRANSFER #if DEBUG_LEVEL >= MSG_TRANSFER
int max = conn->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_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 -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r);
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
#endif #endif
} }
} }
void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s) void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s)
{ {
//DEBUG_INFO();
if(!(SocketTap*)((ConnectionPair*)(s->priv))) if(!(SocketTap*)((ConnectionPair*)(s->priv)))
return; return;
SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap; SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap;
@@ -268,18 +269,19 @@ namespace ZeroTier {
DEBUG_ERROR("invalid tap or conn"); DEBUG_ERROR("invalid tap or conn");
return; return;
} }
int err = 0;
int err;
Mutex::Lock _l(tap->_tcpconns_m);
if(!conn) { if(!conn) {
DEBUG_ERROR("invalid connection"); DEBUG_ERROR("invalid connection");
return;
} }
//DEBUG_INFO("conn = %p", conn); // PICO_SOCK_EV_CONN - triggered when connection is established (TCP only). This event is
//DEBUG_ERROR(" STATE = %d", conn->picosock->state); // received either after a successful call to pico socket connect to indicate that the connection
// accept() // has been established, or on a listening socket, indicating that a call to pico socket accept
// may now be issued in order to accept the incoming connection from a remote host.
if (ev & PICO_SOCK_EV_CONN) { if (ev & PICO_SOCK_EV_CONN) {
if(conn->state == ZT_SOCK_STATE_LISTENING) if(conn->state == ZT_SOCK_STATE_LISTENING)
{ {
Mutex::Lock _l(tap->_tcpconns_m);
uint32_t peer; uint32_t peer;
uint16_t port; uint16_t port;
struct pico_socket *client_psock = pico_socket_accept(s, &peer, &port); struct pico_socket *client_psock = pico_socket_accept(s, &peer, &port);
@@ -311,34 +313,47 @@ namespace ZeroTier {
conn->state = ZT_SOCK_STATE_UNHANDLED_CONNECTED; conn->state = ZT_SOCK_STATE_UNHANDLED_CONNECTED;
} }
} }
// PICO_SOCK_EV_FIN - triggered when the socket is closed. No further communication is
// possible from this point on the socket.
if (ev & PICO_SOCK_EV_FIN) { if (ev & PICO_SOCK_EV_FIN) {
// DEBUG_EXTRA("PICO_SOCK_EV_FIN (socket closed), picosock=%p, conn=%p", s, conn); // DEBUG_EXTRA("PICO_SOCK_EV_FIN (socket closed), picosock=%p, conn=%p", s, conn);
conn->closure_ts = std::time(nullptr); conn->closure_ts = std::time(nullptr);
} }
// PICO_SOCK_EV_ERR - triggered when an error occurs.
if (ev & PICO_SOCK_EV_ERR) { if (ev & PICO_SOCK_EV_ERR) {
if(pico_err == PICO_ERR_ECONNRESET) { if(pico_err == PICO_ERR_ECONNRESET) {
DEBUG_ERROR("PICO_ERR_ECONNRESET"); DEBUG_ERROR("PICO_ERR_ECONNRESET");
conn->state = PICO_ERR_ECONNRESET; conn->state = PICO_ERR_ECONNRESET;
} }
//DEBUG_INFO("PICO_SOCK_EV_ERR (socket error received) err=%d, picosock=%p", pico_err, s); // DEBUG_INFO("PICO_SOCK_EV_ERR (socket error received) err=%d, picosock=%p", pico_err, s);
} }
// PICO_SOCK_EV_CLOSE - triggered when a FIN segment is received (TCP only). This event
// indicates that the oher endpont has closed the connection, so the local TCP layer is only
// allowed to send new data until a local shutdown or close is initiated. PicoTCP is able to
// keep the connection half-open (only for sending) after the FIN packet has been received,
// allowing new data to be sent in the TCP CLOSE WAIT state.
if (ev & PICO_SOCK_EV_CLOSE) { if (ev & PICO_SOCK_EV_CLOSE) {
err = pico_socket_close(s); err = pico_socket_close(s);
//DEBUG_INFO("PICO_SOCK_EV_CLOSE (socket closure) err = %d, picosock=%p, conn=%p", err, s, conn); // DEBUG_INFO("PICO_SOCK_EV_CLOSE (socket closure) err = %d, picosock=%p, conn=%p", err, s, conn);
conn->closure_ts = std::time(nullptr); conn->closure_ts = std::time(nullptr);
return; return;
} }
// Read from picoTCP socket // PICO_SOCK_EV_RD - triggered when new data arrives on the socket. A new receive action
// can be taken by the socket owner because this event indicates there is new data to receive.
if (ev & PICO_SOCK_EV_RD) { if (ev & PICO_SOCK_EV_RD) {
if(conn->socket_type==SOCK_STREAM) if(conn->socket_type==SOCK_STREAM)
pico_cb_tcp_read(tap, s); pico_cb_tcp_read(tap, s);
if(conn->socket_type==SOCK_DGRAM) if(conn->socket_type==SOCK_DGRAM)
pico_cb_udp_read(tap, s); pico_cb_udp_read(tap, s);
} }
// Write to picoTCP socket // PICO_SOCK_EV_WR - triggered when ready to write to the socket. Issuing a write/send call
if (ev & PICO_SOCK_EV_WR) // will now succeed if the buffer has enough space to allocate new outstanding data
if (ev & PICO_SOCK_EV_WR) {
pico_cb_tcp_write(tap, s); pico_cb_tcp_write(tap, s);
} }
}
int pico_eth_send(struct pico_device *dev, void *buf, int len) int pico_eth_send(struct pico_device *dev, void *buf, int len)
{ {
@@ -362,7 +377,7 @@ namespace ZeroTier {
void picoTCP::pico_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType, void picoTCP::pico_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len) const void *data,unsigned int len)
{ {
DEBUG_INFO("len = %d", len); //DEBUG_INFO("len = %d", len);
if(!tap) { if(!tap) {
DEBUG_ERROR("invalid tap"); DEBUG_ERROR("invalid tap");
return; return;
@@ -405,7 +420,7 @@ namespace ZeroTier {
Mutex::Lock _l(tap->_pico_frame_rxbuf_m); Mutex::Lock _l(tap->_pico_frame_rxbuf_m);
unsigned char frame[ZT_SDK_MTU]; unsigned char frame[ZT_SDK_MTU];
int len; int len;
int err; int err = 0;
while (tap->pico_frame_rxbuf_tot > 0 && loop_score > 0) { while (tap->pico_frame_rxbuf_tot > 0 && loop_score > 0) {
//DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", tap->pico_frame_rxbuf_tot); //DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", tap->pico_frame_rxbuf_tot);
memset(frame, 0, sizeof(frame)); memset(frame, 0, sizeof(frame));
@@ -435,13 +450,14 @@ namespace ZeroTier {
int err = 0; int err = 0;
if(conn->socket_family == AF_INET) { if(conn->socket_family == AF_INET) {
struct pico_ip4 zaddr; struct pico_ip4 zaddr;
memset(&zaddr, 0, sizeof (struct pico_ip4));
struct sockaddr_in *in4 = (struct sockaddr_in*)addr; struct sockaddr_in *in4 = (struct sockaddr_in*)addr;
char ipv4_str[INET_ADDRSTRLEN]; char ipv4_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_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)); uint32_t ipval = 0;
//DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh( in4->sin_port )); pico_string_to_ipv4(ipv4_str, &ipval);
zaddr.addr = ipval;
err = pico_socket_connect(conn->picosock, &zaddr, in4->sin_port); err = pico_socket_connect(conn->picosock, &zaddr, in4->sin_port);
//DEBUG_INFO("connect_err = %d", err);
} }
if(conn->socket_family == AF_INET6) { if(conn->socket_family == AF_INET6) {
struct pico_ip6 zaddr; struct pico_ip6 zaddr;
@@ -449,10 +465,8 @@ namespace ZeroTier {
char ipv6_str[INET6_ADDRSTRLEN]; char ipv6_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
pico_string_to_ipv6(ipv6_str, zaddr.addr); pico_string_to_ipv6(ipv6_str, zaddr.addr);
//DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port));
err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port); err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port);
} }
memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage)); memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage));
if(err == PICO_ERR_EPROTONOSUPPORT) if(err == PICO_ERR_EPROTONOSUPPORT)
@@ -474,11 +488,13 @@ namespace ZeroTier {
int err = 0; int err = 0;
if(conn->socket_family == AF_INET) { if(conn->socket_family == AF_INET) {
struct pico_ip4 zaddr; struct pico_ip4 zaddr;
memset(&zaddr, 0, sizeof (struct pico_ip4));
struct sockaddr_in *in4 = (struct sockaddr_in*)addr; struct sockaddr_in *in4 = (struct sockaddr_in*)addr;
char ipv4_str[INET_ADDRSTRLEN]; char ipv4_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN); inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN);
uint32_t ipval = 0;
pico_string_to_ipv4(ipv4_str, &(zaddr.addr)); pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
// DEBUG_ATTN("addr=%s: %d ntoh()=%d", ipv4_str, in4->sin_port, Utils::ntoh(in4->sin_port)); DEBUG_EXTRA("addr=%s:%d", ipv4_str, Utils::ntoh(in4->sin_port));
err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)&(in4->sin_port)); err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)&(in4->sin_port));
} }
if(conn->socket_family == AF_INET6) { if(conn->socket_family == AF_INET6) {
@@ -488,7 +504,7 @@ namespace ZeroTier {
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
// TODO: This isn't proper // TODO: This isn't proper
pico_string_to_ipv6("::", pip6.addr); pico_string_to_ipv6("::", pip6.addr);
DEBUG_INFO("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port)); DEBUG_EXTRA("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port));
err = pico_socket_bind(conn->picosock, &pip6, (uint16_t *)&(in6->sin6_port)); err = pico_socket_bind(conn->picosock, &pip6, (uint16_t *)&(in6->sin6_port));
} }
if(err < 0) { if(err < 0) {
@@ -521,7 +537,7 @@ namespace ZeroTier {
DEBUG_ERROR("invalid conn or conn->picosock"); DEBUG_ERROR("invalid conn or conn->picosock");
return ZT_ERR_GENERAL_FAILURE; return ZT_ERR_GENERAL_FAILURE;
} }
int err; int err = 0;
if((err = pico_socket_listen(conn->picosock, backlog)) < 0) if((err = pico_socket_listen(conn->picosock, backlog)) < 0)
{ {
if(err == PICO_ERR_EINVAL) { if(err == PICO_ERR_EINVAL) {
@@ -611,8 +627,7 @@ namespace ZeroTier {
if(conn->socket_type==SOCK_STREAM) { if(conn->socket_type==SOCK_STREAM) {
#if DEBUG_LEVEL >= MSG_TRANSFER #if DEBUG_LEVEL >= MSG_TRANSFER
float max = conn->socket_type == SOCK_STREAM ? (float)ZT_TCP_RX_BUF_SZ : (float)ZT_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 <- STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", DEBUG_TRANS("[ TCP RX <- STACK] :: conn = %p, len = %d", conn, n);
(float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n);
#endif #endif
} }
if(conn->rxsz == 0) { if(conn->rxsz == 0) {
@@ -635,7 +650,11 @@ namespace ZeroTier {
void picoTCP::pico_Write(Connection *conn, void *data, ssize_t len) void picoTCP::pico_Write(Connection *conn, void *data, ssize_t len)
{ {
//DEBUG_INFO(); Mutex::Lock _l(conn->_tx_m);
if(len <= 0) {
DEBUG_ERROR("invalid write length");
return;
}
if(conn->picosock->state & PICO_SOCKET_STATE_CLOSED){ if(conn->picosock->state & PICO_SOCKET_STATE_CLOSED){
DEBUG_ERROR("socket is CLOSED, this write() will fail"); DEBUG_ERROR("socket is CLOSED, this write() will fail");
return; return;
@@ -644,6 +663,12 @@ namespace ZeroTier {
DEBUG_ERROR("invalid connection"); DEBUG_ERROR("invalid connection");
return; return;
} }
if(conn->txsz + len >= ZT_TCP_TX_BUF_SZ) {
DEBUG_ERROR("TX buffer is too small, try increasing ZT_TCP_TX_BUF_SZ in libzt.h");
return;
}
// DEBUG_INFO("conn->txsz = %d, len = %d", conn->txsz, len);
unsigned char *buf = (unsigned char*)data; unsigned char *buf = (unsigned char*)data;
memcpy(conn->txbuf + conn->txsz, buf, len); memcpy(conn->txbuf + conn->txsz, buf, len);
conn->txsz += len; conn->txsz += len;
@@ -661,18 +686,18 @@ namespace ZeroTier {
// adjust buffer // adjust buffer
int sz = (conn->txsz)-r; int sz = (conn->txsz)-r;
if(sz) if(sz)
{
memmove(&conn->txbuf, (conn->txbuf+r), sz); memmove(&conn->txbuf, (conn->txbuf+r), sz);
}
conn->txsz -= r; conn->txsz -= r;
if(conn->socket_type == SOCK_STREAM) { if(conn->socket_type == SOCK_STREAM) {
max = ZT_TCP_TX_BUF_SZ; max = ZT_TCP_TX_BUF_SZ;
DEBUG_TRANS("[ TCP TX -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r);
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
} }
if(conn->socket_type == SOCK_DGRAM) { if(conn->socket_type == SOCK_DGRAM) {
max = ZT_UDP_TX_BUF_SZ; max = ZT_UDP_TX_BUF_SZ;
DEBUG_TRANS("[ UDP TX -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", DEBUG_TRANS("[ UDP TX -> STACK] :: conn = %p, len = %d", conn, r);
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
} }
} }
@@ -681,12 +706,11 @@ namespace ZeroTier {
DEBUG_INFO("conn = %p, picosock=%p, fd = %d", conn, conn->picosock, conn->app_fd); DEBUG_INFO("conn = %p, picosock=%p, fd = %d", conn, conn->picosock, conn->app_fd);
if(!conn || !conn->picosock) if(!conn || !conn->picosock)
return ZT_ERR_GENERAL_FAILURE; return ZT_ERR_GENERAL_FAILURE;
int err; int err = 0;
Mutex::Lock _l(conn->tap->_tcpconns_m); Mutex::Lock _l(conn->tap->_tcpconns_m);
if(conn->closure_ts != -1) // it was closed at some point in the past, it'll work itself out if(conn->closure_ts != -1) // it was closed at some point in the past, it'll work itself out
return ZT_ERR_OK; return ZT_ERR_OK;
if((err = pico_socket_close(conn->picosock)) < 0) { if((err = pico_socket_close(conn->picosock)) < 0) {
DEBUG_ERROR("closing pico_socket...");
errno = pico_err; errno = pico_err;
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock)); DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock));
} }

192
test/echo.cpp Normal file
View File

@@ -0,0 +1,192 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 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/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
// Comprehensive stress test for socket-like API
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <fcntl.h>
#include <errno.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <map>
#include <ctime>
#include <sys/time.h>
#include "libzt.h"
std::map<std::string, std::string> testConf;
void loadTestConfigFile(std::string filepath)
{
std::string key;
std::string value;
std::ifstream testFile;
testFile.open(filepath.c_str());
while (testFile >> key >> value) {
if(key[0] != '#')
testConf[key] = value;
}
testFile.close();
}
long int get_now_ts()
{
struct timeval tp;
gettimeofday(&tp, NULL);
return tp.tv_sec * 1000 + tp.tv_usec / 1000;
}
/****************************************************************************/
/* PERFORMANCE */
/****************************************************************************/
// Maintain transfer for n_count OR n_count
void start_echo_mode(std::string ipstr, int port)
{
DEBUG_TEST();
/*
int w=0, sockfd, err;
int total_test_sz = 1024*1024;
int arbitrary_chunk_sz_max = 16384;
int arbitrary_chunk_sz_min = 512;
char rbuf[arbitrary_chunk_sz_max];
for (int i=arbitrary_chunk_sz_min; (i*2) < arbitrary_chunk_sz_max; i*=2) {
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
DEBUG_ERROR("error creating ZeroTier socket");
if((err = connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0)
DEBUG_ERROR("error connecting to remote host (%d)\n", err);
DEBUG_TEST("[TX] Testing (%d) byte chunks: ", i);
int chunk_sz = i;
int iterations = total_test_sz / chunk_sz;
long int start_time = get_now_ts();
w = 0;
while(w < total_test_sz)
w += write(sockfd, rbuf, chunk_sz);
long int end_time = get_now_ts();
float ts_delta = (end_time - start_time) / (float)1000;
float rate = (float)total_test_sz / (float)ts_delta;
DEBUG_TEST("%d total bytes, time = %3f, rate = %3f KB/s", w, ts_delta, (rate / (float)1024) );
close(sockfd);
// let things settle after test
sleep(5);
}
*passed = (w == total_test_sz && !err) ? PASSED : FAILED;
*/
}
/*
Mode 1 (Measure performance of other host's TX):
- Receive incoming TX test config (total bytes intended)
- Prepare receiver
- Record time of first received byte
- Record time of last received byte
- Send results back to other host's selftest instance
Mode 2 (Measure performance of other host's RX):
- Receive incoming RX test config (total bytes requested)
- Prepare transmitter
- Send bytes as fast as possible
*/
int main(int argc , char *argv[])
{
if(argc < 1) {
fprintf(stderr, "usage: echo <alice|bob>.conf\n");
fprintf(stderr, " - Define your test environment in *.conf files.\n");
return 1;
}
int err = 0;
int type = 0;
int protocol = 0;
int mode = 0;
int port = 0;
int start_port = 0;
int port_offset = 0;
int operation = 0;
int n_count = 0;
int delay = 0;
std::string local_echo_ipv4;
std::string nwid, stype, path = argv[1];
std::string ipstr, ipstr6, local_ipstr, local_ipstr6, remote_ipstr, remote_ipstr6;
// if a test config file was specified:
if(path.find(".conf") != std::string::npos) {
//printf("\nTest config file contents:\n");
loadTestConfigFile(path);
nwid = testConf["nwid"];
path = testConf["local_path"];
stype = testConf["test"];
start_port = atoi(testConf["start_port"].c_str());
port_offset = atoi(testConf["port_offset"].c_str());
local_ipstr = testConf["local_ipv4"];
local_ipstr6 = testConf["local_ipv6"];
remote_ipstr = testConf["remote_ipv4"];
remote_ipstr6 = testConf["remote_ipv6"];
std::string smode = testConf["mode"];
/*
if(strcmp(smode.c_str(), "server") == 0)
mode = TEST_MODE_SERVER;
else
mode = TEST_MODE_CLIENT;
*/
fprintf(stderr, "\tlocal_ipstr = %s\n", local_ipstr.c_str());
fprintf(stderr, "\tremote_ipstr = %s\n", remote_ipstr.c_str());
fprintf(stderr, "\tstart_port = %d\n", start_port);
fprintf(stderr, "\tport_offset = %d\n", port_offset);
fprintf(stderr, "\tlocal_echo_ipv4 = %s\n", local_echo_ipv4.c_str());
}
fprintf(stderr, "\tpath = %s\n", path.c_str());
fprintf(stderr, "\tnwid = %s\n", nwid.c_str());
fprintf(stderr, "\ttype = %s\n\n", stype.c_str());
DEBUG_TEST("Starting echo mode...");
start_echo_mode(local_echo_ipv4, start_port+port_offset);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -55,13 +55,13 @@ namespace ZeroTier {
ZTProxy::ZTProxy(int proxy_listen_port, std::string nwid, std::string path, std::string internal_addr, int internal_port) ZTProxy::ZTProxy(int proxy_listen_port, std::string nwid, std::string path, std::string internal_addr, int internal_port)
: :
_phy(this,false,true),
_enabled(true), _enabled(true),
_run(true), _run(true),
_proxy_listen_port(proxy_listen_port), _proxy_listen_port(proxy_listen_port),
_internal_port(internal_port), _internal_port(internal_port),
_nwid(nwid), _nwid(nwid),
_internal_addr(internal_addr) _internal_addr(internal_addr),
_phy(this,false,true)
{ {
// Start ZeroTier Node // Start ZeroTier Node
// Join Network which contains resources we need to proxy // Join Network which contains resources we need to proxy
@@ -220,16 +220,19 @@ namespace ZeroTier {
void ZTProxy::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) void ZTProxy::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len)
{ {
// Not used, connections are handled via user space network stack and SocketTap subsystem
DEBUG_INFO("phyOnDatagram"); DEBUG_INFO("phyOnDatagram");
exit(0); exit(0);
} }
void ZTProxy::phyOnTcpWritable(PhySocket *sock,void **uptr) void ZTProxy::phyOnTcpWritable(PhySocket *sock,void **uptr)
{ {
// Not used, connections are handled via user space network stack and SocketTap subsystem
DEBUG_INFO("phyOnTcpWritable"); DEBUG_INFO("phyOnTcpWritable");
exit(0); exit(0);
} }
void ZTProxy::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) void ZTProxy::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable)
{ {
// Not used, connections are handled via user space network stack and SocketTap subsystem
DEBUG_INFO("phyOnFileDescriptorActivity, sock=%p", sock); DEBUG_INFO("phyOnFileDescriptorActivity, sock=%p", sock);
exit(0); exit(0);
} }
@@ -239,6 +242,12 @@ namespace ZeroTier {
DEBUG_INFO("phyOnTcpConnect, sock=%p", sock); DEBUG_INFO("phyOnTcpConnect, sock=%p", sock);
exit(0); exit(0);
} }
void ZTProxy::phyOnUnixClose(PhySocket *sock,void **uptr)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
DEBUG_INFO("phyOnUnixClose, sock=%p", sock);
exit(0);
}
void ZTProxy::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) void ZTProxy::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
{ {
@@ -256,11 +265,6 @@ namespace ZeroTier {
cmap[sockN]=conn; // add new connection cmap[sockN]=conn; // add new connection
} }
void ZTProxy::phyOnUnixClose(PhySocket *sock,void **uptr)
{
DEBUG_INFO("phyOnUnixClose, sock=%p", sock);
exit(0);
}
void ZTProxy::phyOnUnixData(PhySocket *sock,void **uptr,void *data,ssize_t len) void ZTProxy::phyOnUnixData(PhySocket *sock,void **uptr,void *data,ssize_t len)
{ {
DEBUG_INFO("phyOnUnixData(sock=%p, len=%lu)", sock, len); DEBUG_INFO("phyOnUnixData(sock=%p, len=%lu)", sock, len);
@@ -318,7 +322,7 @@ int main(int argc, char **argv)
{ {
if(argc != 6) { if(argc != 6) {
printf("\nZeroTier TCP Proxy Service\n"); printf("\nZeroTier TCP Proxy Service\n");
printf("ztproxy [local port] [network ID]/[ZT internal IP]/port\n"); printf("ztproxy [config_file_path] [local_listen_port] [nwid] [zt_host_addr] [zt_resource_port]\n");
exit(0); exit(0);
} }
std::string path = argv[1]; std::string path = argv[1];
@@ -330,9 +334,9 @@ int main(int argc, char **argv)
ZeroTier::ZTProxy *proxy = new ZeroTier::ZTProxy(proxy_listen_port, nwid, path, internal_addr, internal_port); ZeroTier::ZTProxy *proxy = new ZeroTier::ZTProxy(proxy_listen_port, nwid, path, internal_addr, internal_port);
if(proxy) { if(proxy) {
printf("ZTProxy started. Listening on %d\n", proxy_listen_port); printf("\nZTProxy started. Listening on %d\n", proxy_listen_port);
printf("Traffic will be proxied to and from %s:%d on network %s\n", internal_addr.c_str(), internal_port, nwid.c_str()); printf("Traffic will be proxied to and from %s:%d on network %s\n", internal_addr.c_str(), internal_port, nwid.c_str());
printf("Proxy Node config files and key stored in: %s/\n", path.c_str()); printf("Proxy Node config files and key stored in: %s/\n\n", path.c_str());
while(1) { while(1) {
sleep(1); sleep(1);
} }