improved testing and connection handling
This commit is contained in:
40
README.md
40
README.md
@@ -1,15 +1,51 @@
|
||||
ZeroTier SDK
|
||||
======
|
||||
|
||||
[](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
3
api/clojure/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Clojure Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
3
api/go/README.md
Normal file
3
api/go/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Go Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
@@ -19,6 +19,7 @@ struct pico_ethdev {
|
||||
};
|
||||
|
||||
struct pico_device {
|
||||
void *tap;
|
||||
char name[MAX_DEVICE_NAME];
|
||||
uint32_t hash;
|
||||
uint32_t overhead;
|
||||
|
||||
@@ -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...)
|
||||
|
||||
@@ -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:
|
||||
|
||||
16
make-mac.mk
16
make-mac.mk
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
84
src/Utils.cpp
Normal 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
27
src/Utils.hpp
Normal 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
|
||||
@@ -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(;;) {
|
||||
|
||||
238
src/picoTCP.cpp
238
src/picoTCP.cpp
@@ -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), ðhdr, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
554
test/unit/a.cpp
Normal 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
554
test/unit/b.cpp
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user