improved testing and connection handling

This commit is contained in:
Joseph Henry
2017-04-20 13:39:46 -07:00
parent c65b609fb4
commit 76abb3e0a2
30 changed files with 2430 additions and 775 deletions

View File

@@ -1,15 +1,51 @@
ZeroTier SDK
======
[![irc](https://img.shields.io/badge/IRC-%23zerotier%20on%20freenode-orange.svg)](https://webchat.freenode.net/?channels=zerotier)
***
## Example
```
std::string str = "welcome to the machine";
zts_start(path);
while(!zts_service_running())
sleep(1);
zts_join_network(nwid);
int err, sockfd;
while(!zts_has_address(nwid))
sleep(1);
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
```
Bindings also exist for [many popular languages]().
## Build Targets
### Static Library
`static_lib`
- `make static_lib`: Will output to `build/`
### Tests
- `make tests`: Will output to `build/tests/`
Then run the comprehensive test suite with whatever configuration you need. For instance:
To run a single-test IPv4 server on port 8787:
- Host 1: `./build/test/comprehensive c7cd7c9e1b0f52a2 simple 4 server 8787`
- Host 2: `./build/test/comprehensive c7cd7c9e1b0f52a2 simple 4 client 10.9.9.40 8787`
## Using Language Bindings
`SDK_LANG_JAVA=1`
`SDK_LANG_CSHARP=1`
`SDK_LANG_PYTHON=1`
`SDK_LANG_=1`
`SDK_LANG_GO=1`

3
api/clojure/README.md Normal file
View File

@@ -0,0 +1,3 @@
Clojure Language Binding API for the ZeroTier SDK
======

3
api/go/README.md Normal file
View File

@@ -0,0 +1,3 @@
Go Language Binding API for the ZeroTier SDK
======

View File

@@ -19,6 +19,7 @@ struct pico_ethdev {
};
struct pico_device {
void *tap;
char name[MAX_DEVICE_NAME];
uint32_t hash;
uint32_t overhead;

View File

@@ -27,17 +27,13 @@
#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 ZT_ACCEPT_RECHECK_DELAY 100 // ms (for blocking zts_accept() calls)
#define ZT_CONNECT_RECHECK_DELAY 100 // ms (for blocking zts_connect() calls)
#define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128
// TCP
#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 ZT_UDP_TX_BUF_SZ ZT_MAX_MTU
#define ZT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10
@@ -54,6 +50,11 @@
#define ZT_ERR_OK 0
#define ZT_SOCK_STATE_NONE 100
#define ZT_SOCK_STATE_UNHANDLED_CONNECTED 101
#define ZT_SOCK_STATE_CONNECTED 102
#define ZT_SOCK_STATE_LISTENING 103
/****************************************************************************/
/* Socket API Signatures */
/****************************************************************************/
@@ -407,7 +408,7 @@ void *_start_service(void *thread_id);
#endif
#if ZT_DEBUG_LEVEL >= ZT_MSG_ERROR
#define DEBUG_ERROR(fmt, args...) fprintf(stderr, ZT_RED "ZT_ERROR[%ld] : %14s:%4d:%25s: " fmt \
#define DEBUG_ERROR(fmt, args...) fprintf(stderr, ZT_RED "ZT_ERROR[%ld] : %16s:%4d:%25s: " fmt \
"\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#else
#define DEBUG_ERROR(fmt, args...)

View File

@@ -107,12 +107,13 @@ endif
STACK_DRIVER_FILES:=src/picoTCP.cpp
TAP_FILES:=src/SocketTap.cpp \
src/ZeroTierSDK.cpp
src/ZeroTierSDK.cpp \
src/Utils.cpp
SDK_OBJS+= SocketTap.o \
Socket.o \
picoTCP.o \
ZeroTierSDK.o
ZeroTierSDK.o \
Utils.o
PICO_OBJS+= ext/picotcp/build/lib/pico_device.o \
ext/picotcp/build/lib/pico_frame.o \
@@ -140,7 +141,7 @@ picotcp:
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)
libtool -o $(STATIC_LIB) $(ZTO_OBJS) $(SDK_OBJS) $(PICO_LIB)
jni_static_lib: picotcp $(ZTO_OBJS)
@@ -149,7 +150,7 @@ jni_static_lib: picotcp $(ZTO_OBJS)
##############################################################################
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_OBJ_FILES:=$(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_FILES:.cpp=)))
UNIT_TEST_INCLUDES:=-Iinclude
UNIT_TEST_LIBS:=-Lbuild -lzt
@@ -164,10 +165,10 @@ 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)))
DUMB_TEST_SRC_FILES=$(wildcard $(DUMB_TEST_SRC_DIR)/*.cpp)
DUMB_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(DUMB_TEST_SRC_FILES:.cpp=.out)))
$(TEST_BUILD_DIR)/%.out: $(DUMB_TEST_SRC_DIR)/%.c
$(TEST_BUILD_DIR)/%.out: $(DUMB_TEST_SRC_DIR)/%.cpp
@mkdir -p $(TEST_BUILD_DIR)
@-$(CC) -o $@ $<
@-./check.sh $@
@@ -182,7 +183,7 @@ 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
-find . -type f \( -name '*.o' -o -name '*.so' -o -name '*.a' -o -name '*.o.d' -o -name '*.out' -o -name '*.log' -o -name '*.dSYM' \) -delete
# Check for the presence of built frameworks/bundles/libaries
check:

View File

@@ -108,10 +108,12 @@ endif
STACK_DRIVER_FILES:=src/picoTCP.cpp
TAP_FILES:=src/SocketTap.cpp \
src/ZeroTierSDK.cpp \
src/Utils.cpp
SDK_OBJS+= SocketTap.o \
picoTCP.o \
ZeroTierSDK.o
ZeroTierSDK.o \
Utils.o
PICO_OBJS+= ext/picotcp/build/lib/pico_device.o \
ext/picotcp/build/lib/pico_frame.o \
@@ -148,11 +150,11 @@ jni_static_lib: picotcp $(ZTO_OBJS)
##############################################################################
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_OBJ_FILES:=$(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_FILES:.cpp=)))
UNIT_TEST_INCLUDES:=-Iinclude
UNIT_TEST_LIBS:=-Lbuild -lzt
$(TEST_BUILD_DIR)/%.out: $(UNIT_TEST_SRC_DIR)/%.cpp
$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp
@mkdir -p $(TEST_BUILD_DIR)
@-$(CXX) $(UNIT_TEST_INCLUDES) -o $@ $< $(UNIT_TEST_LIBS)
@-./check.sh $@
@@ -163,10 +165,10 @@ 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)))
DUMB_TEST_SRC_FILES=$(wildcard $(DUMB_TEST_SRC_DIR)/*.cpp)
DUMB_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(DUMB_TEST_SRC_FILES:.cpp=)))
$(TEST_BUILD_DIR)/%.out: $(DUMB_TEST_SRC_DIR)/%.c
$(TEST_BUILD_DIR)/%: $(DUMB_TEST_SRC_DIR)/%.cpp
@mkdir -p $(TEST_BUILD_DIR)
@-$(CC) -o $@ $<
@-./check.sh $@
@@ -181,7 +183,7 @@ 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
-find . -type f \( -name '*.o' -o -name '*.so' -o -name '*.a' -o -name '*.o.d' -o -name '*.out' -o -name '*.log' -o -name '*.dSYM' \) -delete
# Check for the presence of built frameworks/bundles/libaries
check:

View File

@@ -56,6 +56,7 @@ namespace ZeroTier {
std::queue<Connection*> _AcceptedConnections;
SocketTap *tap; // Reference to SocketTap
int state; // See ZeroTierSDK.h for (ZT_SOCK_STATE_*)
Connection() {
ZT_PHY_SOCKFD_TYPE fdpair[2];
@@ -69,5 +70,15 @@ namespace ZeroTier {
app_fd = fdpair[1];
}
};
/*
* A helper object for passing SocketTaps and Connections through the stack
*/
struct ConnectionPair
{
SocketTap *tap;
Connection *conn;
ConnectionPair(SocketTap *_tap, Connection *conn) : tap(_tap), conn(conn) {}
};
}
#endif

View File

@@ -37,16 +37,6 @@
namespace ZeroTier {
// Ignore these
void SocketTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len) {}
void SocketTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
void SocketTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
const struct sockaddr *from) {}
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) {}
/****************************************************************************/
/* SocketTap Service */
/* - For each joined network a SocketTap will be created to administer I/O */
@@ -63,29 +53,17 @@ SocketTap::SocketTap(
void (*handler)(void *,void*,uint64_t,const MAC &,const MAC &,
unsigned int,unsigned int,const void *,unsigned int),
void *arg) :
_handler(handler),
_homePath(homePath),
_arg(arg),
_enabled(true),
_run(true),
_mac(mac),
_mtu(mtu),
_nwid(nwid),
_handler(handler),
_arg(arg),
_phy(this,false,true),
_unixListenSocket((PhySocket *)0),
_enabled(true),
_run(true)
_phy(this,false,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);
_dev = sockPath;
_unixListenSocket = _phy.unixListen(sockPath,(void *)this);
chmod(sockPath, 0777); // make the RPC socket available to all users
if (!_unixListenSocket)
DEBUG_ERROR("unable to bind to: rpc = %s", sockPath);
else
DEBUG_INFO("rpc = %s", sockPath);
*/
_thread = Thread::start(this);
}
@@ -96,6 +74,7 @@ SocketTap::~SocketTap()
_phy.whack();
Thread::join(_thread);
_phy.close(_unixListenSocket,false);
for(int i=0; i<_Connections.size(); i++) delete _Connections[i];
}
void SocketTap::setEnabled(bool en)
@@ -111,7 +90,6 @@ bool SocketTap::enabled() const
bool SocketTap::addIp(const InetAddress &ip)
{
DEBUG_INFO();
picotap = this;
picostack->pico_init_interface(this, ip);
_ips.push_back(ip);
return true;
@@ -128,6 +106,9 @@ bool SocketTap::removeIp(const InetAddress &ip)
if (ip.isV4()) {
// FIXME: De-register from network stacks
}
if (ip.isV6()) {
// FIXME: De-register from network stacks
}
return true;
}
@@ -140,10 +121,8 @@ 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);
}
std::string SocketTap::deviceName() const
@@ -185,84 +164,30 @@ void SocketTap::threadMain()
picostack->pico_loop(this);
}
Connection *SocketTap::getConnection(PhySocket *sock)
void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr)
{
DEBUG_INFO();
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i]->sock == sock)
return _Connections[i];
}
return NULL;
}
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];
}
return NULL;
}
void SocketTap::closeConnection(PhySocket *sock)
{
DEBUG_INFO();
Mutex::Lock _l(_close_m);
// Here we assume _tcpconns_m is already locked by caller
if(!sock) {
DEBUG_EXTRA("invalid PhySocket");
return;
}
picostack->pico_handleClose(sock);
Connection *conn = getConnection(sock);
if(!conn)
return;
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i] == conn){
_Connections.erase(_Connections.begin() + i);
delete conn;
break;
}
}
if(!sock)
return;
close(_phy.getDescriptor(sock));
_phy.close(sock, false);
}
void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr) {
DEBUG_INFO();
//Mutex::Lock _l(_tcpconns_m);
//closeConnection(sock);
// FIXME:
}
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);
Close((Connection*)uptr);
}
void SocketTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
{
DEBUG_INFO();
Connection *conn = getConnection(sock);
Connection *conn = (Connection*)*uptr;
if(!conn)
return;
if(len) {
unsigned char *buf = (unsigned char*)data;
memcpy(conn->txbuf + conn->txsz, buf, len);
conn->txsz += len;
handleWrite(conn);
Write(conn);
}
return;
}
void SocketTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool stack_invoked)
{
Read(sock,uptr,stack_invoked);
}
/****************************************************************************/
/* SDK Socket API */
/****************************************************************************/
@@ -287,52 +212,48 @@ int SocketTap::Accept(Connection *conn) {
return picostack->pico_Accept(conn);
}
void SocketTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) {
picostack->pico_Read(this, sock, uptr, stack_invoked);
}
void SocketTap::Write(Connection *conn) {
picostack->pico_Write(conn);
}
/*------------------------------------------------------------------------------
----------------------------- RPC Handler functions ----------------------------
------------------------------------------------------------------------------*/
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){
DEBUG_EXTRA("no address info available. is it bound?");
struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage));
write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage));
void SocketTap::Close(Connection *conn) {
Mutex::Lock _l(_close_m);
// Here we assume _tcpconns_m is already locked by caller
if(!conn->sock) {
DEBUG_EXTRA("invalid PhySocket");
return;
}
write(_phy.getDescriptor(rpcSock), conn->local_addr, sizeof(struct sockaddr_storage));
}
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){
DEBUG_EXTRA("no peer address info available. is it connected?");
struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage));
write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage));
if(!conn)
return;
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i] == conn){
_Connections.erase(_Connections.begin() + i);
delete conn;
break;
}
write(_phy.getDescriptor(rpcSock), conn->peer_addr, sizeof(struct sockaddr_storage));
}
if(!conn->sock)
return;
close(_phy.getDescriptor(conn->sock));
_phy.close(conn->sock, false);
}
// Write to the network stack (and thus out onto the network)
void SocketTap::handleWrite(Connection *conn)
{
DEBUG_INFO();
picostack->pico_handleWrite(conn);
}
/****************************************************************************/
/* Not used in this implementation */
/****************************************************************************/
void SocketTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len) {}
void SocketTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
void SocketTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
const struct sockaddr *from) {}
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) {}
} // namespace ZeroTier

View File

@@ -45,34 +45,11 @@
#include "pico_icmp4.h"
#include "pico_dev_tap.h"
#include "pico_protocol.h"
#include "pico_socket.h"
#include "pico_device.h"
#include "pico_ipv6.h"
// ZT RPC structs
struct socket_st;
struct listen_st;
struct bind_st;
struct connect_st;
struct getsockname_st;
struct accept_st;
struct pico_socket;
namespace ZeroTier {
extern SocketTap *picotap;
/*
* A helper for passing a reference to _phy to stackrpc callbacks as a "state"
*/
struct Larg
{
SocketTap *tap;
Connection *conn;
Larg(SocketTap *_tap, Connection *conn) : tap(_tap), conn(conn) {}
};
/*
* Socket Tap -- emulates an Ethernet tap device
*/
@@ -97,19 +74,17 @@ namespace ZeroTier {
bool enabled() const;
/*
*
* Adds an address to the userspace stack interface associated with this SocketTap
*/
bool addIp(const InetAddress &ip);
/*
*
* Removes an address from the userspace stack interface associated with this SocketTap
*/
bool removeIp(const InetAddress &ip);
std::vector<InetAddress> ips() const;
std::vector<InetAddress> _ips;
/*
*
* Presents data to the userspace stack
*/
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,
unsigned int len);
@@ -135,73 +110,12 @@ namespace ZeroTier {
void threadMain()
throw();
std::string _homePath;
MAC _mac;
unsigned int _mtu;
uint64_t _nwid;
/*
*
* For moving data onto the ZeroTier virtual wire
*/
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,
const void *,unsigned int);
void *_arg;
Phy<SocketTap *> _phy;
PhySocket *_unixListenSocket;
volatile bool _enabled;
volatile bool _run;
// picoTCP
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
int pico_frame_rxbuf_tot;
Mutex _pico_frame_rxbuf_m;
/****************************************************************************/
/* 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
*/
void handleGetsockname(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
/*
* Return the address of the peer connected to this socket
*/
void handleGetpeername(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
/*
* Writes data from the application's socket to the LWIP connection
*/
void handleWrite(Connection *conn);
// Unused -- no UDP or TCP from this thread/Phy<>
void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len);
void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success);
void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
const struct sockaddr *from);
void phyOnTcpClose(PhySocket *sock,void **uptr);
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len);
void phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked);
/*
*
*/
void handleRead(PhySocket *sock,void **uptr,bool stack_invoked);
/*
* Signals us to close the TcpConnection associated with this PhySocket
*/
@@ -217,21 +131,22 @@ namespace ZeroTier {
*/
void phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked);
/*
* Returns a pointer to a TcpConnection associated with a given PhySocket
*/
Connection *getConnection(PhySocket *sock);
/****************************************************************************/
/* Vars */
/****************************************************************************/
/*
* Returns a pointer to a TcpConnection associated with a given pico_socket
*/
Connection *getConnection(struct pico_socket *socket);
std::vector<InetAddress> ips() const;
std::vector<InetAddress> _ips;
/*
* Closes a TcpConnection, associated connection strcuture,
* PhySocket, and underlying file descriptor
*/
void closeConnection(PhySocket *sock);
std::string _homePath;
void *_arg;
volatile bool _enabled;
volatile bool _run;
MAC _mac;
unsigned int _mtu;
uint64_t _nwid;
PhySocket *_unixListenSocket;
Phy<SocketTap *> _phy;
std::vector<Connection*> _Connections;
@@ -241,7 +156,86 @@ namespace ZeroTier {
std::vector<MulticastGroup> _multicastGroups;
Mutex _multicastGroups_m;
Mutex _ips_m, _tcpconns_m, _rx_buf_m, _close_m;
/****************************************************************************/
/* Guarded RX Frame Buffer for picoTCP */
/****************************************************************************/
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
int pico_frame_rxbuf_tot;
Mutex _pico_frame_rxbuf_m;
/****************************************************************************/
/* In these, we will call the stack's corresponding functions, this is */
/* where one would put logic to select between different stacks */
/****************************************************************************/
/*
* Connect to a remote host via the userspace stack interface associated with this SocketTap
*/
int Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
/*
* Bind to the userspace stack interface associated with this SocketTap
*/
int Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
/*
* Listen for a Connection
*/
void Listen(Connection *conn, int fd, int backlog);
/*
* Accepts an incoming Connection
*/
int Accept(Connection *conn);
/*
* Move data from RX buffer to application's "socket"
*/
void Read(PhySocket *sock,void **uptr,bool stack_invoked);
/*
* Move data from application's "socket" into network stack
*/
void Write(Connection *conn);
/*
* Closes a Connection
*/
void Close(Connection *conn);
/*
* Return the address that the socket is bound to
*/
void handleGetsockname(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
/*
* Return the address of the peer connected to this socket
*/
void handleGetpeername(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
/****************************************************************************/
/* Not used in this implementation */
/****************************************************************************/
void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len);
void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success);
void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
const struct sockaddr *from);
void phyOnTcpClose(PhySocket *sock,void **uptr);
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len);
void phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked);
};
} // namespace ZeroTier
#endif

84
src/Utils.cpp Normal file
View File

@@ -0,0 +1,84 @@
/*
* 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/>.
*/
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
void zt_dump_stacktrace(int sig) {
void *array[16];
size_t size;
size = backtrace(array, 16);
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
/*
char *beautify_pico_error(int err)
{
switch(err){
PICO_ERR_NOERR = 0,
PICO_ERR_EPERM = 1,
PICO_ERR_ENOENT = 2,
PICO_ERR_EINTR = 4,
PICO_ERR_EIO = 5,
PICO_ERR_ENXIO = 6,
PICO_ERR_EAGAIN = 11,
PICO_ERR_ENOMEM = 12,
PICO_ERR_EACCESS = 13,
PICO_ERR_EFAULT = 14,
PICO_ERR_EBUSY = 16,
PICO_ERR_EEXIST = 17,
PICO_ERR_EINVAL = 22,
PICO_ERR_ENONET = 64,
PICO_ERR_EPROTO = 71,
PICO_ERR_ENOPROTOOPT = 92,
PICO_ERR_EPROTONOSUPPORT = 93,
PICO_ERR_EOPNOTSUPP = 95,
PICO_ERR_EADDRINUSE = 98,
PICO_ERR_EADDRNOTAVAIL = 99,
PICO_ERR_ENETDOWN = 100,
PICO_ERR_ENETUNREACH = 101,
PICO_ERR_ECONNRESET = 104,
PICO_ERR_EISCONN = 106,
PICO_ERR_ENOTCONN = 107,
PICO_ERR_ESHUTDOWN = 108,
PICO_ERR_ETIMEDOUT = 110,
PICO_ERR_ECONNREFUSED = 111,
PICO_ERR_EHOSTDOWN = 112,
PICO_ERR_EHOSTUNREACH = 113,
}
return err_text;
}
*/

27
src/Utils.hpp Normal file
View File

@@ -0,0 +1,27 @@
/*
* 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 SDK_UTILS_HPP
#define SDK_UTILS_HPP
/*
* Print a stacktrace
*/
void zt_dump_stacktrace(int sig);
#endif

View File

@@ -48,11 +48,24 @@ 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
/*
* Global reference to stack
*/
picoTCP *picostack = NULL;
/*
* "sockets" that have been created but not bound to a SocketTap interface yet
*/
std::map<int, Connection*> UnassignedConnections;
std::map<int, std::pair<Connection*,SocketTap*>*> AssignedFileDescriptors;
Mutex _multiplexer_lock;
Mutex _accepted_connection_lock;
// FIXME: make sure these are properly deleted
/*
* For fast lookup of Connections and SocketTaps via given file descriptor
*/
std::map<int, std::pair<Connection*,SocketTap*>*> AssignedConnections;
ZeroTier::Mutex _multiplexer_lock;
ZeroTier::Mutex _accepted_connection_lock;
}
/****************************************************************************/
@@ -260,12 +273,12 @@ int zts_get_peer_address(char *peer, const char *devID) {
void zts_enable_http_control_plane()
{
// TODO
}
void zts_disable_http_control_plane()
{
// TODO
}
/****************************************************************************/
@@ -278,6 +291,7 @@ void zts_disable_http_control_plane()
/****************************************************************************/
int zts_socket(ZT_SOCKET_SIG) {
DEBUG_ERROR("UnassConn=%d, AssigFDs=%d", ZeroTier::UnassignedConnections.size(), ZeroTier::AssignedConnections.size());
DEBUG_INFO();
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = new ZeroTier::Connection();
@@ -316,7 +330,7 @@ int zts_socket(ZT_SOCKET_SIG) {
int zts_connect(ZT_CONNECT_SIG) {
if(!zt1Service) {
DEBUG_ERROR("zt1Service = NULL");
DEBUG_ERROR("Service not started. Call zts_start(path) first");
// errno = ?
return -1;
}
@@ -341,12 +355,9 @@ int zts_connect(ZT_CONNECT_SIG) {
(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 route to host");
@@ -354,28 +365,70 @@ int zts_connect(ZT_CONNECT_SIG) {
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
// pointer to tap we use in callbacks from the stack
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
DEBUG_INFO("found appropriate SocketTap");
// TODO: Perhaps move this connect call outside of the lock
// Semantically: tap->stack->connect
err = tap->Connect(conn, fd, addr, addrlen);
if(err == 0) {
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;
}
// Wrap the socketpair we created earlier
// For I/O loop participation and referencing the PhySocket's parent Connection in callbacks
conn->sock = tap->_phy.wrapSocket(conn->sdk_fd, conn);
}
}
else {
DEBUG_ERROR("unable to locate connection");
// errno = ?
err = -1;
}
ZeroTier::AssignedFileDescriptors[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::UnassignedConnections.erase(fd);
ZeroTier::AssignedConnections[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::_multiplexer_lock.unlock();
// NOTE: pico_socket_connect() will return 0 if no error happens immediately, but that doesn't indicate
// the connection was completed, for that we must wait for a callback from the stack. During that
// callback we will place the Connection in a ZT_SOCK_STATE_UNHANDLED_CONNECTED state to signal
// to the multiplexer logic that this connection is complete and a success value can be sent to the
// user application
// non-blocking
if(err == 0 && false)
{
errno = EINPROGRESS;
return -1;
}
// blocking
if(err == 0 && true) {
while(true)
{
usleep(ZT_CONNECT_RECHECK_DELAY * 1000);
tap->_tcpconns_m.lock();
for(int i=0; i<tap->_Connections.size(); i++)
{
if(tap->_Connections[i]->state == PICO_ERR_ECONNRESET) {
errno = ECONNRESET;
return -1;
}
if(tap->_Connections[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) {
tap->_Connections[i]->state = ZT_SOCK_STATE_CONNECTED;
errno = 0;
return 0; // complete
}
}
tap->_tcpconns_m.unlock();
}
}
return err;
}
int zts_bind(ZT_BIND_SIG) {
if(!zt1Service) {
DEBUG_ERROR("zt1Service = NULL");
DEBUG_ERROR("Service not started. Call zts_start(path) first");
// errno = ?
return -1;
}
@@ -415,7 +468,7 @@ int zts_bind(ZT_BIND_SIG) {
else {
DEBUG_INFO("found appropriate SocketTap");
DEBUG_INFO("conn->picosock = %p", conn->picosock);
conn->picosock->priv = new ZeroTier::Larg(tap, conn);
conn->picosock->priv = new ZeroTier::ConnectionPair(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
@@ -427,37 +480,43 @@ int zts_bind(ZT_BIND_SIG) {
// errno = ?
err = -1;
}
ZeroTier::AssignedFileDescriptors[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::AssignedConnections[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");
DEBUG_ERROR("Service not started. Call zts_start(path) first");
// errno = ?
return -1;
}
int err;
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::AssignedFileDescriptors[fd]->first;
ZeroTier::SocketTap *tap = ZeroTier::AssignedFileDescriptors[fd]->second;
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::AssignedConnections[fd];
if(!p) {
DEBUG_ERROR("unable to locate connection pair (did you zbind()?");
return -1;
}
ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second;
if(!tap || !conn) {
DEBUG_ERROR("unable to locate tap interface for file descriptor");
err = -1;
return -1;
}
tap->Listen(conn, fd, backlog);
err = 0;
DEBUG_INFO("put %p into LISTENING state", conn);
DEBUG_INFO("put conn=%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;
ZeroTier::Connection *conn = ZeroTier::AssignedConnections[fd]->first;
ZeroTier::SocketTap *tap = ZeroTier::AssignedConnections[fd]->second;
// BLOCKING: loop and keep checking until we find a newly accepted connection
if(true) {
while(true) {
@@ -476,57 +535,75 @@ int zts_accept(ZT_ACCEPT_SIG) {
#if defined(__linux__)
int zts_accept4(ZT_ACCEPT4_SIG)
{
// TODO
return 0;
}
#endif
int zts_setsockopt(ZT_SETSOCKOPT_SIG)
{
// TODO
return 0;
}
int zts_getsockopt(ZT_GETSOCKOPT_SIG)
{
// TODO
return 0;
}
int zts_getsockname(ZT_GETSOCKNAME_SIG)
{
// TODO
return 0;
}
int zts_getpeername(ZT_GETPEERNAME_SIG)
{
// TODO
return 0;
}
int zts_close(ZT_CLOSE_SIG)
{
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::AssignedConnections[fd]->first;
ZeroTier::SocketTap *tap = ZeroTier::AssignedConnections[fd]->second;
// Tell the tap to stop monitoring this PhySocket
tap->Close(conn);
// Tell the userspace stack to close this pico_socket
ZeroTier::picostack->pico_Close(conn);
ZeroTier::_multiplexer_lock.unlock();
return 0;
}
int zts_fcntl(ZT_FCNTL_SIG)
{
// TODO
return 0;
}
ssize_t zts_sendto(ZT_SENDTO_SIG)
{
// TODO
return 0;
}
ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
{
// TODO
return 0;
}
ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
{
// TODO
return 0;
}
ssize_t zts_recvmsg(ZT_RECVMSG_SIG)
{
// TODO
return 0;
}
@@ -666,7 +743,7 @@ void *_start_service(void *thread_id) {
// Generate random port for new service instance
unsigned int randp = 0;
ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
int servicePort = 9000 + (randp % 10000);
int servicePort = 9000 + (randp % 1000);
DEBUG_ERROR("servicePort = %d", servicePort);
for(;;) {

View File

@@ -27,6 +27,7 @@
#include "pico_ipv6.h"
#include "ZeroTierSDK.h"
#include "Utils.hpp"
#include "SocketTap.hpp"
#include "picoTCP.hpp"
@@ -36,13 +37,6 @@
#include "Constants.hpp"
#include "Phy.hpp"
// stack locks
ZeroTier::Mutex _lock;
ZeroTier::Mutex _lock_mem;
struct pico_socket;
struct pico_device;
extern "C" int pico_stack_init(void);
extern "C" void pico_stack_tick(void);
@@ -73,6 +67,8 @@ extern "C" struct pico_ipv6_link * pico_ipv6_link_add(PICO_IPV6_LINK_ADD_SIG);
namespace ZeroTier {
//extern ZeroTier::Mutex _accepted_connection_lock;
// Reference to the tap interface
// This is needed due to the fact that there's a lot going on in the tap interface
// that needs to be updated on each of the network stack's callbacks and not every
@@ -82,7 +78,6 @@ namespace ZeroTier {
// will make it easier to maintain multiple active tap interfaces
struct pico_device picodev;
SocketTap * picotap;
int pico_eth_send(struct pico_device *dev, void *buf, int len);
int pico_eth_poll(struct pico_device *dev, int loop_score);
@@ -105,6 +100,7 @@ namespace ZeroTier {
picodev.send = pico_eth_send; // tx
picodev.poll = pico_eth_poll; // rx
picodev.mtu = tap->_mtu;
picodev.tap = tap;
if( 0 != pico_device_init(&(picodev), "p0", mac)) {
DEBUG_ERROR("dev init failed");
return;
@@ -125,6 +121,7 @@ namespace ZeroTier {
pico_ipv6_link_add(&(picodev), ipaddr, netmask);
picodev.send = pico_eth_send; // tx
picodev.poll = pico_eth_poll; // rx
picodev.tap = tap;
uint8_t mac[PICO_SIZE_ETH];
tap->_mac.copyTo(mac, PICO_SIZE_ETH);
DEBUG_ATTN("mac = %s", tap->_mac.toString().c_str());
@@ -138,7 +135,6 @@ namespace ZeroTier {
}
}
// Main stack loop
void picoTCP::pico_loop(SocketTap *tap)
{
while(tap->_run)
@@ -151,7 +147,7 @@ namespace ZeroTier {
void picoTCP::pico_cb_tcp_read(ZeroTier::SocketTap *tap, struct pico_socket *s)
{
DEBUG_INFO();
Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
if(conn) {
int r;
uint16_t port = 0;
@@ -180,7 +176,7 @@ namespace ZeroTier {
void picoTCP::pico_cb_udp_read(SocketTap *tap, struct pico_socket *s)
{
DEBUG_INFO();
Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
if(conn) {
uint16_t port = 0;
@@ -242,7 +238,7 @@ namespace ZeroTier {
void picoTCP::pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s)
{
DEBUG_INFO();
Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
if(!conn) {
DEBUG_ERROR("invalid connection");
@@ -276,10 +272,10 @@ namespace ZeroTier {
{
DEBUG_INFO();
// TODO: Test API out of order so this check isn't necessary
if(!(SocketTap*)((Larg*)(s->priv)))
if(!(SocketTap*)((ConnectionPair*)(s->priv)))
return;
SocketTap *tap = (SocketTap*)((Larg*)(s->priv))->tap;
Connection *conn = (Connection*)((Larg*)(s->priv))->conn;
SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap;
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
int err;
Mutex::Lock _l(tap->_tcpconns_m);
@@ -289,12 +285,17 @@ namespace ZeroTier {
// accept()
if (ev & PICO_SOCK_EV_CONN) {
if(conn->state == ZT_SOCK_STATE_LISTENING)
{
uint32_t peer;
uint16_t port;
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));
if(pico_err == PICO_ERR_EINVAL)
DEBUG_ERROR("pico_err = PICO_ERR_EINVAL");
if(pico_err == PICO_ERR_EAGAIN)
DEBUG_ERROR("pico_err = PICO_ERR_EAGAIN");
return;
}
// Create a new Connection and add it to the queue,
@@ -304,67 +305,59 @@ namespace ZeroTier {
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);
newConn->picosock->priv = new ConnectionPair(tap,newConn);
tap->_Connections.push_back(newConn);
conn->_AcceptedConnections.push(newConn);
// For I/O loop participation and referencing the PhySocket's parent Connection in callbacks
newConn->sock = tap->_phy.wrapSocket(newConn->sdk_fd, newConn);
}
if(conn->state != ZT_SOCK_STATE_LISTENING) {
// set state so blocking socket multiplexer logic will pick this up
conn->state = ZT_SOCK_STATE_UNHANDLED_CONNECTED;
}
}
if (ev & PICO_SOCK_EV_FIN) {
DEBUG_INFO("socket closed. exit normally. picosock=%p\n\n", s);
DEBUG_INFO("socket closed. exit normally. picosock=%p", s);
//pico_timer_add(2000, compare_results, NULL);
}
if (ev & PICO_SOCK_EV_ERR) {
DEBUG_INFO("socket error received" /*, strerror(pico_err)*/);
if(pico_err == PICO_ERR_ECONNRESET) {
DEBUG_ERROR("PICO_ERR_ECONNRESET");
conn->state = PICO_ERR_ECONNRESET;
}
DEBUG_INFO("socket error received pico_err=%d, picosock=%p", pico_err, s);
}
if (ev & PICO_SOCK_EV_CLOSE) {
err = pico_socket_close(s);
DEBUG_INFO("socket closure = %d, picosock=%p", err, s);
if(err==0) {
tap->closeConnection(conn->sock);
}
if(err==0)
tap->Close(conn);
return;
}
// Read from picoTCP socket
if (ev & PICO_SOCK_EV_RD) {
if(conn->socket_type==SOCK_STREAM)
pico_cb_tcp_read(picotap, s);
pico_cb_tcp_read(tap, s);
if(conn->socket_type==SOCK_DGRAM)
pico_cb_udp_read(picotap, s);
pico_cb_udp_read(tap, s);
}
// Write to picoTCP socket
if (ev & PICO_SOCK_EV_WR)
pico_cb_tcp_write(picotap, s);
pico_cb_tcp_write(tap, s);
}
// Called when an incoming ping is received
/*
static void pico_cb_ping(struct pico_icmp4_stats *s)
{
DEBUG_INFO();
char host[30];
pico_ipv4_to_string(host, s->dst.addr);
if (s->err == 0) {
printf("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size,
host, s->seq, s->ttl, (long unsigned int)s->time);
} else {
printf("PING %lu to %s: Error %d\n", s->seq, host, s->err);
}
}
*/
int pico_eth_send(struct pico_device *dev, void *buf, int len)
{
DEBUG_INFO();
SocketTap *tap = (SocketTap*)(dev->tap);
struct pico_eth_hdr *ethhdr;
ethhdr = (struct pico_eth_hdr *)buf;
MAC src_mac;
MAC dest_mac;
src_mac.setTo(ethhdr->saddr, 6);
dest_mac.setTo(ethhdr->daddr, 6);
picotap->_handler(picotap->_arg,NULL,picotap->_nwid,src_mac,dest_mac,
tap->_handler(tap->_arg,NULL,tap->_nwid,src_mac,dest_mac,
Utils::ntoh((uint16_t)ethhdr->proto),0, ((char*)buf) + sizeof(struct pico_eth_hdr),len - sizeof(struct pico_eth_hdr));
return len;
}
@@ -372,7 +365,6 @@ 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);
@@ -385,85 +377,50 @@ namespace ZeroTier {
int newlen = len + sizeof(int) + sizeof(struct pico_eth_hdr);
int mylen;
// FIXME
while(newlen > (MAX_PICO_FRAME_RX_BUF_SZ-tap->pico_frame_rxbuf_tot) && ethhdr.proto == 56710)
{
mylen = 0;
//DEBUG_FLOW(" [ ZTWIRE -> FBUF ] not enough space left on RX frame buffer, dropping oldest packet in buffer");
/*
memcpy(&mylen, picotap->pico_frame_rxbuf, sizeof(len));
memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + mylen, MAX_PICO_FRAME_RX_BUF_SZ-mylen); // shift buffer
picotap->pico_frame_rxbuf_tot-=mylen;
*/
memset(tap->pico_frame_rxbuf,0,MAX_PICO_FRAME_RX_BUF_SZ);
picotap->pico_frame_rxbuf_tot=0;
tap->pico_frame_rxbuf_tot=0;
}
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot, &newlen, sizeof(newlen)); // size of frame + meta
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen), &ethhdr, sizeof(ethhdr)); // new eth header
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen) + sizeof(ethhdr), data, len); // frame data
tap->pico_frame_rxbuf_tot += newlen;
DEBUG_FLOW(" [ ZTWIRE -> FBUF ] Move FRAME(sz=%d) into FBUF(sz=%d), data_len=%d", newlen, picotap->pico_frame_rxbuf_tot, len);
DEBUG_FLOW(" [ ZWIRE -> FBUF ] Move FRAME(sz=%d) into FBUF(sz=%d), data_len=%d", newlen, tap->pico_frame_rxbuf_tot, len);
}
int pico_eth_poll(struct pico_device *dev, int loop_score)
{
// OPTIMIZATION: The copy logic and/or buffer structure should be reworked for better performance after the BETA
SocketTap *tap = (SocketTap*)(dev->tap);
// FIXME: 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);
Mutex::Lock _l(tap->_pico_frame_rxbuf_m);
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);
int err;
while (tap->pico_frame_rxbuf_tot > 0 && loop_score > 0) {
//DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", tap->pico_frame_rxbuf_tot);
memset(frame, 0, sizeof(frame));
len = 0;
memcpy(&len, picotap->pico_frame_rxbuf, sizeof(len)); // get frame len
memcpy(&len, tap->pico_frame_rxbuf, sizeof(len)); // get frame len
if(len >= 0) {
//DEBUG_FLOW(" [ FBUF -> STACK] Moving FRAME of size (%d) from FBUF(sz=%d) into stack",len, picotap->pico_frame_rxbuf_tot-len);
memcpy(frame, picotap->pico_frame_rxbuf + sizeof(len), len-(sizeof(len)) ); // get frame data
memmove(picotap->pico_frame_rxbuf, picotap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer
pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(len)));
picotap->pico_frame_rxbuf_tot-=len;
//DEBUG_FLOW(" [ FBUF -> STACK] Moving FRAME of size (%d) from FBUF(sz=%d) into stack",len, tap->pico_frame_rxbuf_tot-len);
memcpy(frame, tap->pico_frame_rxbuf + sizeof(len), len-(sizeof(len)) ); // get frame data
memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer
err = pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(len)));
tap->pico_frame_rxbuf_tot-=len;
}
else {
DEBUG_ERROR("Invalid frame size (%d). Exiting.",len);
exit(0);
zt_dump_stacktrace(0);
}
loop_score--;
}
return loop_score;
}
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 < 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;
}
// adjust buffer
int sz = (conn->txsz)-r;
if(sz)
memmove(&conn->txbuf, (conn->txbuf+r), sz);
conn->txsz -= r;
if(conn->socket_type == SOCK_STREAM) {
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 = 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);
}
}
int picoTCP::pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{
int err;
@@ -483,8 +440,8 @@ namespace ZeroTier {
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));
err = pico_socket_connect(conn->picosock, &zaddr, (struct sockaddr_in *)&addr->sin_port);
DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port));
err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port);
#endif
memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage));
@@ -516,7 +473,7 @@ namespace ZeroTier {
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);
err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)in6->sin6_port);
#endif
if(err < 0) {
DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), err);
@@ -546,16 +503,17 @@ namespace ZeroTier {
if((err = pico_socket_listen(conn->picosock, backlog)) < 0)
{
if(err == PICO_ERR_EINVAL) {
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
DEBUG_ERROR("PICO_ERR_EINVAL");
errno = EINVAL;
return -1;
}
if(err == PICO_ERR_EISCONN) {
DEBUG_ERROR("PICO_ERR_EISCONN - socket is connected");
DEBUG_ERROR("PICO_ERR_EISCONN");
errno = EISCONN;
return -1;
}
}
conn->state = ZT_SOCK_STATE_LISTENING;
return ZT_ERR_OK;
}
@@ -574,17 +532,17 @@ namespace ZeroTier {
return err;
}
void picoTCP::pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked)
void picoTCP::pico_Read(SocketTap *tap, PhySocket *sock, void **uptr, bool stack_invoked)
{
DEBUG_INFO();
if(!lwip_invoked) {
if(!stack_invoked) {
// The stack thread writes to RXBUF as well
picotap->_tcpconns_m.lock();
picotap->_rx_buf_m.lock();
tap->_tcpconns_m.lock();
tap->_rx_buf_m.lock();
}
int tot = 0, n = -1, write_attempts = 0;
Connection *conn = picotap->getConnection(sock);
Connection *conn = (Connection*)uptr;
if(conn && conn->rxsz) {
//
@@ -592,7 +550,7 @@ namespace ZeroTier {
// 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, ZT_SDK_MTU);
n = tap->_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
@@ -620,7 +578,7 @@ namespace ZeroTier {
//
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);
n = tap->_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);
conn->rxsz -= n;
@@ -636,37 +594,67 @@ namespace ZeroTier {
#endif
}
if(conn->rxsz == 0) {
picotap->_phy.setNotifyWritable(sock, false);
tap->_phy.setNotifyWritable(sock, false);
}
else {
picotap->_phy.setNotifyWritable(sock, true);
tap->_phy.setNotifyWritable(sock, true);
}
}
else {
picotap->_phy.setNotifyWritable(sock, false);
tap->_phy.setNotifyWritable(sock, false);
}
}
if(!lwip_invoked) {
picotap->_tcpconns_m.unlock();
picotap->_rx_buf_m.unlock();
if(!stack_invoked) {
tap->_tcpconns_m.unlock();
tap->_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)
void picoTCP::pico_Write(Connection *conn)
{
DEBUG_INFO();
/*
int ret;
if(conn && conn->picosock) {
if((ret = pico_socket_close(conn->picosock)) < 0) {
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock));
// sendReturnValue()
}
if(!conn || !conn->picosock) {
DEBUG_ERROR(" invalid connection");
return;
}
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;
}
// adjust buffer
int sz = (conn->txsz)-r;
if(sz)
memmove(&conn->txbuf, (conn->txbuf+r), sz);
conn->txsz -= r;
if(conn->socket_type == SOCK_STREAM) {
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 = 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);
}
}
int picoTCP::pico_Close(Connection *conn)
{
DEBUG_INFO();
int err;
if(conn && conn->picosock) {
if((err = pico_socket_close(conn->picosock)) < 0) {
errno = pico_err;
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock));
return -1;
}
return err;
}
DEBUG_ERROR("invalid connection or pico_socket");
*/
return -1;
}
}

View File

@@ -32,7 +32,7 @@
#include "SocketTap.hpp"
/****************************************************************************/
/* PicoTCP API Signatures */
/* PicoTCP API Signatures (See ZeroTierSDK.h for the API an app should use) */
/****************************************************************************/
#define PICO_IPV4_TO_STRING_SIG char *ipbuf, const uint32_t ip
@@ -100,19 +100,44 @@ namespace ZeroTier
static void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s);
/*
* Where packets enter the stack
* Packets from the ZeroTier virtual wire enter the stack here
*/
void pico_rx(SocketTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len);
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
/*
* Connect to remote host via userspace network stack interface - Called from SocketTap
*/
int pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
/*
* Bind to a userspace network stack interface - Called from SocketTap
*/
int pico_Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
/*
* Listen for incoming connections - Called from SocketTap
*/
int pico_Listen(Connection *conn, int fd, int backlog);
/*
* Accept an incoming connection - Called from SocketTap
*/
int pico_Accept(Connection *conn);
/*
* Read from RX buffer to application - Called from SocketTap
*/
void pico_Read(SocketTap *tap, ZeroTier::PhySocket *sock,void **uptr,bool stack_invoked);
/*
* Write to userspace network stack - Called from SocketTap
*/
void pico_Write(Connection *conn);
/*
* Close a Connection - Called from SocketTap
*/
int pico_Close(Connection *conn);
};
}

View File

@@ -5,6 +5,7 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int atoi(const char *str);
int close(int filedes);
@@ -14,7 +15,7 @@ int close(int filedes);
int main(int argc , char *argv[])
{
if(argc < 3) {
printf("usage: client <addr> <port>\n");
printf("usage: client <addr> <port> <single|multiple> <n?>\n");
return 1;
}
@@ -37,7 +38,7 @@ int main(int argc , char *argv[])
}
printf("connected\n");
char *msg = "welcome to the machine!";
char *msg = (char*)"welcome to the machine!";
while(1)
{

View File

@@ -20,7 +20,7 @@ int main(int argc, char *argv[]) {
char buffer[256] = "This is a string from client!";
if (argc < 3) {
fprintf(stderr, "Usage: %s \n", argv[0]);
printf("Usage: %s \n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
@@ -30,12 +30,12 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: socket()
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
printf("ERROR opening socket");
//Sockets Layer Call: gethostbyname2()
server = gethostbyname2(argv[1],AF_INET6);
if (server == NULL) {
fprintf(stderr, "ERROR, no such host\n");
printf("ERROR, no such host\n");
exit(0);
}
@@ -47,13 +47,13 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: connect()
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("ERROR connecting");
//Sockets Layer Call: send()
n = send(sockfd,buffer, strlen(buffer)+1, 0);
if (n < 0)
error("ERROR writing to socket");
printf("ERROR writing to socket");
printf("sent %d bytes\n", n);
memset(buffer, 0, 256);
@@ -62,7 +62,7 @@ int main(int argc, char *argv[]) {
printf("reading...\n");
n = recv(sockfd, buffer, 255, 0);
if (n < 0)
error("ERROR reading from socket");
printf("ERROR reading from socket");
printf("Message from server: %s\n", buffer);
//Sockets Layer Call: close()

View File

@@ -48,14 +48,16 @@ int main(int argc , char *argv[])
{
count++;
int bytes_read = read(client_sock, client_message, msglen);
printf("[%lu] RX = (%d): ", count, bytes_read);
printf("[%lu] RX = (%d): %s\n", count, bytes_read, client_message);
/*
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);
//int bytes_written = write(client_sock, "Server here!", 12);
//printf("\t\nTX = %d\n", bytes_written);
}
return 0;
}

View File

@@ -24,7 +24,7 @@ int main(int argc, char *argv[]) {
char client_addr_ipv6[100];
if (argc < 2) {
fprintf(stderr, "Usage: %s \n", argv[0]);
printf("Usage: %s \n", argv[0]);
exit(0);
}
@@ -33,7 +33,7 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: socket()
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
printf("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: bind()
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
printf("ERROR on binding");
//Sockets Layer Call: listen()
listen(sockfd, 5);
@@ -54,7 +54,7 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: accept()
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
printf("ERROR on accept");
//Sockets Layer Call: inet_ntop()
inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100);
@@ -65,7 +65,7 @@ int main(int argc, char *argv[]) {
//Sockets Layer Call: recv()
n = recv(newsockfd, buffer, 255, 0);
if (n < 0)
error("ERROR reading from socket");
printf("ERROR reading from socket");
printf("Message from client: %s\n", buffer);
@@ -73,7 +73,7 @@ int main(int argc, char *argv[]) {
printf("sending...\n");
n = send(newsockfd, "Server got your message", 23+1, 0);
if (n < 0)
error("ERROR writing to socket");
printf("ERROR writing to socket");
//Sockets Layer Call: close()
close(sockfd);

View File

@@ -41,12 +41,12 @@ int main(int argc, char **argv) {
/* socket: create the socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
error("ERROR opening socket");
printf("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);
printf("ERROR, no such host as %s\n", hostname);
exit(0);
}
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
serveraddr.sin_port = htons(portno);
/* get a message from the user */
char *msg = "A message to the server!\0";
char *msg = (char*)"A message to the server!";
fcntl(sock, F_SETFL, O_NONBLOCK);
long count = 0;
while(1)

554
test/unit/a.cpp Normal file
View File

@@ -0,0 +1,554 @@
// 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 "ZeroTierSDK.h"
#define PASSED 0
#define FAILED -1
std::string str = "welcome to the machine";
// [] random
// [OK] simple client ipv4
// [OK] simple server ipv4
// [?] simple client ipv6
// [?] simple server ipv6
// [OK] sustained client ipv4
// [OK] sustained server ipv4
// [?] sustained client ipv6
// [?] sustained server ipv6
// [] comprehensive client ipv4
// [] comprehensive server ipv6
// ---
// comprehensive client addr port
// comprehensive server port
// simple [4|6] client addr port
// simple [4|6] server port
/****************************************************************************/
/* SIMPLE CLIENT */
/****************************************************************************/
//
int ipv4_tcp_client_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
//
int ipv6_tcp_client_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SIMPLE SERVER */
/****************************************************************************/
//
int ipv4_tcp_server_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
//
int ipv6_tcp_server_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SUSTAINED CLIENT */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SUSTAINED SERVER */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* main */
/****************************************************************************/
int main(int argc , char *argv[])
{
if(argc < 3) {
printf("invalid arguments\n");
return 1;
}
int port;
struct hostent *server;
std::string protocol;
std::string mode;
struct sockaddr_in6 addr6;
struct sockaddr_in addr;
char *path = (char*)"./zt";
int n_seconds = 10;
int n_times = 10000;
std::string nwid = argv[1]; // "ebcd7a7e120f4492"
std::string type = argv[2]; // simple, sustained, comprehensive
// If we're performing a non-random test, join the network we want to test on
// and wait until the service initializes the SocketTap and provides an address
if(type == "simple" || type == "sustained" || type == "comprehensive") {
zts_start(path);
while(!zts_service_running())
sleep(1);
zts_join_network(nwid.c_str());
while(!zts_has_address(nwid.c_str()))
sleep(1);
}
/****************************************************************************/
/* SIMPLE */
/****************************************************************************/
// SIMPLE
// performs a one-off test of a particular subset of the API
// For instance (ipv4 client, ipv6 server, etc)
if(type == "simple")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SIMPLE CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SIMPLE SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.40");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* SUSTAINED */
/****************************************************************************/
// SUSTAINED
// Performs a stress test for benchmarking performance
if(type == "sustained")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SUSTAINED CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SUSTAINED SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.0");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* COMPREHENSIVE */
/****************************************************************************/
// COMPREHENSIVE
// Tests ALL API calls
if(type == "comprehensive")
{
}
/****************************************************************************/
/* RANDOM */
/****************************************************************************/
// RANDOM
// performs random API calls with plausible (and random) arguments/data
if(type == "random")
{
}
printf("invalid configuration. exiting.\n");
return 0;
}

554
test/unit/b.cpp Normal file
View File

@@ -0,0 +1,554 @@
// 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 "ZeroTierSDK.h"
#define PASSED 0
#define FAILED -1
std::string str = "welcome to the machine";
// [] random
// [OK] simple client ipv4
// [OK] simple server ipv4
// [?] simple client ipv6
// [?] simple server ipv6
// [OK] sustained client ipv4
// [OK] sustained server ipv4
// [?] sustained client ipv6
// [?] sustained server ipv6
// [] comprehensive client ipv4
// [] comprehensive server ipv6
// ---
// comprehensive client addr port
// comprehensive server port
// simple [4|6] client addr port
// simple [4|6] server port
/****************************************************************************/
/* SIMPLE CLIENT */
/****************************************************************************/
//
int ipv4_tcp_client_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
//
int ipv6_tcp_client_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SIMPLE SERVER */
/****************************************************************************/
//
int ipv4_tcp_server_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
//
int ipv6_tcp_server_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SUSTAINED CLIENT */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SUSTAINED SERVER */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* main */
/****************************************************************************/
int main(int argc , char *argv[])
{
if(argc < 3) {
printf("invalid arguments\n");
return 1;
}
int port;
struct hostent *server;
std::string protocol;
std::string mode;
struct sockaddr_in6 addr6;
struct sockaddr_in addr;
char *path = (char*)"./zt";
int n_seconds = 10;
int n_times = 10000;
std::string nwid = argv[1]; // "ebcd7a7e120f4492"
std::string type = argv[2]; // simple, sustained, comprehensive
// If we're performing a non-random test, join the network we want to test on
// and wait until the service initializes the SocketTap and provides an address
if(type == "simple" || type == "sustained" || type == "comprehensive") {
zts_start(path);
while(!zts_service_running())
sleep(1);
zts_join_network(nwid.c_str());
while(!zts_has_address(nwid.c_str()))
sleep(1);
}
/****************************************************************************/
/* SIMPLE */
/****************************************************************************/
// SIMPLE
// performs a one-off test of a particular subset of the API
// For instance (ipv4 client, ipv6 server, etc)
if(type == "simple")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SIMPLE CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SIMPLE SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.40");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* SUSTAINED */
/****************************************************************************/
// SUSTAINED
// Performs a stress test for benchmarking performance
if(type == "sustained")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SUSTAINED CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SUSTAINED SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.0");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* COMPREHENSIVE */
/****************************************************************************/
// COMPREHENSIVE
// Tests ALL API calls
if(type == "comprehensive")
{
}
/****************************************************************************/
/* RANDOM */
/****************************************************************************/
// RANDOM
// performs random API calls with plausible (and random) arguments/data
if(type == "random")
{
}
printf("invalid configuration. exiting.\n");
return 0;
}

View File

@@ -1,64 +0,0 @@
// 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

@@ -1,64 +1,554 @@
// 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 "ZeroTierSDK.h"
#define PASSED 0
#define FAILED -1
std::string str = "welcome to the machine";
// [] random
// [OK] simple client ipv4
// [OK] simple server ipv4
// [?] simple client ipv6
// [?] simple server ipv6
// [OK] sustained client ipv4
// [OK] sustained server ipv4
// [?] sustained client ipv6
// [?] sustained server ipv6
// [] comprehensive client ipv4
// [] comprehensive server ipv6
// ---
// comprehensive client addr port
// comprehensive server port
// simple [4|6] client addr port
// simple [4|6] server port
/****************************************************************************/
/* Test Functions */
/* SIMPLE CLIENT */
/****************************************************************************/
int test_for_correctness()
//
int ipv4_tcp_client_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
return 0;
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
int ipv4_udp_server()
//
int ipv6_tcp_client_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
return 0;
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
int ipv6_udp_server()
/****************************************************************************/
/* SIMPLE SERVER */
/****************************************************************************/
//
int ipv4_tcp_server_test(char *path, char *nwid, struct sockaddr_in *addr, int port)
{
return 0;
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
int ipv4_tcp_server()
//
int ipv6_tcp_server_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port)
{
return 0;
int sockfd, err;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
int wrote = zts_write(sockfd, str.c_str(), str.length());
err = zts_close(sockfd);
return (wrote == str.length() && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
int ipv6_tcp_server()
/****************************************************************************/
/* SUSTAINED CLIENT */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
return 0;
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_client_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) {
printf("error connecting to remote host (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* SUSTAINED SERVER */
/****************************************************************************/
// Maintain transfer for n_seconds OR n_times
int ipv4_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
// Maintain transfer for n_seconds OR n_times
int ipv6_tcp_server_sustained_test(char *path, char *nwid, struct sockaddr_in6 *addr, int port, int n_seconds, int n_times)
{
int sockfd, err;
int msg_len = str.length();
int wrote = 0;
if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket");
exit(0);
}
if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
exit(0);
}
if((err = zts_listen(sockfd, 1)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
exit(0);
}
// TODO: handle new address
if((err = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)) < 0)) {
printf("error accepting connection (%d)\n", err);
exit(0);
}
if(n_seconds) {
/*
printf("testing for (%d) seconds\n", n_seconds);
int wrote;
for(int i=0; i<n_seconds; i++) {
wrote = zts_write(sockfd, str.c_str(), str.length());
printf("wrote = %d\n", wrote);
}
*/
}
if(n_times) {
printf("testing (%d) times\n", n_seconds);
for(int i=0; i<n_times; i++) {
wrote += zts_write(sockfd, str.c_str(), str.length());
printf("[%d] wrote = %d\n", i, wrote);
}
}
err = zts_close(sockfd);
return (wrote == (str.length()*n_times) && !err) ? PASSED : FAILED; // if wrote correct number of bytes
}
/****************************************************************************/
/* main */
/****************************************************************************/
int main()
int main(int argc , char *argv[])
{
int test_all = 1;
if(test_all)
{
printf("Testing API calls for correctness\n");
test_for_correctness();
printf("Testing as IPv4 UDP Server\n");
ipv4_udp_server();
printf("Testing as IPv6 UDP Server\n");
ipv6_udp_server();
printf("Testing as IPv4 TCP Server\n");
ipv4_udp_server();
printf("Testing as IPv6 TCP Server\n");
ipv6_udp_server();
printf("Testing \n");
printf("\n");
printf("\n");
if(argc < 3) {
printf("invalid arguments\n");
return 1;
}
int port;
struct hostent *server;
std::string protocol;
std::string mode;
struct sockaddr_in6 addr6;
struct sockaddr_in addr;
char *path = (char*)"./zt";
int n_seconds = 10;
int n_times = 10000;
std::string nwid = argv[1]; // "ebcd7a7e120f4492"
std::string type = argv[2]; // simple, sustained, comprehensive
// If we're performing a non-random test, join the network we want to test on
// and wait until the service initializes the SocketTap and provides an address
if(type == "simple" || type == "sustained" || type == "comprehensive") {
zts_start(path);
while(!zts_service_running())
sleep(1);
zts_join_network(nwid.c_str());
while(!zts_has_address(nwid.c_str()))
sleep(1);
}
/****************************************************************************/
/* SIMPLE */
/****************************************************************************/
// SIMPLE
// performs a one-off test of a particular subset of the API
// For instance (ipv4 client, ipv6 server, etc)
if(type == "simple")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SIMPLE CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SIMPLE SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.40");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_test(path, (char*)nwid.c_str(), &addr, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_test(path, (char*)nwid.c_str(), &addr6, port) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* SUSTAINED */
/****************************************************************************/
// SUSTAINED
// Performs a stress test for benchmarking performance
if(type == "sustained")
{
protocol = argv[3]; // 4, 6
mode = argv[4]; // client, server
// SUSTAINED CLIENT
if(mode == "client")
{
port = atoi(argv[6]);
printf("connecting to %s on port %s\n", argv[5], argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(argv[5]);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
addr6.sin6_port = htons(port);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_client_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
// SUSTAINED SERVER
if(mode == "server")
{
port = atoi(argv[5]);
printf("serving on port %s\n", argv[6]);
// IPv4
if(protocol == "4") {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("10.9.9.0");
// addr.sin_addr.s_addr = htons(INADDR_ANY);
addr.sin_family = AF_INET;
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv4_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
// IPv6
if(protocol == "6") {
server = gethostbyname2(argv[1],AF_INET6);
memset((char *) &addr6, 0, sizeof(addr6));
addr6.sin6_flowinfo = 0;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
//memmove((char *) &addr6.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length);
printf(" running (%s) test as ipv=%s\n", mode.c_str(), protocol.c_str());
if(ipv6_tcp_server_sustained_test(path, (char*)nwid.c_str(), &addr6, port, n_seconds, n_times) == PASSED)
printf("PASSED\n");
else
printf("FAILED\n");
return 0;
}
}
}
/****************************************************************************/
/* COMPREHENSIVE */
/****************************************************************************/
// COMPREHENSIVE
// Tests ALL API calls
if(type == "comprehensive")
{
}
/****************************************************************************/
/* RANDOM */
/****************************************************************************/
// RANDOM
// performs random API calls with plausible (and random) arguments/data
if(type == "random")
{
}
printf("invalid configuration. exiting.\n");
return 0;
}

View File

@@ -1,64 +0,0 @@
// Comprehensive stress test for socket-like API
#include <stdio.h>
/****************************************************************************/
/* Test Functions */
/****************************************************************************/
int test_for_correctness()
{
return 0;
}
int ipv4_udp_server()
{
return 0;
}
int ipv6_udp_server()
{
return 0;
}
int ipv4_tcp_server()
{
return 0;
}
int ipv6_tcp_server()
{
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 Server\n");
ipv4_udp_server();
printf("Testing as IPv6 UDP Server\n");
ipv6_udp_server();
printf("Testing as IPv4 TCP Server\n");
ipv4_udp_server();
printf("Testing as IPv6 TCP Server\n");
ipv6_udp_server();
printf("Testing \n");
printf("\n");
printf("\n");
}
return 0;
}

View File

@@ -52,12 +52,11 @@ int main()
printf("waiting for service to issue an address\n");
sleep(1);
}
// Begin Socket API calls
int err;
int sockfd;
int port = 5555;
int port = 7878;
struct sockaddr_in addr;
// socket()
@@ -69,7 +68,7 @@ int main()
// connect() IPv6
if(false)
{
struct hostent *server = gethostbyname2("fde5:cd7a:9e1c:fd2:7299:932e:e35a:9a03",AF_INET6);
struct hostent *server = gethostbyname2("fde5:cd7a:9e1c:0fd2:7299:9367:5993:3b86",AF_INET6);
struct sockaddr_in6 serv_addr;
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin6_flowinfo = 0;
@@ -91,6 +90,10 @@ int main()
printf("error connecting to remote host (%d)\n", err);
return -1;
}
zts_write(sockfd, "hello", 5);
sleep(3);
zts_close(sockfd);
}
// bind() ipv4
if(false)
@@ -129,12 +132,12 @@ int main()
printf("peer_count = %lu\n", zts_get_peer_count());
/*
while(1)
{
sleep(1);
}
*/
// ---

View File

@@ -1003,9 +1003,14 @@ public:
Mutex::Lock _l(_nets_m);
std::map<uint64_t,NetworkState>::iterator it;
for(it = _nets.begin(); it != _nets.end(); it++) {
printf("TEEEESTING....\n");
if(it->second.tap) {
printf("\tips = %d\n", it->second.tap->_ips.size());
for(int j=0; j<it->second.tap->_ips.size(); j++) {
printf("\tTESTING: %s\n", it->second.tap->_ips[j].toString().c_str());
printf("\t\tdoesn't contain: %s\n", addr.toString().c_str());
if(it->second.tap->_ips[j].containsAddress(addr)) {
return it->second.tap;
}
}