From 142c27091cb9df3d173a409cf501546ba24fbc95 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 5 Sep 2017 16:51:07 -0700 Subject: [PATCH] Added new unit tests and time-sync code for subtests, recvfrom() fixes --- FAQ.md | 10 + include/libzt.h | 16 +- make-linux.mk | 18 +- make-mac.mk | 19 +- src/libzt.cpp | 180 +++- src/lwIP.cpp | 116 ++- src/lwIP.hpp | 86 +- src/picoTCP.cpp | 22 +- test/generate_test_env.sh | 32 - test/selftest.cpp | 1898 ++++++++++++++++++++++++------------- test/stop.sh | 16 - 11 files changed, 1584 insertions(+), 829 deletions(-) create mode 100644 FAQ.md delete mode 100755 test/generate_test_env.sh delete mode 100755 test/stop.sh diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..5ea0d19 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,10 @@ +## Frequently Asked Questions +*** + +### Can I use this in my commercial or closed-source application or service? + +Yes! - Just let us know, and we will work out a licensing scheme. You will need to build the library with the `lwIP` network stack. In the case that you're a non-profit, or are developing open source software, you can use this entirely for free and may choose either `picoTCP` or `lwIP` as your network stack. + +### Application or service won't fully come online + +Sometimes it can take a substatial amount of time for libzt to come online and become reachable. In cases where it never seems to progress beyond this stage you should check to make sure there are no rogue processes on the machines using the same ZeroTier identity files, or no other instances on your ZeroTier network using said identity files. If this doesn't help. Contact us. \ No newline at end of file diff --git a/include/libzt.h b/include/libzt.h index 6300ad6..5c4f70a 100644 --- a/include/libzt.h +++ b/include/libzt.h @@ -85,17 +85,27 @@ struct zts_ifreq { #endif /****************************************************************************/ -/* LWIP */ +/* lwIP */ /****************************************************************************/ +#if defined(STACK_LWIP) #define LWIP_APPLICATION_POLL_FREQ 2 #define LWIP_TCP_TIMER_INTERVAL 50 #define LWIP_STATUS_TMR_INTERVAL 500 // How often we check VirtualSocket statuses (in ms) +#endif + +/****************************************************************************/ +/* picoTCP */ +/****************************************************************************/ + +#if defined(STACK_PICO) +#endif /****************************************************************************/ /* Defines */ /****************************************************************************/ +#define ZT_MAX_SOCKETS 1024 #define ZT_SDK_MTU ZT_MAX_MTU #define ZT_LEN_SZ 4 #define ZT_ADDR_SZ 128 @@ -206,7 +216,6 @@ struct zts_ifreq { /****************************************************************************/ /* SDK Socket API (ZeroTier Service Controls) */ -/* Implemented in libzt.cpp */ /****************************************************************************/ #ifdef __cplusplus @@ -341,9 +350,8 @@ void zts_disable_http_control_plane(); /****************************************************************************/ /* SDK Socket API (Socket User Controls) */ -/* - These functions are designed to work just like regular socket calls */ +/* - These functions are designed to work just like ordinary socket calls */ /* but are provisioned and handled by ZeroTier */ -/* Implemented in Socket.c */ /****************************************************************************/ /** diff --git a/make-linux.mk b/make-linux.mk index 8ff44a8..675c0c3 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -249,20 +249,26 @@ UNIT_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_F UNIT_TEST_INCLUDES := -Iinclude UNIT_TEST_LIBS := -L$(BUILD) -lzt $(COMMON_LIBS) -$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp - @mkdir -p $(TEST_BUILD_DIR) - @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) - @./check.sh $@ +#$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp +# @mkdir -p $(TEST_BUILD_DIR) +# @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) +# @./check.sh $@ -tests: $(UNIT_TEST_OBJ_FILES) +tests: selftest nativetest ztproxy intercept intercept: @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) examples/intercept/intercept.cpp -D_GNU_SOURCE -shared -o $(BUILD)/intercept.so $< $(UNIT_TEST_LIBS) -ldl @./check.sh $(BUILD)/intercept.so - ztproxy: @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) examples/ztproxy/ztproxy.cpp -o $(BUILD)/ztproxy $< $(UNIT_TEST_LIBS) -ldl @./check.sh $(BUILD)/ztproxy +selftest: + @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) test/selftest.cpp -D__SELFTEST__ -o $(BUILD)/selftest $(UNIT_TEST_LIBS) + @./check.sh $(BUILD)/selftest +nativetest: + @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) test/selftest.cpp -D__NATIVETEST__ -o $(BUILD)/nativetest + @./check.sh $(BUILD)/nativetest + ############################################################################## ## Misc ## diff --git a/make-mac.mk b/make-mac.mk index cfc4a29..abeaa2d 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -261,20 +261,25 @@ UNIT_TEST_OBJ_FILES := $(addprefix $(TEST_BUILD_DIR)/,$(notdir $(UNIT_TEST_SRC_F UNIT_TEST_INCLUDES := -Iinclude UNIT_TEST_LIBS := -L$(BUILD) -lzt -$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp - @mkdir -p $(TEST_BUILD_DIR) - @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) - @./check.sh $@ +#$(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp +# @mkdir -p $(TEST_BUILD_DIR) +# @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) +# @./check.sh $@ -tests: $(UNIT_TEST_OBJ_FILES) +tests: selftest nativetest ztproxy intercept intercept: - @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) examples/intercept/intercept.cpp -D_GNU_SOURCE -shared -o $(BUILD)/intercept.so $< $(UNIT_TEST_LIBS) -ldl + @$(CXX) $(CXXFLAGS) -fPIE $(UNIT_TEST_INCLUDES) examples/intercept/intercept.cpp -D_GNU_SOURCE -shared -o $(BUILD)/intercept.so $< $(UNIT_TEST_LIBS) -ldl @./check.sh $(BUILD)/intercept.so - ztproxy: @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) examples/ztproxy/ztproxy.cpp -o $(BUILD)/ztproxy $< $(UNIT_TEST_LIBS) -ldl @./check.sh $(BUILD)/ztproxy +selftest: + @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) test/selftest.cpp -D__SELFTEST__ -o $(BUILD)/selftest $(UNIT_TEST_LIBS) + @./check.sh $(BUILD)/selftest +nativetest: + @$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) test/selftest.cpp -D__NATIVETEST__ -o $(BUILD)/nativetest + @./check.sh $(BUILD)/nativetest ############################################################################## ## Misc ## diff --git a/src/libzt.cpp b/src/libzt.cpp index 5b906c0..8d2204e 100644 --- a/src/libzt.cpp +++ b/src/libzt.cpp @@ -500,9 +500,8 @@ Linux: int zts_connect(ZT_CONNECT_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - DEBUG_ERROR("EBADF"); return -1; } if(!ZeroTier::zt1Service) { @@ -516,6 +515,19 @@ int zts_connect(ZT_CONNECT_SIG) { errno = EBADF; return -1; } + if(!addr) { + DEBUG_ERROR("invalid address for fd=%d", fd); + errno = EINVAL; + return -1; + } + if(addrlen <= 0) { + DEBUG_ERROR("invalid address length for fd=%d", fd); + errno = EINVAL; + return -1; + } + // TODO: Handle bad address lengths, right now this call will still + // succeed with a complete connect despite a bad address length. + // DEBUG_EXTRA("fd = %d, %s : %d", fd, ipstr, ntohs(port)); ZeroTier::InetAddress inet; sockaddr2inet(vs->socket_family, addr, &inet); @@ -618,7 +630,7 @@ Darwin: */ int zts_bind(ZT_BIND_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } @@ -707,7 +719,7 @@ Linux: */ int zts_listen(ZT_LISTEN_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } @@ -754,7 +766,7 @@ Darwin: int zts_accept(ZT_ACCEPT_SIG) { int err = errno = 0; //DEBUG_EXTRA("fd=%d", fd); - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } @@ -857,7 +869,7 @@ EPERM Firewall rules forbid VirtualSocket. { errno = 0; //DEBUG_INFO("fd=%d", fd); - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } @@ -888,9 +900,9 @@ int zts_setsockopt(ZT_SETSOCKOPT_SIG) int err = errno = 0; #if defined(STACK_PICO) //DEBUG_INFO("fd=%d", fd); - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } // Disable Nagle's algorithm struct pico_socket *p = NULL; @@ -926,9 +938,9 @@ int zts_setsockopt(ZT_SETSOCKOPT_SIG) int zts_getsockopt(ZT_GETSOCKOPT_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } err = getsockopt(fd, level, optname, optval, optlen); return err; @@ -945,9 +957,9 @@ int zts_getsockopt(ZT_GETSOCKOPT_SIG) int zts_getsockname(ZT_GETSOCKNAME_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } // TODO return err; @@ -968,9 +980,9 @@ Linux: int zts_getpeername(ZT_GETPEERNAME_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); if(!vs) { @@ -1037,8 +1049,7 @@ Linux / Darwin: int zts_close(ZT_CLOSE_SIG) { int err = errno = 0; - //DEBUG_EXTRA("fd=%d", fd); - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } @@ -1096,9 +1107,9 @@ int zts_select(ZT_SELECT_SIG) int zts_fcntl(ZT_FCNTL_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } else { err = fcntl(fd, cmd, flags); @@ -1116,9 +1127,9 @@ int zts_fcntl(ZT_FCNTL_SIG) int zts_ioctl(ZT_IOCTL_SIG) { int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } else { #if defined(__linux__) @@ -1190,15 +1201,30 @@ Linux: [ ] [EPIPE] The local end has been shut down on a VirtualSocket oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set. + ZT_SENDTO_SIG int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen */ + ssize_t zts_sendto(ZT_SENDTO_SIG) { - DEBUG_TRANS("fd=%d", fd); + //DEBUG_TRANS("fd=%d", fd); int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } + if(len == 0) { + return 0; + } + if(len > ZT_SOCKET_MSG_BUF_SZ) { + DEBUG_ERROR("msg is too long to be sent atomically (len=%d)", len); + errno = EMSGSIZE; + return -1; + } + if(!buf) { + DEBUG_ERROR("msg buf is null"); + errno = EINVAL; + return -1; + } ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); if(!vs) { DEBUG_ERROR("no vs found for fd=%x", fd); @@ -1308,11 +1334,26 @@ ssize_t zts_sendto(ZT_SENDTO_SIG) socket. In this case, the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set. + ZT_SEND_SIG int fd, const void *buf, size_t len, int flags */ + ssize_t zts_send(ZT_SEND_SIG) { - DEBUG_TRANS("fd=%d", fd); + // DEBUG_TRANS("fd=%d", fd); int err = errno = 0; + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { + errno = EBADF; + return -1; + } + if(len == 0) { + return 0; + } + if(len > ZT_SOCKET_MSG_BUF_SZ) { + DEBUG_ERROR("msg is too long to be sent atomically (len=%d)", len); + errno = EMSGSIZE; + return -1; + } + ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); if(!vs) { DEBUG_ERROR("invalid vs for fd=%d", fd); @@ -1381,9 +1422,9 @@ ssize_t zts_sendmsg(ZT_SENDMSG_SIG) { DEBUG_TRANS("fd=%d", fd); int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } else { err = sendmsg(fd, msg, flags); @@ -1414,7 +1455,10 @@ ssize_t zts_sendmsg(ZT_SENDMSG_SIG) [ ] ENOMEM Could not allocate memory for recvmsg(). [ ] ENOTCONN The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)). [ ] ENOTSOCK The file descriptor sockfd does not refer to a socket. + + ZT_RECV_SIG int fd, void *buf, size_t len, int flags */ + ssize_t zts_recv(ZT_RECV_SIG) { DEBUG_TRANS("fd=%d", fd); @@ -1502,47 +1546,85 @@ ssize_t zts_recv(ZT_RECV_SIG) [ ] [ENOTCONN] The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)). [ ] [ENOTSOCK] The argument sockfd does not refer to a socket. + + ZT_RECVFROM_SIG int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen */ + ssize_t zts_recvfrom(ZT_RECVFROM_SIG) { - DEBUG_TRANS("fd=%d", fd); + //DEBUG_TRANS("fd=%d", fd); int32_t r = 0; errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; return -1; } + if(len == 0) { + return 0; + } + if(!buf) { + DEBUG_ERROR("buf is null"); + errno = EINVAL; + return -1; + } char udp_msg_buf[ZT_SOCKET_MSG_BUF_SZ]; char *msg_ptr = udp_msg_buf; - r = read(fd, msg_ptr, sizeof(udp_msg_buf)); - if(r > 0) { - *addrlen = sizeof(struct sockaddr_storage); + memset(msg_ptr, 0, sizeof(int32_t)); // zero only len portion - // get message length - int32_t udp_msg_len = 0; - memcpy(&udp_msg_len, msg_ptr, sizeof(udp_msg_len)); - msg_ptr+=sizeof(int32_t); - - // get address - memcpy(addr, msg_ptr, *addrlen); - msg_ptr+=*addrlen; - - // get payload - int32_t payload_sz = udp_msg_len - *addrlen; - memcpy(buf, msg_ptr, payload_sz); - r = payload_sz; + int32_t udp_msg_len = 0; + + // PEEK at the buffer and see if we can read a length, if not, err out + r = recv(fd, msg_ptr, sizeof(int32_t), MSG_PEEK); + if(r != sizeof(int32_t)){ + //DEBUG_ERROR("invalid datagram, PEEK, r=%d", r); + errno = EIO; // TODO: test for this + return -1; } - return r; + // read of sizeof(int32_t) for the length of the datagram (including address) + r = read(fd, msg_ptr, sizeof(int32_t)); + // copy to length variable + memcpy(&udp_msg_len, msg_ptr, sizeof(int32_t)); + msg_ptr+=sizeof(int32_t); + + if(udp_msg_len <= 0) { + DEBUG_ERROR("invalid datagram"); + errno = EIO; // TODO: test for this + return -1; + } + // there is a datagram to read, so let's read it + // zero remainder of buffer + memset(msg_ptr, 0, ZT_SOCKET_MSG_BUF_SZ- sizeof(int32_t)); + if((r = read(fd, msg_ptr, udp_msg_len)) < 0) { + DEBUG_ERROR("invalid datagram"); + errno = EIO; // TODO: test for this + return -1; + } + // get address + if(addr) { + if(*addrlen < sizeof(struct sockaddr_storage)) { + DEBUG_ERROR("invalid address length provided"); + errno = EINVAL; + return -1; + } + *addrlen = sizeof(struct sockaddr_storage); + memcpy(addr, msg_ptr, *addrlen); + } + msg_ptr+=sizeof(struct sockaddr_storage); + // get payload + int32_t payload_sz = udp_msg_len - *addrlen; + int32_t write_sz = len < payload_sz ? len : payload_sz; + memcpy(buf, msg_ptr, write_sz); + return write_sz; } // TODO ssize_t zts_recvmsg(ZT_RECVMSG_SIG) { - DEBUG_TRANS("fd=%d", fd); + //DEBUG_TRANS("fd=%d", fd); int err = errno = 0; - if(fd < 0) { + if(fd < 0 || fd >= ZT_MAX_SOCKETS) { errno = EBADF; - err = -1; + return -1; } else { err = recvmsg(fd, msg, flags); @@ -1551,12 +1633,12 @@ ssize_t zts_recvmsg(ZT_RECVMSG_SIG) } int zts_read(ZT_READ_SIG) { - DEBUG_TRANS("fd=%d", fd); + //DEBUG_TRANS("fd=%d", fd); return read(fd, buf, len); } int zts_write(ZT_WRITE_SIG) { - DEBUG_TRANS("fd=%d", fd); + //DEBUG_TRANS("fd=%d", fd); return write(fd, buf, len); } diff --git a/src/lwIP.cpp b/src/lwIP.cpp index 9e999d8..89f694c 100644 --- a/src/lwIP.cpp +++ b/src/lwIP.cpp @@ -51,7 +51,6 @@ err_t tapif_init(struct netif *netif) err_t lwip_eth_tx(struct netif *netif, struct pbuf *p) { - DEBUG_INFO(); struct pbuf *q; char buf[ZT_MAX_MTU+32]; char *bufptr; @@ -76,6 +75,19 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p) tap->_handler(tap->_arg,NULL,tap->_nwid,src_mac,dest_mac, ZeroTier::Utils::ntoh((uint16_t)ethhdr->type),0,buf + sizeof(struct eth_hdr),totalLength - sizeof(struct eth_hdr)); + + if(ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { + char flagbuf[32]; + memset(&flagbuf, 0, 32); + char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; + mac2str(macBuf, ZT_MAC_ADDRSTRLEN, ethhdr->dest.addr); + ZeroTier::MAC mac; + mac.setTo(ethhdr->dest.addr, 6); + mac.toAddress(tap->_nwid).toString(nodeBuf); + DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] proto=0x%04x %s %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(), + ZeroTier::Utils::ntoh(ethhdr->type), beautify_eth_proto_nums(ZeroTier::Utils::ntoh(ethhdr->type)), flagbuf); + } + return ERR_OK; } @@ -89,7 +101,7 @@ namespace ZeroTier if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) { tap->_ips.push_back(ip); std::sort(tap->_ips.begin(),tap->_ips.end()); - char ipbuf[64], nmbuf[64]; + char ipbuf[INET6_ADDRSTRLEN], nmbuf[INET6_ADDRSTRLEN]; #if defined(LIBZT_IPV4) if (ip.isV4()) { // Set IP @@ -140,12 +152,22 @@ namespace ZeroTier } } + int lwIP::lwip_add_dns_nameserver(struct sockaddr *addr) + { + return -1; + } + + int lwIP::lwip_del_dns_nameserver(struct sockaddr *addr) + { + return -1; + } + void lwIP::lwip_loop(VirtualTap *tap) { - DEBUG_INFO(); - uint64_t prev_tcp_time = 0, prev_discovery_time = 0; - while(tap->_run) - { + // DEBUG_INFO(); + uint64_t prev_tcp_time = 0, prev_discovery_time = 0; + while(tap->_run) + { uint64_t now = OSUtils::now(); uint64_t since_tcp = now - prev_tcp_time; uint64_t since_discovery = now - prev_discovery_time; @@ -183,7 +205,6 @@ namespace ZeroTier void lwIP::lwip_eth_rx(VirtualTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) { - DEBUG_INFO("etherType=%x, len=%d", etherType, len); struct pbuf *p,*q; if (!tap->_enabled) return; @@ -211,6 +232,19 @@ namespace ZeroTier dataptr += q->len; } } + + if(ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { + char flagbuf[32]; + memset(&flagbuf, 0, 32); + char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; + mac2str(macBuf, ZT_MAC_ADDRSTRLEN, ethhdr.dest.addr); + ZeroTier::MAC mac; + mac.setTo(ethhdr.dest.addr, 6); + mac.toAddress(tap->_nwid).toString(nodeBuf); + DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), + ZeroTier::Utils::ntoh(ethhdr.type), beautify_eth_proto_nums(ZeroTier::Utils::ntoh(ethhdr.type)), flagbuf); + } + else { DEBUG_ERROR("dropped packet: no pbufs available"); return; @@ -260,7 +294,7 @@ namespace ZeroTier struct sockaddr_in *in4 = (struct sockaddr_in *)addr; if(addr->sa_family == AF_INET) { inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); - DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in4->sin_port)); + DEBUG_EXTRA("connecting to %s : %d", addrstr, lwip_ntohs(in4->sin_port)); } ba = convert_ip(in4); port = lwip_ntohs(in4->sin_port); @@ -271,36 +305,33 @@ namespace ZeroTier if(addr->sa_family == AF_INET6) { struct sockaddr_in6 *vsaddr6 = (struct sockaddr_in6 *)addr; inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in6->sin6_port)); + DEBUG_EXTRA("connecting to %s : %d", addrstr, lwip_ntohs(in6->sin6_port)); } #endif - - DEBUG_INFO("addr=%s", addrstr); - if(vs->socket_type == SOCK_DGRAM) { // Generates no network traffic if((err = udp_connect((struct udp_pcb*)vs->pcb,(ip_addr_t *)&ba,port)) < 0) { DEBUG_ERROR("error while connecting to with UDP"); } - udp_recv((struct udp_pcb*)vs->pcb, nc_udp_recved, vs); + udp_recv((struct udp_pcb*)vs->pcb, lwip_cb_udp_recved, vs); return ERR_OK; } if(vs->socket_type == SOCK_STREAM) { struct tcp_pcb *tpcb = (struct tcp_pcb*)vs->pcb; - tcp_sent(tpcb, nc_sent); - tcp_recv(tpcb, nc_recved); - tcp_err(tpcb, nc_err); - tcp_poll(tpcb, nc_poll, LWIP_APPLICATION_POLL_FREQ); + tcp_sent(tpcb, lwip_cb_sent); + tcp_recv(tpcb, lwip_cb_tcp_recved); + tcp_err(tpcb, lwip_cb_err); + tcp_poll(tpcb, lwip_cb_poll, LWIP_APPLICATION_POLL_FREQ); tcp_arg(tpcb, vs); //DEBUG_EXTRA(" pcb->state=%x", vs->TCP_pcb->state); //if(vs->TCP_pcb->state != CLOSED) { - // DEBUG_INFO(" cannot connect using this PCB, PCB!=CLOSED"); - // tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); - // return; + // DEBUG_INFO(" cannot connect using this PCB, PCB!=CLOSED"); + // tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); + // return; //} - if((err = tcp_connect(tpcb,&ba,port,nc_connected)) < 0) + if((err = tcp_connect(tpcb,&ba,port,lwip_cb_connected)) < 0) { if(err == ERR_ISCONN) { // Already in connected state @@ -334,7 +365,7 @@ namespace ZeroTier // that the SYN packet was enqueued onto the stack properly, // that's it! // - Most instances of a retval for a connect() should happen - // in the nc_connect() and nc_err() callbacks! + // in the nc_connect() and lwip_cb_err() callbacks! DEBUG_ERROR("unable to connect"); errno = EAGAIN; return -1; @@ -354,7 +385,7 @@ namespace ZeroTier struct sockaddr_in *in4 = (struct sockaddr_in *)addr; if(addr->sa_family == AF_INET) { inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); - DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in4->sin_port)); + DEBUG_EXTRA("binding to %s : %d", addrstr, lwip_ntohs(in4->sin_port)); } ba = convert_ip(in4); port = lwip_ntohs(in4->sin_port); @@ -365,7 +396,7 @@ namespace ZeroTier if(addr->sa_family == AF_INET6) { struct sockaddr_in6 *vsaddr6 = (struct sockaddr_in6 *)addr; inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in6->sin6_port)); + DEBUG_EXTRA("binding to %s : %d", addrstr, lwip_ntohs(in6->sin6_port)); } #endif if(vs->socket_type == SOCK_DGRAM) { @@ -376,7 +407,7 @@ namespace ZeroTier } else { // set the recv callback - udp_recv((struct udp_pcb*)vs->pcb, nc_udp_recved, new VirtualBindingPair(tap, vs)); + udp_recv((struct udp_pcb*)vs->pcb, lwip_cb_udp_recved, new VirtualBindingPair(tap, vs)); err = ERR_OK; errno = ERR_OK; // success } @@ -417,7 +448,7 @@ namespace ZeroTier #endif if(listeningPCB != NULL) { vs->pcb = listeningPCB; - tcp_accept(listeningPCB, nc_accept); // set callback + tcp_accept(listeningPCB, lwip_cb_accept); // set callback tcp_arg(listeningPCB, vs); //fcntl(tap->_phy.getDescriptor(vs->sock), F_SETFL, O_NONBLOCK); } @@ -446,7 +477,7 @@ namespace ZeroTier DEBUG_EXTRA("vs=%p", vs); int err = 0; if(!vs) { - DEBUG_ERROR("no VirtualSocket"); + DEBUG_ERROR("no virtual socket"); return -1; } if(!lwip_invoked) { @@ -487,14 +518,14 @@ namespace ZeroTier DEBUG_EXTRA("vs=%p, len=%d", (void*)&vs, len); int err = 0; if(!vs) { - DEBUG_ERROR("no VirtualSocket"); + DEBUG_ERROR("no virtual socket"); return -1; } if(vs->socket_type == SOCK_DGRAM) { DEBUG_ERROR("socket_type==SOCK_DGRAM"); // TODO: Packet re-assembly hasn't yet been tested with lwIP so UDP packets are limited to MTU-sized chunks - int udp_trans_len = std::min((ssize_t)vs->TXbuf->count(), (ssize_t)ZT_MAX_MTU); + int udp_trans_len = std::min((ssize_t)vs->TXbuf->count(), (ssize_t)ZT_MAX_MTU); DEBUG_EXTRA("allocating pbuf chain of size=%d for UDP packet, txsz=%d", udp_trans_len, vs->TXbuf->count()); struct pbuf * pb = pbuf_alloc(PBUF_TRANSPORT, udp_trans_len, PBUF_POOL); if(!pb){ @@ -524,7 +555,7 @@ namespace ZeroTier int err, r; if(!sndbuf) { // PCB send buffer is full, turn off readability notifications for the - // corresponding PhySocket until nc_sent() is called and confirms that there is + // corresponding PhySocket until lwip_cb_sent() is called and confirms that there is // now space on the buffer DEBUG_ERROR("lwIP stack is full, sndbuf == 0"); vs->tap->_phy.setNotifyReadable(vs->sock, false); @@ -571,7 +602,7 @@ namespace ZeroTier // FIXME: check if already closed? vs->TCP_pcb->state != CLOSED if(vs->pcb) { //DEBUG_EXTRA("vs=%p, sock=%p, PCB->state = %d", - // (void*)&conn, (void*)&sock, vs->TCP_pcb->state); + // (void*)&conn, (void*)&sock, vs->TCP_pcb->state); if(((struct tcp_pcb*)vs->pcb)->state == SYN_SENT /*|| vs->TCP_pcb->state == CLOSE_WAIT*/) { DEBUG_EXTRA("ignoring close request. invalid PCB state for this operation. sock=%p", vs->sock); return -1; @@ -596,7 +627,7 @@ namespace ZeroTier /* Callbacks from lwIP stack */ /****************************************************************************/ - err_t lwIP::nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err) + err_t lwIP::lwip_cb_tcp_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err) { DEBUG_INFO(); VirtualSocket *vs = (VirtualSocket *)arg; @@ -649,12 +680,11 @@ namespace ZeroTier return ERR_OK; } - err_t lwIP::nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err) + err_t lwIP::lwip_cb_accept(void *arg, struct tcp_pcb *newPCB, err_t err) { VirtualSocket *vs = (VirtualSocket*)arg; DEBUG_INFO("vs=%p", vs); //Mutex::Lock _l(vs->tap->_tcpconns_m); - // create and populate new VirtualSocket object VirtualSocket *new_vs = new VirtualSocket(); new_vs->socket_type = SOCK_STREAM; new_vs->pcb = newPCB; @@ -666,22 +696,22 @@ namespace ZeroTier vs->_AcceptedConnections.push(new_vs); // set callbacks tcp_arg(newPCB, new_vs); - tcp_recv(newPCB, nc_recved); - tcp_err(newPCB, nc_err); - tcp_sent(newPCB, nc_sent); - tcp_poll(newPCB, nc_poll, 1); + tcp_recv(newPCB, lwip_cb_tcp_recved); + tcp_err(newPCB, lwip_cb_err); + tcp_sent(newPCB, lwip_cb_sent); + tcp_poll(newPCB, lwip_cb_poll, 1); // let lwIP know that it can queue additional incoming VirtualSockets tcp_accepted((struct tcp_pcb*)vs->pcb); return 0; } - void lwIP::nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port) + void lwIP::lwip_cb_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port) { DEBUG_INFO(); // to be implemented } - err_t lwIP::nc_sent(void* arg, struct tcp_pcb *PCB, u16_t len) + err_t lwIP::lwip_cb_sent(void* arg, struct tcp_pcb *PCB, u16_t len) { DEBUG_EXTRA("pcb=%p", (void*)&PCB); VirtualSocket *vs = (VirtualSocket *)arg; @@ -696,7 +726,7 @@ namespace ZeroTier return ERR_OK; } - err_t lwIP::nc_connected(void *arg, struct tcp_pcb *PCB, err_t err) + err_t lwIP::lwip_cb_connected(void *arg, struct tcp_pcb *PCB, err_t err) { DEBUG_ATTN("pcb=%p", (void*)&PCB); VirtualSocket *vs = (VirtualSocket *)arg; @@ -706,12 +736,12 @@ namespace ZeroTier // FIXME: check stack for expected return values } - err_t lwIP::nc_poll(void* arg, struct tcp_pcb *PCB) + err_t lwIP::lwip_cb_poll(void* arg, struct tcp_pcb *PCB) { return ERR_OK; } - void lwIP::nc_err(void *arg, err_t err) + void lwIP::lwip_cb_err(void *arg, err_t err) { DEBUG_ERROR("err=%d", err); VirtualSocket *vs = (VirtualSocket *)arg; diff --git a/src/lwIP.hpp b/src/lwIP.hpp index 4ab29bb..830bc49 100644 --- a/src/lwIP.hpp +++ b/src/lwIP.hpp @@ -174,6 +174,16 @@ namespace ZeroTier { */ void lwip_init_interface(VirtualTap *tap, const InetAddress &ip); + /* + * Registers a DNS nameserver with the network stack + */ + int lwip_add_dns_nameserver(struct sockaddr *addr); + + /* + * Un-registers a DNS nameserver from the network stack + */ + int lwip_del_dns_nameserver(struct sockaddr *addr); + /* * Main stack loop */ @@ -184,22 +194,84 @@ namespace ZeroTier { */ void lwip_eth_rx(VirtualTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + /* + * Creates a stack-specific "socket" or "VirtualSocket object" + */ int lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol); + + /* + * Connect to remote host via userspace network stack interface - Called from VirtualTap + */ int lwip_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen); + + /* + * Bind to a userspace network stack interface - Called from VirtualTap + */ int lwip_Bind(VirtualTap *tap, VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen); + + /* + * Listen for incoming VirtualSockets - Called from VirtualTap + */ int lwip_Listen(VirtualSocket *vs, int backlog); + + /* + * Accept an incoming VirtualSocket - Called from VirtualTap + */ VirtualSocket* lwip_Accept(VirtualSocket *vs); + + /* + * Read from RX buffer to application - Called from VirtualTap + */ int lwip_Read(VirtualSocket *vs, bool lwip_invoked); + + /* + * Write to userspace network stack - Called from VirtualTap + */ int lwip_Write(VirtualSocket *vs, void *data, ssize_t len); + + /* + * Close a VirtualSocket - Called from VirtualTap + */ int lwip_Close(VirtualSocket *vs); - static err_t nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err); - static err_t nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err); - static void nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port); - static void nc_err(void *arg, err_t err); - static err_t nc_poll(void* arg, struct tcp_pcb *PCB); - static err_t nc_sent(void *arg, struct tcp_pcb *PCB, u16_t len); - static err_t nc_connected(void *arg, struct tcp_pcb *PCB, err_t err); + + // --- Callbacks from network stack --- + + + /* + * Callback for handling received UDP packets (already processed by network stack) + */ + static err_t lwip_cb_tcp_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err); + + /* + * Callback for handling accepted connection + */ + static err_t lwip_cb_accept(void *arg, struct tcp_pcb *newPCB, err_t err); + + /* + * Callback for handling received TCP packets (already processed by stack) + */ + static void lwip_cb_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port); + + /* + * Callback for handling errors from within the network stack + */ + static void lwip_cb_err(void *arg, err_t err); + + /* + * Callback for handling periodic background tasks + */ + static err_t lwip_cb_poll(void* arg, struct tcp_pcb *PCB); + + /* + * Callback for handling confirmation of sent packets + */ + static err_t lwip_cb_sent(void *arg, struct tcp_pcb *PCB, u16_t len); + + /* + * Callback for handling successful connections + */ + static err_t lwip_cb_connected(void *arg, struct tcp_pcb *PCB, err_t err); }; } diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp index 2da9cc4..645463f 100644 --- a/src/picoTCP.cpp +++ b/src/picoTCP.cpp @@ -391,7 +391,7 @@ namespace ZeroTier { int txsz = vs->TXbuf->count(); if(txsz <= 0) return; - //DEBUG_INFO("TXbuf->count() = %d", vs->TXbuf->count()); + //DEBUG_INFO("TXbuf->count()=%d", vs->TXbuf->count()); int r, max_write_len = std::min(std::min(txsz, ZT_SDK_MTU),ZT_STACK_SOCKET_WR_MAX); if((r = pico_socket_write(vs->picosock, vs->TXbuf->get_buf(), max_write_len)) < 0) { @@ -447,7 +447,7 @@ namespace ZeroTier { DEBUG_ERROR("pico_socket_close()=%d, pico_err=%d, %s", err, pico_err, beautify_pico_error(pico_err)); } DEBUG_EXTRA("PICO_SOCK_EV_CLOSE (socket closure) err=%d (%s), picosock=%p", pico_err, beautify_pico_error(pico_err), s); - //DEBUG_EXTRA("PICO_SOCK_EV_CLOSE (socket closure) err = %d, picosock=%p, vs=%p, app_fd=%d, sdk_fd=%d", err, s, vs, vs->app_fd, vs->sdk_fd); + //DEBUG_EXTRA("PICO_SOCK_EV_CLOSE (socket closure) err=%d, picosock=%p, vs=%p, app_fd=%d, sdk_fd=%d", err, s, vs, vs->app_fd, vs->sdk_fd); //vs->closure_ts = std::time(nullptr); return; } @@ -591,17 +591,9 @@ namespace ZeroTier { { tcp_hdr_ptr = &buf + PICO_SIZE_ETHHDR + PICO_SIZE_IP4HDR; hdr = (struct pico_tcp_hdr *)tcp_hdr_ptr; - - /* - ext/picotcp/build/include/pico_tcp.h:#define PICO_TCP_SYNACK (PICO_TCP_SYN | PICO_TCP_ACK) - ext/picotcp/build/include/pico_tcp.h:#define PICO_TCP_PSHACK (PICO_TCP_PSH | PICO_TCP_ACK) - ext/picotcp/build/include/pico_tcp.h:#define PICO_TCP_FINACK (PICO_TCP_FIN | PICO_TCP_ACK) - ext/picotcp/build/include/pico_tcp.h:#define PICO_TCP_FINPSHACK (PICO_TCP_FIN | PICO_TCP_PSH | PICO_TCP_ACK) - ext/picotcp/build/include/pico_tcp.h:#define PICO_TCP_RSTACK (PICO_TCP_RST | PICO_TCP_ACK) - */ if(hdr) { - char *flag_ptr = flagbuf; + char *flag_ptr = flagbuf; if (hdr->flags & PICO_TCP_PSH) { sprintf(flag_ptr, "PSH "); @@ -991,10 +983,10 @@ namespace ZeroTier { vs->TXbuf->consume(r); } if(vs->socket_type == SOCK_STREAM) { - DEBUG_TRANS("len=%5d, [app(buf) --> network_stack(vs=%p)] proto=0x%04x (TCP)", r, vs, PICO_PROTO_TCP); + DEBUG_TRANS("len=%5d [app(buf) --> network_stack(vs=%p)] proto=0x%04x (TCP)", r, vs, PICO_PROTO_TCP); } if(vs->socket_type == SOCK_DGRAM) { - DEBUG_TRANS("len=%5d, [app(buf) --> network_stack(vs=%p)] proto=0x%04x (TCP)", r, vs, PICO_PROTO_UDP); + DEBUG_TRANS("len=%5d [app(buf) --> network_stack(vs=%p)] proto=0x%04x (TCP)", r, vs, PICO_PROTO_UDP); } } return err; @@ -1016,8 +1008,8 @@ namespace ZeroTier { return ZT_ERR_OK; if((err = pico_socket_close(vs->picosock)) < 0) { errno = pico_err; - DEBUG_ERROR("error closing pico_socket(%p), err=%d, pico_err=%s, %s", - (void*)(vs->picosock), err, pico_err, beautify_pico_error(pico_err)); + DEBUG_ERROR("error closing pico_socket, err=%d, pico_err=%s, %s", + err, pico_err, beautify_pico_error(pico_err)); } return err; } diff --git a/test/generate_test_env.sh b/test/generate_test_env.sh deleted file mode 100755 index 6146303..0000000 --- a/test/generate_test_env.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# create dirs to house the identities/config -mkdir alice -mkdir bob -mkdir ted -mkdir carol - -# generate identities -zerotier-one alice -d -echo $! >> "zto.alice" -zerotier-one bob -d -echo $! >> "zto.bob" -zerotier-one ted -d -echo $! >> "zto.ted" -zerotier-one carol -d -echo $! >> "zto.carol" - -# should be done by now -sleep(30) - -# kill daemons -echo "killing daemons" - -pid=$(cat alice/zto.alice) -kill -9 $pid -pid=$(cat bob/zto.bob) -kill -9 $pid -pid=$(cat ted/zto.ted) -kill -9 $pid -pid=$(cat carol/zto.carol) -kill -9 $pid \ No newline at end of file diff --git a/test/selftest.cpp b/test/selftest.cpp index 019e1ac..1589a8d 100644 --- a/test/selftest.cpp +++ b/test/selftest.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include "libzt.h" @@ -59,8 +60,7 @@ #define ECHO_INTERVAL 1000000 // us #define SLAM_INTERVAL 500000 -#define WAIT_FOR_SERVER_TO_COME_ONLINE 2 -#define WAIT_FOR_TEST_TO_CONCLUDE 15 +#define WAIT_FOR_TEST_TO_CONCLUDE 0 #define WAIT_FOR_TRANSMISSION_TO_COMPLETE 5 #define STR_SIZE 32 @@ -80,11 +80,11 @@ #define MIN_PORT 5000 #define MAX_PORT 50000 -#define TCP_UNIT_TEST_SIG_4 struct sockaddr_in *addr, int operation, int count, int delay, char *details, bool *passed -#define UDP_UNIT_TEST_SIG_4 struct sockaddr_in *local_addr, struct sockaddr_in *remote_addr, int operation, int count, int delay, char *details, bool *passed +#define TCP_UNIT_TEST_SIG_4 struct sockaddr_in *addr, int op, int cnt, char *details, bool *passed +#define UDP_UNIT_TEST_SIG_4 struct sockaddr_in *local_addr, struct sockaddr_in *remote_addr, int op, int cnt, char *details, bool *passed -#define TCP_UNIT_TEST_SIG_6 struct sockaddr_in6 *addr, int operation, int count, int delay, char *details, bool *passed -#define UDP_UNIT_TEST_SIG_6 struct sockaddr_in6 *local_addr, struct sockaddr_in6 *remote_addr, int operation, int count, int delay, char *details, bool *passed +#define TCP_UNIT_TEST_SIG_6 struct sockaddr_in6 *addr, int op, int cnt, char *details, bool *passed +#define UDP_UNIT_TEST_SIG_6 struct sockaddr_in6 *local_addr, struct sockaddr_in6 *remote_addr, int op, int cnt, char *details, bool *passed #define ECHOTEST_MODE_RX 333 @@ -99,6 +99,53 @@ #define DETAILS_STR_LEN 128 + +// If running a self test, use libzt calls +#if defined(__SELFTEST__) +#define SOCKET zts_socket +#define BIND zts_bind +#define LISTEN zts_listen +#define ACCEPT zts_accept +#define CONNECT zts_connect +#define READ zts_read +#define WRITE zts_write +#define RECV zts_recvmsg +#define SEND zts_send +#define RECVFROM zts_recvfrom +#define SENDTO zts_sendto +#define RECVMSG zts_recvmsg +#define SENDMSG zts_sendmsg +#define SETSOCKOPT zts_setsockopt +#define GETSOCKOPT zts_getsockopt +#define IOCTL zts_ioctl +#define FCNTL zts_fcntl +#define CLOSE zts_close +#define GETPEERNAME zts_getpeername +#endif + +// If running a native instance to test against, use system calls +#if defined(__NATIVETEST__) +#define SOCKET socket +#define BIND bind +#define LISTEN listen +#define ACCEPT accept +#define CONNECT connect +#define READ read +#define WRITE write +#define RECV recvmsg +#define SEND send +#define RECVFROM recvfrom +#define SENDTO sendto +#define RECVMSG recvmsg +#define SENDMSG sendmsg +#define SETSOCKOPT setsockopt +#define GETSOCKOPT getsockopt +#define IOCTL ioctl +#define FCNTL fcntl +#define CLOSE close +#define GETPEERNAME getpeername +#endif + std::map testConf; /* Tests in this file: @@ -132,7 +179,7 @@ std::map testConf; [ ] Block/Non-block - Test that blocking and non-blocking behaviour is consistent [ ] Release of resources - Test that all destructor methods/blocks function properly - [ ] Multi-network handling - Test internal Tap multiplexing works for multiple networks + [OK] Multi-network handling - Test internal Tap multiplexing works for multiple networks [ ] Address handling - Test that addresses are copied/parsed/returned properly */ @@ -181,16 +228,34 @@ long int get_now_ts() { return tp.tv_sec * 1000 + tp.tv_usec / 1000; } -void generate_random_data(void *buf, size_t n) { +// for syncronizing tests +void wait_until_tplus(long int original_time, int tplus_ms) { + while(original_time + tplus_ms > get_now_ts()) { + sleep(1); + } +} +void wait_until_tplus_s(long int original_time, int tplus_s) { + int current_time_offset = (get_now_ts() - original_time) / 1000; + fprintf(stderr, "\n\n--- WAITING FOR T+%d --- (current: T+%d)\n\n", tplus_s, current_time_offset); + if(current_time_offset > tplus_s) { + DEBUG_ERROR("--- ABORTING TEST: Tests are out of sync and might not yield valid results. ---"); + exit(0); + } + if(current_time_offset == tplus_s) { + DEBUG_ERROR("--- WARNING: Tests might be out of sync and might not yield valid results. ---"); + } + wait_until_tplus(original_time, tplus_s * 1000); +} + +void generate_random_data(void *buf, size_t n, int min, int max) { char *b = (char*)buf; - int min = 0, max = 9; srand((unsigned)time(0)); for(int i=0; i(max - min + 1)); } } -void create_addr(std::string ipstr, int port, int ipv, struct sockaddr *saddr) { +void str2addr(std::string ipstr, int port, int ipv, struct sockaddr *saddr) { if(ipv == 4) { struct sockaddr_in *in4 = (struct sockaddr_in*)saddr; in4->sin_port = htons(port); @@ -206,18 +271,16 @@ void create_addr(std::string ipstr, int port, int ipv, struct sockaddr *saddr) { } } - -void RECORD_RESULTS(int *test_number, bool passed, char *details, std::vector *results) +void RECORD_RESULTS(bool passed, char *details, std::vector *results) { - (*test_number) = 0; char *ok_str = (char*)"[ OK ]"; char *fail_str = (char*)"[ FAIL ]"; if(passed == PASSED) { - DEBUG_TEST("[%d]%s", *test_number, ok_str); + DEBUG_TEST("%s", ok_str); results->push_back(std::string(ok_str) + " " + std::string(details)); } else { - DEBUG_ERROR("[%d]%s", *test_number, fail_str); + DEBUG_ERROR("%s", fail_str); results->push_back(std::string(fail_str) + " " + std::string(details)); } if(EXIT_ON_FAIL && !passed) { @@ -235,320 +298,478 @@ void RECORD_RESULTS(int *test_number, bool passed, char *details, std::vector %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + socklen_t peer_addrlen = sizeof(peer_addr); + + if((err = GETPEERNAME(fd, (struct sockaddr*)&peer_addr, &peer_addrlen)) < 0) { + perror("getpeername"); + *passed = false; + return; + } + DEBUG_TEST("getpeername() => %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); - w = zts_write(sockfd, msg.c_str(), len); - r = zts_read(sockfd, rbuf, len); + w = WRITE(fd, msg.c_str(), len); + r = READ(fd, rbuf, len); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + err = CLOSE(fd); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); } -// + + + + +// TEST-2 void tcp_server_4(TCP_UNIT_TEST_SIG_4) { std::string testname = "tcp_server_4"; std::string msg = "tcp_cs_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int w=0, r=0, sockfd, accfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "accept connection with IPv4 address, read string, write string, compare.\n"); + int w=0, r=0, fd, client_fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); - if((err = zts_listen(sockfd, 100)) < 0) + perror("bind"); + *passed = false; + return; + } + if((err = LISTEN(fd, 100)) < 0) { printf("error placing socket in LISTENING state (%d)", err); - if((accfd = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) - DEBUG_ERROR("error accepting connection (%d)", err); + perror("listen"); + *passed = false; + return; + } + + struct sockaddr_in client; + socklen_t client_addrlen = sizeof(sockaddr_in); + if((client_fd = ACCEPT(fd, (struct sockaddr *)&client, &client_addrlen)) < 0) + fprintf(stderr,"error accepting connection (%d)\n", err); + DEBUG_TEST("accepted connection from %s, on port %d", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + // TODO: Put this test in the general API section struct sockaddr_storage peer_addr; struct sockaddr_in *in4 = (struct sockaddr_in*)&peer_addr; - socklen_t peer_addrlen; - zts_getpeername(accfd, (struct sockaddr*)&peer_addr, &peer_addrlen); - DEBUG_INFO("getpeername() => %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + socklen_t peer_addrlen = sizeof(peer_addr); - r = zts_read(accfd, rbuf, sizeof rbuf); - w = zts_write(accfd, rbuf, len); + if((err = GETPEERNAME(client_fd, (struct sockaddr*)&peer_addr, &peer_addrlen)) < 0) { + perror("getpeername"); + *passed = false; + return; + } + + DEBUG_TEST("getpeername() => %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + + r = READ(client_fd, rbuf, sizeof rbuf); + w = WRITE(client_fd, rbuf, len); DEBUG_TEST("Received : %s", rbuf); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - err = zts_close(accfd); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + err = CLOSE(fd); + err = CLOSE(client_fd); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); } -// + + + + +// TEST-3 void tcp_client_6(TCP_UNIT_TEST_SIG_6) { std::string testname = "tcp_client_6"; std::string msg = "tcp_cs_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "connect to remote host with IPv6 address, write string, read string, compare.\n"); + int r, w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET6, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) + perror("socket"); + *passed = false; + return; + } + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) { DEBUG_ERROR("error connecting to remote host (%d)", err); + perror("connect"); + *passed = false; + return; + } // TODO: Put this test in the general API section struct sockaddr_storage peer_addr; struct sockaddr_in6 *p6 = (struct sockaddr_in6*)&peer_addr; - socklen_t peer_addrlen; - zts_getpeername(sockfd, (struct sockaddr*)&peer_addr, &peer_addrlen); - char peer_addrstr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(p6->sin6_addr), peer_addrstr, INET6_ADDRSTRLEN); - DEBUG_INFO("getpeername() => %s : %d", peer_addrstr, ntohs(p6->sin6_port)); + socklen_t peer_addrlen = sizeof(peer_addr); - w = zts_write(sockfd, msg.c_str(), len); - r = zts_read(sockfd, rbuf, len); + if((err = GETPEERNAME(fd, (struct sockaddr*)&peer_addr, &peer_addrlen)) < 0) { + perror("getpeername"); + *passed = false; + return; + } + char peer_addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(p6->sin6_addr), peer_addrstr, INET6_ADDRSTRLEN); + DEBUG_TEST("getpeername() => %s : %d", peer_addrstr, ntohs(p6->sin6_port)); + + w = WRITE(fd, msg.c_str(), len); + r = READ(fd, rbuf, len); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + err = CLOSE(fd); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); } -// + + + + +// TEST-4 void tcp_server_6(TCP_UNIT_TEST_SIG_6) { - std::string testname = "tcp_sever_6"; + std::string testname = "tcp_server_6"; std::string msg = "tcp_cs_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int w=0, r=0, sockfd, accfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "accept connection with IPv6 address, read string, write string, compare.\n"); + int w=0, r=0, fd, client_fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET6, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); - if((err = zts_listen(sockfd, 100)) < 0) + perror("bind"); + *passed = false; + return; + } + if((err = LISTEN(fd, 100)) < 0) { DEBUG_ERROR("error placing socket in LISTENING state (%d)", err); - if((accfd = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) - DEBUG_ERROR("error accepting connection (%d)", err); + perror("listen"); + *passed = false; + return; + } + + struct sockaddr_in6 client; + socklen_t client_addrlen = sizeof(sockaddr_in6); + if((client_fd = ACCEPT(fd, (struct sockaddr *)&client, &client_addrlen)) < 0) + fprintf(stderr,"error accepting connection (%d)\n", err); + char ipstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &client.sin6_addr, ipstr, sizeof ipstr); + DEBUG_TEST("accepted connection from %s, on port %d", ipstr, ntohs(client.sin6_port)); + // TODO: Put this test in the general API section struct sockaddr_storage peer_addr; struct sockaddr_in6 *p6 = (struct sockaddr_in6*)&peer_addr; - socklen_t peer_addrlen; - zts_getpeername(accfd, (struct sockaddr*)&peer_addr, &peer_addrlen); - char peer_addrstr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(p6->sin6_addr), peer_addrstr, INET6_ADDRSTRLEN); - DEBUG_INFO("getpeername() => %s : %d", peer_addrstr, ntohs(p6->sin6_port)); + socklen_t peer_addrlen = sizeof(peer_addr); - r = zts_read(accfd, rbuf, sizeof rbuf); - w = zts_write(accfd, rbuf, len); + if((err = GETPEERNAME(client_fd, (struct sockaddr*)&peer_addr, &peer_addrlen)) < 0) { + perror("getpeername"); + *passed = false; + return; + } + char peer_addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(p6->sin6_addr), peer_addrstr, INET6_ADDRSTRLEN); + DEBUG_TEST("getpeername() => %s : %d", peer_addrstr, ntohs(p6->sin6_port)); + + r = READ(client_fd, rbuf, sizeof rbuf); + w = WRITE(client_fd, rbuf, len); DEBUG_TEST("Received : %s", rbuf); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - err = zts_close(accfd); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + err = CLOSE(fd); + err = CLOSE(client_fd); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); } + + + + // UDP -// +// TEST-5 void udp_client_4(UDP_UNIT_TEST_SIG_4) { std::string testname = "udp_client_4"; std::string msg = "udp_cs_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv4 address, send string until response is seen. compare.\n"); + int r, w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - - if((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)) - std::cout << "error setting O_NONBLOCK (errno=" << strerror(errno) << ")" << std::endl; - DEBUG_INFO("sending UDP packets until I get a single response...\n"); - if((err = zts_bind(sockfd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = FCNTL(fd, F_SETFL, O_NONBLOCK) < 0)) { + fprintf(stderr, "error setting O_NONBLOCK (errno=%d)", errno); + perror("fcntl"); + *passed = false; + return; + } + DEBUG_TEST("sending UDP packets until I get a single response..."); + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; + } struct sockaddr_storage saddr; while(1) { // tx - if((w = zts_sendto(sockfd, msg.c_str(), strlen(msg.c_str()), 0, (struct sockaddr *)remote_addr, sizeof(remote_addr))) < 0) { + if((w = SENDTO(fd, msg.c_str(), strlen(msg.c_str()), 0, (struct sockaddr *)remote_addr, sizeof(*remote_addr))) < 0) { DEBUG_ERROR("error sending packet, err=%d", errno); } sleep(1); memset(rbuf, 0, sizeof(rbuf)); - int serverlen = sizeof(remote_addr); + int serverlen = sizeof(struct sockaddr_storage); // rx - r = zts_recvfrom(sockfd, rbuf, STR_SIZE, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen); - if(r == strlen(msg.c_str())) { - sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - DEBUG_INFO("%s, n=%d, err=%d, r=%d, w=%d\n", testname.c_str(), count, err, r, w); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + r = RECVFROM(fd, rbuf, STR_SIZE, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen); + if(r == strlen(msg.c_str())) { + sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); + err = CLOSE(fd); + DEBUG_TEST("%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); return; - } + } } } + + + + +// TEST-6 void udp_server_4(UDP_UNIT_TEST_SIG_4) { std::string testname = "udp_server_4"; std::string msg = "udp_cs_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv4 address, read single string, send many responses. compare.\n"); + int r, w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - - if((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) - DEBUG_ERROR("error binding to interface (%d)", err); - // rx - DEBUG_INFO("waiting for UDP packet..."); - struct sockaddr_storage saddr; - struct sockaddr_in *in4 = (struct sockaddr_in*)&saddr; - int serverlen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - r = zts_recvfrom(sockfd, rbuf, STR_SIZE, 0, (struct sockaddr *)in4, (socklen_t *)&serverlen); - char addrstr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); - // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see - DEBUG_INFO("received DGRAM from %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); - DEBUG_INFO("sending DGRAM(s) to %s : %d", inet_ntoa(remote_addr->sin_addr), ntohs(remote_addr->sin_port)); - // tx - long int tx_ti = get_now_ts(); - while(1) { - sleep(1); - //DEBUG_INFO("sending UDP packet"); - if((w = zts_sendto(sockfd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(remote_addr))) < 0) { + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) { + DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; + } + // rx + DEBUG_TEST("waiting for UDP packet..."); + struct sockaddr_storage saddr; + struct sockaddr_in *in4 = (struct sockaddr_in*)&saddr; + int serverlen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if((r = RECVFROM(fd, rbuf, STR_SIZE, 0, (struct sockaddr *)in4, (socklen_t *)&serverlen)) < 0) { + perror("recvfrom"); + *passed = false; + return; + } + char addrstr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); + // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see + DEBUG_TEST("received DGRAM from %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + DEBUG_TEST("sending DGRAM(s) to %s : %d", inet_ntoa(remote_addr->sin_addr), ntohs(remote_addr->sin_port)); + // tx + long int tx_ti = get_now_ts(); + while(1) { + sleep(1); + //DEBUG_TEST("sending UDP packet"); + if((w = SENDTO(fd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(*remote_addr))) < 0) { DEBUG_ERROR("error sending packet, err=%d", errno); } - if(get_now_ts() >= tx_ti + 20000) { - DEBUG_INFO("get_now_ts()-tx_ti=%d", get_now_ts()-tx_ti); + if(get_now_ts() >= tx_ti + 10000) { + // DEBUG_TEST("get_now_ts()-tx_ti=%d", get_now_ts()-tx_ti); break; } } sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - //err = zts_close(sockfd); - DEBUG_INFO("%s, n=%d, err=%d, r=%d, w=%d\n", testname.c_str(), count, err, r, w); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + //err = CLOSE(fd); + DEBUG_TEST("%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); } -// + + + + +// TEST-7 void udp_client_6(UDP_UNIT_TEST_SIG_6) { std::string testname = "udp_client_6"; std::string msg = "udp_cs_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv6 address, send string until response is seen. compare.\n"); + int r, w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + if((fd = SOCKET(AF_INET6, SOCK_DGRAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = FCNTL(fd, F_SETFL, O_NONBLOCK) < 0)) { std::cout << "error setting O_NONBLOCK (errno=" << strerror(errno) << ")" << std::endl; - - DEBUG_INFO("[1] binding and sending UDP packets until I get a single response..."); - if((err = zts_bind(sockfd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) + perror("fcntl"); + *passed = false; + return; + } + DEBUG_TEST("[1] binding and sending UDP packets until I get a single response..."); + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; + } // start sending UDP packets in the hopes that at least one will be picked up by the server struct sockaddr_storage saddr; while(1) { // tx - if((w = zts_sendto(sockfd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(remote_addr))) < 0) { + if((w = SENDTO(fd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(*remote_addr))) < 0) { DEBUG_ERROR("error sending packet, err=%d", errno); } usleep(100000); memset(rbuf, 0, sizeof(rbuf)); - int serverlen = sizeof(remote_addr); + int serverlen = sizeof(struct sockaddr_storage); // rx - r = zts_recvfrom(sockfd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen); - if(r == len) { - DEBUG_INFO("[2] complete"); - sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - DEBUG_INFO("%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + r = RECVFROM(fd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen); + if(r == len) { + DEBUG_TEST("[2] complete"); + sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); + err = CLOSE(fd); + DEBUG_TEST("%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); return; - } + } } } + + + +// TEST-8 void udp_server_6(UDP_UNIT_TEST_SIG_6) { std::string testname = "udp_server_6"; std::string msg = "udp_cs_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv6 address, read single string, send many responses. compare.\n"); + int r, w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) - DEBUG_ERROR("error binding to interface (%d)", err); - // rx - DEBUG_INFO("[1/4] waiting for UDP packet to start test..."); - struct sockaddr_storage saddr; - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&saddr; - int serverlen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - r = zts_recvfrom(sockfd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen); - - char addrstr[INET6_ADDRSTRLEN], remote_addrstr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(remote_addr->sin6_addr), remote_addrstr, INET6_ADDRSTRLEN); - DEBUG_INFO("[2/4] received DGRAM from %s : %d", addrstr, ntohs(in6->sin6_port)); - DEBUG_INFO("[2/4] sending DGRAM(s) to %s : %d", remote_addrstr, ntohs(remote_addr->sin6_port)); - // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see - // tx - long int tx_ti = get_now_ts(); - while(1) { - usleep(100000); - //DEBUG_INFO("sending UDP packet"); - if((w = zts_sendto(sockfd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(remote_addr))) < 0) { + if((fd = SOCKET(AF_INET6, SOCK_DGRAM, 0)) < 0) { + DEBUG_ERROR("error creating socket"); + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) { + DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; + } + // rx + DEBUG_TEST("[1/3] waiting for UDP packet to start test..."); + struct sockaddr_storage saddr; + struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&saddr; + int serverlen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if((r = RECVFROM(fd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen)) < 0) { + perror("recvfrom"); + *passed = false; + return; + } + char addrstr[INET6_ADDRSTRLEN], remote_addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &(remote_addr->sin6_addr), remote_addrstr, INET6_ADDRSTRLEN); + DEBUG_TEST("[2/3] received DGRAM from %s : %d", addrstr, ntohs(in6->sin6_port)); + DEBUG_TEST("[2/3] sending DGRAM(s) to %s : %d", remote_addrstr, ntohs(remote_addr->sin6_port)); + // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see + // tx + long int tx_ti = get_now_ts(); + while(1) { + usleep(100000); + //DEBUG_TEST("sending UDP packet"); + if((w = SENDTO(fd, msg.c_str(), len, 0, (struct sockaddr *)remote_addr, sizeof(*remote_addr))) < 0) { DEBUG_ERROR("error sending packet, err=%d", errno); } - if(get_now_ts() >= tx_ti + 20000) { - DEBUG_INFO("[3/4] get_now_ts()-tx_ti=%d", get_now_ts()-tx_ti); + if(get_now_ts() >= tx_ti + 10000) { + // DEBUG_TEST("[3/4] get_now_ts()-tx_ti=%d", get_now_ts()-tx_ti); break; } } sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - //err = zts_close(sockfd); - DEBUG_INFO("[4/4] complete, %s, n=%d, err=%d, r=%d, w=%d\n", testname.c_str(), count, err, r, w); - sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), count, err, r, w); + //err = CLOSE(fd); + DEBUG_TEST("[3/3] complete, %s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); + sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w); DEBUG_TEST("Sent : %s", msg.c_str()); DEBUG_TEST("Received : %s", rbuf); *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); @@ -556,34 +777,48 @@ void udp_server_6(UDP_UNIT_TEST_SIG_6) + + + /****************************************************************************/ /* SUSTAINED */ /****************************************************************************/ -// Maintain transfer for count OR count + + + + void tcp_client_sustained_4(TCP_UNIT_TEST_SIG_4) { std::string testname = "tcp_client_sustained_4"; std::string msg = "tcp_sustained_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int n=0, w=0, r=0, sockfd, err; - char *rxbuf = (char*)malloc(count*sizeof(char)); - char *txbuf = (char*)malloc(count*sizeof(char)); - generate_random_data(txbuf, count); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "connect to remote host with IPv4 address, exchange a sequence of packets, check order.\n"); + int n=0, w=0, r=0, fd, err; + char *rxbuf = (char*)malloc(cnt*sizeof(char)); + char *txbuf = (char*)malloc(cnt*sizeof(char)); + generate_random_data(txbuf, cnt, 0, 9); - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) + perror("socket"); + *passed = false; + return; + } + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) { DEBUG_ERROR("error connecting to remote host (%d)", err); - - if(operation == TEST_OP_N_BYTES) { - int wrem = count, rrem = count; - + perror("connect"); + *passed = false; + return; + } + if(op == TEST_OP_N_BYTES) { + int wrem = cnt, rrem = cnt; // TX long int tx_ti = get_now_ts(); while(wrem) { int next_write = std::min(4096, wrem); - n = zts_write(sockfd, &txbuf[w], next_write); + signal(SIGPIPE, SIG_IGN); + n = WRITE(fd, &txbuf[w], next_write); if (n > 0) { w += n; @@ -596,7 +831,7 @@ void tcp_client_sustained_4(TCP_UNIT_TEST_SIG_4) // RX long int rx_ti = 0; while(rrem) { - n = zts_read(sockfd, &rxbuf[r], rrem); + n = READ(fd, &rxbuf[r], rrem); if(!rx_ti) { // wait for first message rx_ti = get_now_ts(); } @@ -610,27 +845,23 @@ void tcp_client_sustained_4(TCP_UNIT_TEST_SIG_4) long int rx_tf = get_now_ts(); DEBUG_TEST("read=%d", r); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - + err = CLOSE(fd); // Compare RX and TX buffer and detect mismatches bool match = true; - for(int i=0; i=0); + testname.c_str(), match, cnt, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); + *passed = (r == cnt && w == cnt && match && err>=0); } free(rxbuf); free(txbuf); @@ -638,31 +869,38 @@ void tcp_client_sustained_4(TCP_UNIT_TEST_SIG_4) -// Maintain transfer for count OR count + + void tcp_client_sustained_6(TCP_UNIT_TEST_SIG_6) { std::string testname = "tcp_client_sustained_6"; std::string msg = "tcp_sustained_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int n=0, w=0, r=0, sockfd, err; - char *rxbuf = (char*)malloc(count*sizeof(char)); - char *txbuf = (char*)malloc(count*sizeof(char)); - - generate_random_data(txbuf, count); - - if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "connect to remote host with IPv6 address, exchange a sequence of packets, check order.\n"); + int n=0, w=0, r=0, fd, err; + char *rxbuf = (char*)malloc(cnt*sizeof(char)); + char *txbuf = (char*)malloc(cnt*sizeof(char)); + generate_random_data(txbuf, cnt, 0, 9); + if((fd = SOCKET(AF_INET6, SOCK_STREAM, 0)) < 0){ DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) + perror("socket"); + *passed = false; + return; + } + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) { DEBUG_ERROR("error connecting to remote host (%d)", err); + perror("connect"); + *passed = false; + return; + } - if(operation == TEST_OP_N_BYTES) { - int wrem = count, rrem = count; - + if(op == TEST_OP_N_BYTES) { + int wrem = cnt, rrem = cnt; // TX long int tx_ti = get_now_ts(); while(wrem) { int next_write = std::min(4096, wrem); - n = zts_write(sockfd, &txbuf[w], next_write); + n = WRITE(fd, &txbuf[w], next_write); if (n > 0) { w += n; @@ -675,7 +913,7 @@ void tcp_client_sustained_6(TCP_UNIT_TEST_SIG_6) // RX long int rx_ti = 0; while(rrem) { - n = zts_read(sockfd, &rxbuf[r], rrem); + n = READ(fd, &rxbuf[r], rrem); if(!rx_ti) { // wait for first message rx_ti = get_now_ts(); } @@ -688,58 +926,73 @@ void tcp_client_sustained_6(TCP_UNIT_TEST_SIG_6) } long int rx_tf = get_now_ts(); DEBUG_TEST("read=%d", r); - sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - + err = CLOSE(fd); // Compare RX and TX buffer and detect mismatches bool match = true; - for(int i=0; i=0); + testname.c_str(), msg.c_str(), match, cnt, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); + *passed = (r == cnt && w == cnt && match && err>=0); } free(rxbuf); free(txbuf); } -// Maintain transfer for count OR count + + + void tcp_server_sustained_4(TCP_UNIT_TEST_SIG_4) { std::string testname = "tcp_server_sustained_4"; std::string msg = "tcp_sustained_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int n=0, w=0, r=0, sockfd, accfd, err; - char *rxbuf = (char*)malloc(count*sizeof(char)); - memset(rxbuf, 0, count); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "accept connection from host with IPv4 address, exchange a sequence of packets, check order.\n"); + int n=0, w=0, r=0, fd, client_fd, err; + char *rxbuf = (char*)malloc(cnt*sizeof(char)); + memset(rxbuf, 0, cnt); - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(addr)) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)addr, (socklen_t)sizeof(*addr)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); - if((err = zts_listen(sockfd, 1)) < 0) + perror("bind"); + *passed = false; + return; + } + if((err = LISTEN(fd, 1)) < 0) { DEBUG_ERROR("error placing socket in LISTENING state (%d)", err); - if((accfd = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) - DEBUG_ERROR("error accepting connection (%d)", err); - if(operation == TEST_OP_N_BYTES) { - int wrem = count, rrem = count; + perror("listen"); + *passed = false; + return; + } + struct sockaddr_in client; + socklen_t client_addrlen = sizeof(sockaddr_in); + if((client_fd = ACCEPT(fd, (struct sockaddr *)&client, &client_addrlen)) < 0) { + fprintf(stderr,"error accepting connection (%d)\n", err); + perror("accept"); + } + DEBUG_TEST("accepted connection from %s, on port %d", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + if(op == TEST_OP_N_BYTES) { + int wrem = cnt, rrem = cnt; long int rx_ti = 0; while(rrem) { - n = zts_read(accfd, &rxbuf[r], rrem); + n = READ(client_fd, &rxbuf[r], rrem); if (n > 0) { if(!rx_ti) { // wait for first message @@ -756,7 +1009,7 @@ void tcp_server_sustained_4(TCP_UNIT_TEST_SIG_4) long int tx_ti = get_now_ts(); while(wrem) { int next_write = std::min(1024, wrem); - n = zts_write(accfd, &rxbuf[w], next_write); + n = WRITE(client_fd, &rxbuf[w], next_write); if (n > 0) { w += n; @@ -766,48 +1019,70 @@ void tcp_server_sustained_4(TCP_UNIT_TEST_SIG_4) } long int tx_tf = get_now_ts(); DEBUG_TEST("wrote=%d", w); - sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - + err = CLOSE(fd); // Compute time deltas and transfer rates float tx_dt = (tx_tf - tx_ti) / (float)1000; float rx_dt = (rx_tf - rx_ti) / (float)1000; - float tx_rate = (float)count / (float)tx_dt; - float rx_rate = (float)count / (float)rx_dt; - + float tx_rate = (float)cnt / (float)tx_dt; + float rx_rate = (float)cnt / (float)rx_dt; sprintf(details, "%s, n=%d, tx_dt=%.2f, rx_dt=%.2f, r=%d, w=%d, tx_rate=%.2f MB/s, rx_rate=%.2f MB/s", - testname.c_str(), count, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); + testname.c_str(), cnt, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); - *passed = (r == count && w == count && err>=0); + *passed = (r == cnt && w == cnt && err>=0); } free(rxbuf); } -// Maintain transfer for count OR count + + + void tcp_server_sustained_6(TCP_UNIT_TEST_SIG_6) { std::string testname = "tcp_server_sustained_6"; std::string msg = "tcp_sustained_6"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int n=0, w=0, r=0, sockfd, accfd, err; - char *rxbuf = (char*)malloc(count*sizeof(char)); - memset(rxbuf, 0, count); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "accept connection from host with IPv6 address, exchange a sequence of packets, check order.\n"); + int n=0, w=0, r=0, fd, client_fd, err; + char *rxbuf = (char*)malloc(cnt*sizeof(char)); + memset(rxbuf, 0, cnt); - if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET6, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) + perror("socket"); + *passed = false; + return; + } + if((err = BIND(fd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in6)) < 0)) { DEBUG_ERROR("error binding to interface (%d)", err); - if((err = zts_listen(sockfd, 1)) < 0) + perror("bind"); + *passed = false; + return; + } + if((err = LISTEN(fd, 1)) < 0) { DEBUG_ERROR("error placing socket in LISTENING state (%d)", err); - if((accfd = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) - DEBUG_ERROR("error accepting connection (%d)", err); - if(operation == TEST_OP_N_BYTES) { - int wrem = count, rrem = count; + perror("listen"); + *passed = false; + return; + } + struct sockaddr_in6 client; + socklen_t client_addrlen = sizeof(sockaddr_in6); + if((client_fd = ACCEPT(fd, (struct sockaddr *)&client, &client_addrlen)) < 0) { + fprintf(stderr,"error accepting connection (%d)\n", err); + perror("accept"); + *passed = false; + return; + } + char ipstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &client.sin6_addr, ipstr, sizeof ipstr); + DEBUG_TEST("accepted connection from %s, on port %d", ipstr, ntohs(client.sin6_port)); + + if(op == TEST_OP_N_BYTES) { + int wrem = cnt, rrem = cnt; long int rx_ti = 0; while(rrem) { - n = zts_read(accfd, &rxbuf[r], rrem); + n = READ(client_fd, &rxbuf[r], rrem); if (n > 0) { if(!rx_ti) { // wait for first message @@ -823,7 +1098,7 @@ void tcp_server_sustained_6(TCP_UNIT_TEST_SIG_6) long int tx_ti = get_now_ts(); while(wrem) { int next_write = std::min(1024, wrem); - n = zts_write(accfd, &rxbuf[w], next_write); + n = WRITE(client_fd, &rxbuf[w], next_write); if (n > 0) { w += n; @@ -834,90 +1109,230 @@ void tcp_server_sustained_6(TCP_UNIT_TEST_SIG_6) long int tx_tf = get_now_ts(); DEBUG_TEST("wrote=%d", w); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - + err = CLOSE(fd); // Compute time deltas and transfer rates float tx_dt = (tx_tf - tx_ti) / (float)1000; float rx_dt = (rx_tf - rx_ti) / (float)1000; - float tx_rate = (float)count / (float)tx_dt; - float rx_rate = (float)count / (float)rx_dt; - + float tx_rate = (float)cnt / (float)tx_dt; + float rx_rate = (float)cnt / (float)rx_dt; sprintf(details, "%s, n=%d, tx_dt=%.2f, rx_dt=%.2f, r=%d, w=%d, tx_rate=%.2f MB/s, rx_rate=%.2f MB/s", - testname.c_str(), count, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); + testname.c_str(), cnt, tx_dt, rx_dt, r, w, (tx_rate / float(ONE_MEGABYTE) ), (rx_rate / float(ONE_MEGABYTE) )); - *passed = (r == count && w == count && err>=0); + *passed = (r == cnt && w == cnt && err>=0); } free(rxbuf); } -void udp_client_sustained_4(TCP_UNIT_TEST_SIG_4) + + + + +void udp_client_sustained_4(UDP_UNIT_TEST_SIG_4) { std::string testname = "udp_client_sustained_4"; std::string msg = "udp_sustained_4"; - fprintf(stderr, "\n\n%s\n\n", testname.c_str()); - int r, w, sockfd, err, len = strlen(msg.c_str()); + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv4 address, TX n-datagrams\n"); + int w, fd, err, len = strlen(msg.c_str()); char rbuf[STR_SIZE]; memset(rbuf, 0, sizeof rbuf); - if((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) + + if((fd = SOCKET(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); - - for(int i=0; i<1000; i++) { - w = zts_sendto(sockfd, msg.c_str(), strlen(msg.c_str()), 0, (struct sockaddr *)addr, sizeof(addr)); + perror("socket"); + *passed = false; + return; + } + if((err = FCNTL(fd, F_SETFL, O_NONBLOCK) < 0)) { + fprintf(stderr, "error setting O_NONBLOCK (errno=%d)", errno); + perror("fcntl"); + *passed = false; + return; + } + DEBUG_TEST("sending UDP packets until I get a single response..."); + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) { + DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; } - memset(rbuf, 0, sizeof(rbuf)); - int serverlen = sizeof(addr); - r = zts_recvfrom(sockfd, rbuf, STR_SIZE, 0, (struct sockaddr *)&addr, (socklen_t *)&serverlen); + int num_to_send = 10; + for(int i=0; isin_addr), addrstr, INET_ADDRSTRLEN); + // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see + DEBUG_TEST("received DGRAM from %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + DEBUG_TEST("sending DGRAM(s) to %s : %d", inet_ntoa(remote_addr->sin_addr), ntohs(remote_addr->sin_port)); + } + + sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); + //err = CLOSE(fd); + DEBUG_TEST("%s, n=%d, err=%d, r=%d", testname.c_str(), cnt, err, r); + sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), cnt, err, r); DEBUG_TEST("Received : %s", rbuf); - *passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str()); + *passed = (r == len && !err) && !strcmp(rbuf, msg.c_str()); +} + + + + + +void udp_client_sustained_6(UDP_UNIT_TEST_SIG_6) +{ + std::string testname = "udp_client_sustained_6"; + std::string msg = "udp_sustained_6"; + fprintf(stderr, "\n\n%s\n", testname.c_str()); + fprintf(stderr, "bind to interface with IPv6 address, TX n-datagrams\n"); + int w, fd, err, len = strlen(msg.c_str()); + char rbuf[STR_SIZE]; + memset(rbuf, 0, sizeof rbuf); + if((fd = SOCKET(AF_INET6, SOCK_DGRAM, 0)) < 0) { + DEBUG_ERROR("error creating ZeroTier socket"); + perror("socket"); + *passed = false; + return; + } + if((err = FCNTL(fd, F_SETFL, O_NONBLOCK) < 0)) { + fprintf(stderr, "error setting O_NONBLOCK (errno=%d)", errno); + perror("fcntl"); + *passed = false; + return; + } + DEBUG_TEST("sending UDP packets until I get a single response..."); + if((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) { + DEBUG_ERROR("error binding to interface (%d)", err); + perror("bind"); + *passed = false; + return; + } + int num_to_send = 10; + for(int i=0; isin6_addr), addrstr, INET6_ADDRSTRLEN); + // once we receive a UDP packet, spend 10 seconds sending responses in the hopes that the client will see + //DEBUG_TEST("received DGRAM from %s : %d", inet_ntoa(in6->sin6_addr), ntohs(in6->sin6_port)); + //DEBUG_TEST("sending DGRAM(s) to %s : %d", inet_ntoa(remote_addr->sin6_addr), ntohs(remote_addr->sin6_port)); + } + sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); + //err = CLOSE(fd); + DEBUG_TEST("%s, n=%d, err=%d, r=%d", testname.c_str(), cnt, err, r); + sprintf(details, "%s, n=%d, err=%d, r=%d, w=%d", testname.c_str(), cnt, err, r); + DEBUG_TEST("Received : %s", rbuf); + *passed = (r == len && !err) && !strcmp(rbuf, msg.c_str()); } /****************************************************************************/ /* PERFORMANCE (between library instances) */ /****************************************************************************/ -// Maintain transfer for count OR count +// Maintain transfer for cnt OR cnt void tcp_client_perf_4(TCP_UNIT_TEST_SIG_4) { fprintf(stderr, "\n\n\ntcp_client_perf_4\n"); /* - int w=0, sockfd, err; - int total_test_sz = count; + int w=0, fd, err; + int total_test_sz = cnt; int arbitrary_chunk_sz_max = MAX_RX_BUF_SZ; int arbitrary_chunk_sz_min = 512; @@ -925,9 +1340,9 @@ void tcp_client_perf_4(TCP_UNIT_TEST_SIG_4) for (int i=arbitrary_chunk_sz_min; (i*2) < arbitrary_chunk_sz_max; i*=2) { - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(addr))) < 0) DEBUG_ERROR("error connecting to remote host (%d)", err); DEBUG_TEST("[TX] Testing (%d) byte chunks: ", i); @@ -938,25 +1353,25 @@ void tcp_client_perf_4(TCP_UNIT_TEST_SIG_4) // TX while(w < total_test_sz) - w += zts_write(sockfd, rbuf, chunk_sz); + w += WRITE(fd, rbuf, chunk_sz); long int end_time = get_now_ts(); float ts_delta = (end_time - start_time) / (float)1000; float rate = (float)total_test_sz / (float)ts_delta; sprintf(details, "tot=%d, dt=%.2f, rate=%.2f MB/s", w, ts_delta, (rate / float(ONE_MEGABYTE) )); - zts_close(sockfd); + CLOSE(fd); } *passed = (w == total_test_sz && !err) ? PASSED : FAILED; */ } -// Maintain transfer for count OR count +// Maintain transfer for cnt OR cnt void tcp_server_perf_4(TCP_UNIT_TEST_SIG_4) { fprintf(stderr, "\n\n\ntcp_server_perf_4\n"); /* - int r=0, sockfd, accfd, err; - int total_test_sz = count; + int r=0, fd, client_fd, err; + int total_test_sz = cnt; int arbitrary_chunk_sz_max = MAX_RX_BUF_SZ; int arbitrary_chunk_sz_min = 512; @@ -964,13 +1379,13 @@ void tcp_server_perf_4(TCP_UNIT_TEST_SIG_4) for (int i=arbitrary_chunk_sz_min; (i*2) < arbitrary_chunk_sz_max; i*=2) { DEBUG_ERROR("TESTING chunk size = %d", i); - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) DEBUG_ERROR("error creating ZeroTier socket"); - if((err = zts_bind(sockfd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) + if((err = BIND(fd, (struct sockaddr *)addr, (socklen_t)sizeof(struct sockaddr_in)) < 0)) DEBUG_ERROR("error binding to interface (%d)", err); - if((err = zts_listen(sockfd, 1)) < 0) + if((err = LISTEN(fd, 1)) < 0) DEBUG_ERROR("error placing socket in LISTENING state (%d)", err); - if((accfd = zts_accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) + if((client_fd = ACCEPT(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr))) < 0) DEBUG_ERROR("error accepting connection (%d)", err); DEBUG_TEST("[RX] Testing (%d) byte chunks: ", i); @@ -981,7 +1396,7 @@ void tcp_server_perf_4(TCP_UNIT_TEST_SIG_4) // RX while(r < total_test_sz) - r += zts_read(accfd, rbuf, chunk_sz); + r += READ(client_fd, rbuf, chunk_sz); long int end_time = get_now_ts(); @@ -990,8 +1405,8 @@ void tcp_server_perf_4(TCP_UNIT_TEST_SIG_4) sprintf(details, "tot=%d, dt=%.2f, rate=%.2f MB/s", r, ts_delta, (rate / float(ONE_MEGABYTE) )); - zts_close(sockfd); - zts_close(accfd); + CLOSE(fd); + CLOSE(client_fd); } *passed = (r == total_test_sz && !err) ? PASSED : FAILED; */ @@ -1013,7 +1428,7 @@ void tcp_perf_tx_echo_4(TCP_UNIT_TEST_SIG_4) int err = 0; int tot = 0; int w = 0; - int sockfd, mode; + int fd, mode; char pbuf[64]; // test parameter buffer char tbuf[MAX_TX_BUF_SZ]; @@ -1021,11 +1436,11 @@ void tcp_perf_tx_echo_4(TCP_UNIT_TEST_SIG_4) mode = ECHOTEST_MODE_TX; // connect to remote echotest host - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) { + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); return; } - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) { + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) { DEBUG_ERROR("error connecting to remote host (%d)", err); return; } @@ -1033,18 +1448,18 @@ void tcp_perf_tx_echo_4(TCP_UNIT_TEST_SIG_4) DEBUG_TEST("copying test parameters to buffer"); memset(pbuf, 0, sizeof pbuf); memcpy(pbuf, &mode, sizeof mode); - memcpy(pbuf + sizeof mode, &count, sizeof count); + memcpy(pbuf + sizeof mode, &cnt, sizeof cnt); DEBUG_TEST("sending test parameters to echotest"); - if((w = zts_write(sockfd, pbuf, sizeof pbuf)) < 0) { + if((w = WRITE(fd, pbuf, sizeof pbuf)) < 0) { DEBUG_ERROR("error while sending test parameters to echotest (err=%d)", w); return; } // begin DEBUG_TEST("beginning test, sending test byte stream..."); - while(tot < count) { - if((w = zts_write(sockfd, tbuf, sizeof tbuf)) < 0) { + while(tot < cnt) { + if((w = WRITE(fd, tbuf, sizeof tbuf)) < 0) { DEBUG_ERROR("error while sending test byte stream to echotest (err=%d)", w); return; } @@ -1054,7 +1469,7 @@ void tcp_perf_tx_echo_4(TCP_UNIT_TEST_SIG_4) // read results memset(pbuf, 0, sizeof pbuf); DEBUG_TEST("reading test results from echotest"); - if((w = zts_read(sockfd, pbuf, sizeof tbuf)) < 0) { + if((w = READ(fd, pbuf, sizeof tbuf)) < 0) { DEBUG_ERROR("error while reading results from echotest (err=%d)", w); return; } @@ -1069,8 +1484,8 @@ void tcp_perf_tx_echo_4(TCP_UNIT_TEST_SIG_4) sprintf(details, "%s, tot=%d, dt=%.2f, rate=%.2f MB/s", msg.c_str(), tot, ts_delta, (rate / float(ONE_MEGABYTE) )); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - *passed = (tot == count && !err) ? PASSED : FAILED; + err = CLOSE(fd); + *passed = (tot == cnt && !err) ? PASSED : FAILED; } @@ -1086,16 +1501,16 @@ void tcp_perf_rx_echo_4(TCP_UNIT_TEST_SIG_4) char pbuf[64]; // test parameter buffer char tbuf[MAX_TX_BUF_SZ]; - int sockfd; + int fd; mode = ECHOTEST_MODE_RX; // connect to remote echotest host - if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) { + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) { DEBUG_ERROR("error creating ZeroTier socket"); return; } - if((err = zts_connect(sockfd, (const struct sockaddr *)addr, sizeof(addr))) < 0) { + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) { DEBUG_ERROR("error connecting to remote host (%d)", err); return; } @@ -1103,17 +1518,17 @@ void tcp_perf_rx_echo_4(TCP_UNIT_TEST_SIG_4) DEBUG_TEST("copying test parameters to buffer"); memset(pbuf, 0, sizeof pbuf); memcpy(pbuf, &mode, sizeof mode); - memcpy(pbuf + sizeof mode, &count, sizeof count); + memcpy(pbuf + sizeof mode, &cnt, sizeof cnt); DEBUG_TEST("sending test parameters to echotest"); - if((r = zts_write(sockfd, pbuf, sizeof pbuf)) < 0) { + if((r = WRITE(fd, pbuf, sizeof pbuf)) < 0) { DEBUG_ERROR("error while sending test parameters to echotest (err=%d)", r); return; } // begin DEBUG_TEST("beginning test, as soon as bytes are read we will start keeping time..."); - if((r = read(sockfd, tbuf, sizeof tbuf)) < 0) { + if((r = read(fd, tbuf, sizeof tbuf)) < 0) { DEBUG_ERROR("there was an error reading the test stream. aborting (err=%d, errno=%s)", r, strerror(errno)); return; } @@ -1123,8 +1538,8 @@ void tcp_perf_rx_echo_4(TCP_UNIT_TEST_SIG_4) long int start_time = get_now_ts(); DEBUG_TEST("Received first set of bytes in test stream. now keeping time"); - while(tot < count) { - if((r = read(sockfd, tbuf, sizeof tbuf)) < 0) { + while(tot < cnt) { + if((r = read(fd, tbuf, sizeof tbuf)) < 0) { DEBUG_ERROR("there was an error reading the test stream. aborting (err=%d)", r); return; } @@ -1137,8 +1552,8 @@ void tcp_perf_rx_echo_4(TCP_UNIT_TEST_SIG_4) sprintf(details, "%s, tot=%d, dt=%.2f, rate=%.2f MB/s", msg.c_str(), tot, ts_delta, (rate / float(ONE_MEGABYTE) )); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); - err = zts_close(sockfd); - *passed = (tot == count && !err) ? PASSED : FAILED; + err = CLOSE(fd); + *passed = (tot == cnt && !err) ? PASSED : FAILED; } @@ -1149,6 +1564,8 @@ void tcp_perf_rx_echo_4(TCP_UNIT_TEST_SIG_4) /* SLAM API (multiple of each api call and/or plausible call sequence) */ /****************************************************************************/ +#if defined(__SELFTEST__) + #define SLAM_NUMBER 16 #define SLAM_REPEAT 1 @@ -1161,7 +1578,7 @@ int slam_api_test() struct sockaddr_in6 addr6; struct sockaddr_in addr; - // int start_stack_timer_count = pico_ntimers(); // number of picoTCP timers allocated + // int start_stack_timer_cnt = pico_ntimers(); // number of picoTCP timers allocated // TESTS: // socket() @@ -1175,7 +1592,7 @@ int slam_api_test() // create sockets int fds[SLAM_NUMBER]; for(int i = 0; i 0) { - if((err = zts_close(sock)) < 0) { + if((err = CLOSE(sock)) < 0) { std::cout << "error closing socket (errno = " << strerror(errno) << ")" << std::endl; //return -1; } @@ -1296,12 +1713,12 @@ int slam_api_test() // socket() printf("creating socket... (%d)\n", j); - if((sock = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) + if((sock = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) std::cout << "error creating socket (errno = " << strerror(errno) << ")" << std::endl; results[j] = std::min(results[j], sock); // set O_NONBLOCK - if((err = zts_fcntl(sock, F_SETFL, O_NONBLOCK) < 0)) + if((err = FCNTL(sock, F_SETFL, O_NONBLOCK) < 0)) std::cout << "error setting O_NONBLOCK (errno=" << strerror(errno) << ")" << std::endl; results[j] = std::min(results[j], err); @@ -1313,14 +1730,14 @@ int slam_api_test() addr6.sin6_family = AF_INET6; addr6.sin6_port = htons(port); addr6.sin6_addr = in6addr_any; - err = zts_connect(sock, (struct sockaddr *)&addr6, (socklen_t)(sizeof addr6)); + err = CONNECT(sock, (struct sockaddr *)&addr6, (socklen_t)(sizeof addr6)); } if(true) { addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr("10.9.9.51"); //addr.sin_addr.s_addr = htons(INADDR_ANY); addr.sin_family = AF_INET; - err = zts_connect(sock, (struct sockaddr *)&addr, (socklen_t)(sizeof addr)); + err = CONNECT(sock, (struct sockaddr *)&addr, (socklen_t)(sizeof addr)); } if(errno != EINPROGRESS) { // acceptable error for non-block mode @@ -1330,7 +1747,7 @@ int slam_api_test() } // close() - if((err = zts_close(sock)) < 0) + if((err = CLOSE(sock)) < 0) std::cout << "error closing socket (errno = " << strerror(errno) << ")" << std::endl; results[j] = std::min(results[j], err); } @@ -1350,8 +1767,49 @@ int slam_api_test() int obscure_api_test() { + /* + // getpeername() + int fd, client_fd; + + // after accept() + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) + DEBUG_ERROR("error creating ZeroTier socket"); + if((err = BIND(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) + DEBUG_ERROR("error binding to interface (%d)", err); + if((err = LISTEN(fd, 100)) < 0) + printf("error placing socket in LISTENING state (%d)", err); + // accept + struct sockaddr_in client; + socklen_t client_addrlen = sizeof(sockaddr_in); + if((client_fd = accept(fd, (struct sockaddr *)&client, &client_addrlen)) < 0) + fprintf(stderr,"error accepting connection (%d)\n", err); + fprintf(stderr, "accepted connection from %s, on port %d", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + // getpeername + struct sockaddr_storage peer_addr; + struct sockaddr_in *in4 = (struct sockaddr_in*)&peer_addr; + socklen_t peer_addrlen = sizeof(peer_addr); + GETPEERNAME(fd, (struct sockaddr*)&peer_addr, &peer_addrlen); + DEBUG_TEST("getpeername() => %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + // compate getpeername() result to address returned by accept() + + // after connect + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) + DEBUG_ERROR("error creating ZeroTier socket"); + if((err = CONNECT(fd, (const struct sockaddr *)addr, sizeof(*addr))) < 0) + DEBUG_ERROR("error connecting to remote host (%d)", err); + // TODO: Put this test in the general API section + struct sockaddr_storage peer_addr; + struct sockaddr_in *in4 = (struct sockaddr_in*)&peer_addr; + socklen_t peer_addrlen = sizeof(peer_addr); + GETPEERNAME(fd, (struct sockaddr*)&peer_addr, &peer_addrlen); + DEBUG_TEST("getpeername() => %s : %d", inet_ntoa(in4->sin_addr), ntohs(in4->sin_port)); + // compare result of getpeername to remote address + + // TODO: write an ipv6 version of the above ^^^ + */ + // Disable Nagle's Algorithm on a socket - int sock = zts_socket(AF_INET, SOCK_STREAM, 0); + int sock = SOCKET(AF_INET, SOCK_STREAM, 0); int flag = 1; int err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); if (err < 0) { @@ -1374,7 +1832,7 @@ void get_network_routes(char *nwid) char via_str[INET6_ADDRSTRLEN]; memset(via_str, 0, INET6_ADDRSTRLEN); inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)via)->sin_addr.s_addr, via_str, INET_ADDRSTRLEN); - DEBUG_INFO("", target_str, via_str, routes->at(i).flags); + DEBUG_TEST("", target_str, via_str, routes->at(i).flags); } } @@ -1384,45 +1842,74 @@ void get_network_routes(char *nwid) int random_api_test() { - /* // PASSED implies we didn't segfault or hang anywhere - // - int calls_made = 0; - - // how many calls we'll make - int num_of_api_calls = 10; - - - zts_socket() - zts_connect() - zts_listen() - zts_accept() - zts_bind() - zts_getsockopt() - zts_setsockopt() - zts_fnctl() - zts_close() - // variables which will be populated with random values - int fd, arg_val; + int socket_family; + int socket_type; + int protocol; + int fd; + int len; + int addrlen; + int flags; + + struct sockaddr_storage; struct sockaddr_in addr; struct sockaddr_in6 addr6; - while(calls_made < num_of_api_calls) - { - fprintf(stderr, "calls_made=%d\n", calls_made); - int random_call = 0; + /* + int num_operations = 100; + char *opbuf = (char*)malloc(num_operations*sizeof(char)); + generate_random_data(opbuf, num_operations, 0, 9); + for(int i=0; isin_port++; } } @@ -1628,12 +2115,12 @@ void bind_to_localhost_test(int port) int fd, err = 0; // ipv4, 0.0.0.0 struct sockaddr_storage bind_addr; - DEBUG_INFO("binding to 0.0.0.0"); - create_addr("0.0.0.0", port, 4, (struct sockaddr *)&bind_addr); - if((fd = zts_socket(AF_INET, SOCK_STREAM, 0)) > 0) { - if((err = zts_bind(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { + DEBUG_TEST("binding to 0.0.0.0"); + str2addr("0.0.0.0", port, 4, (struct sockaddr *)&bind_addr); + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) > 0) { + if((err = BIND(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { usleep(100000); - if((err = zts_close(fd)) < 0) { + if((err = CLOSE(fd)) < 0) { DEBUG_ERROR("error closing socket (%d)", err); } } @@ -1649,12 +2136,12 @@ void bind_to_localhost_test(int port) /* // ipv4, 127.0.0.1 - DEBUG_INFO("binding to 127.0.0.1"); - create_addr("127.0.0.1", port, 4, (struct sockaddr *)&bind_addr); - if((fd = zts_socket(AF_INET, SOCK_STREAM, 0)) > 0) { - if((err = zts_bind(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { + DEBUG_TEST("binding to 127.0.0.1"); + str2addr("127.0.0.1", port, 4, (struct sockaddr *)&bind_addr); + if((fd = SOCKET(AF_INET, SOCK_STREAM, 0)) > 0) { + if((err = BIND(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { usleep(100000); - if((err = zts_close(fd)) < 0) { + if((err = CLOSE(fd)) < 0) { DEBUG_ERROR("error closing socket (%d)", err); } } @@ -1670,12 +2157,12 @@ void bind_to_localhost_test(int port) */ // ipv6, [::] - DEBUG_INFO("binding to [::]"); - create_addr("::", port, 6, (struct sockaddr *)&bind_addr); - if((fd = zts_socket(AF_INET6, SOCK_STREAM, 0)) > 0) { - if((err = zts_bind(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { + DEBUG_TEST("binding to [::]"); + str2addr("::", port, 6, (struct sockaddr *)&bind_addr); + if((fd = SOCKET(AF_INET6, SOCK_STREAM, 0)) > 0) { + if((err = BIND(fd, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr_in))) == 0) { usleep(100000); - if((err = zts_close(fd)) < 0) { + if((err = CLOSE(fd)) < 0) { DEBUG_ERROR("error closing socket (%d)", err); } } @@ -1688,6 +2175,8 @@ void bind_to_localhost_test(int port) } } +#endif // __SELFTEST__ + /****************************************************************************/ /* main(), calls test_driver(...) */ /****************************************************************************/ @@ -1703,50 +2192,54 @@ int main(int argc , char *argv[]) std::string from = argv[2]; std::string to = argv[4]; std::string me = from; - std::vector results; - - int err = 0; - int mode = 0; - int port = 0; - int operation = 0; - int start_port = 0; - int port_offset = 0; - int count = 0; - int delay = 0; - std::string remote_echo_ipv4, smode; std::string nwid, stype, path = argv[1]; std::string ipstr, ipstr6, local_ipstr, local_ipstr6, remote_ipstr, remote_ipstr6; + int err = 0; + int mode = 0; + int port = 0; + int op = 0; + int start_port = 0; + int cnt = 0; + int ipv; + // for timing + // how long we expect the specific test to take + int subtest_expected_duration; + // (T+X), when we plan to start this test + int subtest_start_time_offset = 0; + + char details[128]; + memset(&details, 0, sizeof details); + bool passed = 0; + struct sockaddr_storage local_addr; + struct sockaddr_storage remote_addr; + // load config file if(path.find(".conf") == std::string::npos) { fprintf(stderr, "Possibly invalid conf file. Exiting...\n"); exit(0); } loadTestConfigFile(path); - // get origin details - local_ipstr = testConf[me + ".ipv4"]; - local_ipstr6 = testConf[me + ".ipv6"]; - nwid = testConf[me + ".nwid"]; - path = testConf[me + ".path"]; - stype = testConf[me + ".test"]; - smode = testConf[me + ".mode"]; - start_port = atoi(testConf[me + ".port"].c_str()); - port_offset = 100; - - // get destination details + local_ipstr = testConf[me + ".ipv4"]; + local_ipstr6 = testConf[me + ".ipv6"]; + nwid = testConf[me + ".nwid"]; + path = testConf[me + ".path"]; + stype = testConf[me + ".test"]; + smode = testConf[me + ".mode"]; + start_port = atoi(testConf[me + ".port"].c_str()); remote_echo_ipv4 = testConf[to + ".echo_ipv4"]; - remote_ipstr = testConf[to + ".ipv4"]; - remote_ipstr6 = testConf[to + ".ipv6"]; + remote_ipstr = testConf[to + ".ipv4"]; + remote_ipstr6 = testConf[to + ".ipv6"]; if(strcmp(smode.c_str(), "server") == 0) mode = TEST_MODE_SERVER; else mode = TEST_MODE_CLIENT; - fprintf(stderr, "ORIGIN:\n\n"); + fprintf(stderr, "\n\nORIGIN:\n\n"); fprintf(stderr, "\tlocal_ipstr = %s\n", local_ipstr.c_str()); fprintf(stderr, "\tlocal_ipstr6 = %s\n", local_ipstr6.c_str()); fprintf(stderr, "\tstart_port = %d\n", start_port); @@ -1758,6 +2251,11 @@ int main(int argc , char *argv[]) fprintf(stderr, "\tremote_ipstr6 = %s\n", remote_ipstr6.c_str()); fprintf(stderr, "\tremote_echo_ipv4 = %s\n", remote_echo_ipv4.c_str()); +#if defined(__SELFTEST__) + // set start time here since we need to wait for both libzt instances to be online + long int selftest_start_time = get_now_ts(); + subtest_expected_duration = 30; + DEBUG_TEST("Waiting for libzt to come online...\n"); zts_simple_start(path.c_str(), nwid.c_str()); char device_id[ZT_ID_LEN]; @@ -1767,6 +2265,7 @@ int main(int argc , char *argv[]) DEBUG_TEST("Ready. You should start selftest program on second host now...\n\n"); if(mode == TEST_MODE_CLIENT) DEBUG_TEST("Ready. Contacting selftest program on first host.\n\n"); +#endif // __SELFTEST__ // What follows is a long-form of zts_simple_start(): /* @@ -1781,35 +2280,21 @@ int main(int argc , char *argv[]) sleep(1); */ - /****************************************************************************/ - /* COMPREHENSIVE */ - /****************************************************************************/ - - int test_number = 0, ipv; - char details[128]; - memset(&details, 0, sizeof details); - bool passed = 0; - - struct sockaddr_storage local_addr; - struct sockaddr_storage remote_addr; - - // closure test -/* +#if defined(__SELFTEST__) port = 1000; struct sockaddr_in in4; - DEBUG_INFO("testing closures by binding to: %s", local_ipstr.c_str()); - create_addr(local_ipstr, port, 4, (struct sockaddr *)&in4); + DEBUG_TEST("testing closures by binding to: %s", local_ipstr.c_str()); + str2addr(local_ipstr, port, 4, (struct sockaddr *)&in4); close_test((struct sockaddr*)&in4); port++; -*/ // Test adding, resolving, and removing a DNS server - ipv = 4; - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - dns_test((struct sockaddr *)&remote_addr); +// ipv = 4; +// str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); +// dns_test((struct sockaddr *)&remote_addr); // close_while_writing_test(); @@ -1831,233 +2316,346 @@ int main(int argc , char *argv[]) // OBSCURE API TEST //obscure_api_test(); - port = start_port; - delay = 0; - count = 1024*128; - operation = TEST_OP_N_BYTES; +#endif // __SELFTEST__ -// ipv4 client/server (UDP) + port = start_port; + cnt = 1024*128; + op = TEST_OP_N_BYTES; + +/* + tcp-ip4-client tcp-ip6-client udp-ip4-client udp-ip6-client + | | | | | +tcp-ip4-server | OK | | OK | | +tcp-ip6-server | | OK | | OK | +udp-ip4-server | OK | | OK | | +udp-ip6-server | | OK | | OK | + +*/ + +// set start time here since we aren't waiting for libzt to come online in NATIVETEST mode +#if defined(__NATIVETEST__) + long int selftest_start_time = get_now_ts(); + subtest_expected_duration = 10; // initial value, wait for other instance to come online +#endif + + +#if defined(LIBZT_IPV4) + // UDP 4 client/server + + ipv = 4; + subtest_start_time_offset += subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; + +// UDP 4 sustained transfer + + ipv = 4; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_sustained_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_sustained_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_sustained_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_sustained_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; + +// TCP 4 client/server ipv = 4; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - udp_server_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_4((struct sockaddr_in *)&local_addr, op, cnt, details, &passed); } else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - udp_client_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); } - RECORD_RESULTS(&test_number, passed, details, &results); + RECORD_RESULTS(passed, details, &results); mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - udp_server_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_4((struct sockaddr_in *)&local_addr, op, cnt, details, &passed); } else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - udp_client_4((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); } - RECORD_RESULTS(&test_number, passed, details, &results); + RECORD_RESULTS(passed, details, &results); port++; -// ipv6 client/server (UDP) - ipv = 6; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr*)&local_addr); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr*)&remote_addr); - udp_server_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - udp_client_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles - port++; // move up one port - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - udp_server_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - udp_client_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - port++; - - -// ipv4 sustained transfer (UDP) - ipv = 4; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles - port++; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - port++; - -// ipv4 client/server - ipv = 4; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles - port++; // move up one port - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - port++; - -// ipv4 sustained transfer (TCP) +// TCP 4 sustained transfer ipv = 4; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_sustained_4((struct sockaddr_in *)&local_addr, op, cnt, details, &passed); } else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); } - RECORD_RESULTS(&test_number, passed, details, &results); // swtich roles + RECORD_RESULTS(passed, details, &results); mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles port++; + subtest_start_time_offset+=subtest_expected_duration; if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_4((struct sockaddr_in *)&local_addr, operation, count, delay, details, &passed); + str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_sustained_4((struct sockaddr_in *)&local_addr, op, cnt, details, &passed); } else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); + str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_sustained_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); } - RECORD_RESULTS(&test_number, passed, details, &results); + RECORD_RESULTS(passed, details, &results); port++; -// ipv6 client/server (TCP) - ipv = 6; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_6((struct sockaddr_in6 *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - DEBUG_TEST("waiting (15s) for other selftest to complete before continuing..."); - sleep(WAIT_FOR_TEST_TO_CONCLUDE); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_6((struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles - port++; // move up one port - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_6((struct sockaddr_in6 *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_6((struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - port++; + // PERFORMANCE (between this library instance and a native non library instance (echo) ) + // Client/Server mode isn't being tested here, so it isn't important, we'll just set it to client -// ipv6 sustained transfer (TCP) - ipv = 6; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_6((struct sockaddr_in6 *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_6((struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles - port++; - if(mode == TEST_MODE_SERVER) { - create_addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); - tcp_server_sustained_6((struct sockaddr_in6 *)&local_addr, operation, count, delay, details, &passed); - } - else if(mode == TEST_MODE_CLIENT) { - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - create_addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); - tcp_client_sustained_6((struct sockaddr_in6 *)&remote_addr, operation, count, delay, details, &passed); - } - RECORD_RESULTS(&test_number, passed, details, &results); - port++; - -// PERFORMANCE (between this library instance and a native non library instance (echo) ) -// Client/Server mode isn't being tested here, so it isn't important, we'll just set it to client - -// ipv4 echo test (TCP) + // ipv4 echo test (TCP) /* ipv = 4; if(me == "alice" || me == "ted") { port=start_port+100; // e.g. 7100 - create_addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr); - tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - RECORD_RESULTS(&test_number, passed, details, &results); - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - RECORD_RESULTS(&test_number, passed, details, &results); + str2addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr); + tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + RECORD_RESULTS(passed, details, &results); + tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + RECORD_RESULTS(passed, details, &results); } if(me == "bob" || me == "carol") { DEBUG_TEST("waiting (15s) for other selftest to complete before continuing..."); - sleep(WAIT_FOR_TEST_TO_CONCLUDE); port=start_port+101; // e.g. 7101 - create_addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr); - tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - RECORD_RESULTS(&test_number, passed, details, &results); - sleep(WAIT_FOR_SERVER_TO_COME_ONLINE); - tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, operation, count, delay, details, &passed); - RECORD_RESULTS(&test_number, passed, details, &results); + str2addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr); + tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + RECORD_RESULTS(passed, details, &results); + tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed); + RECORD_RESULTS(passed, details, &results); } */ +#endif // LIBZT_IPV4 + + + + + +#if defined(LIBZT_IPV6) + // UDP 6 client/server + + ipv = 6; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr*)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr*)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; + + + +// UDP 6 sustained transfer + + ipv = 6; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_sustained_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_sustained_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + udp_server_sustained_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + udp_client_sustained_6((struct sockaddr_in6 *)&local_addr, (struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; + +// TCP 6 client/server + + ipv = 6; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_6((struct sockaddr_in6 *)&local_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + DEBUG_TEST("waiting (15s) for other selftest to complete before continuing..."); + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_6((struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; // move up one port + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_6((struct sockaddr_in6 *)&local_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_6((struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; + +// TCP 6 sustained transfer + + ipv = 6; + subtest_start_time_offset+=subtest_expected_duration; + subtest_expected_duration = 30; + + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_sustained_6((struct sockaddr_in6 *)&local_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_sustained_6((struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + mode = mode == TEST_MODE_SERVER ? TEST_MODE_CLIENT : TEST_MODE_SERVER; // switch roles + port++; + subtest_start_time_offset+=subtest_expected_duration; + if(mode == TEST_MODE_SERVER) { + str2addr(local_ipstr6, port, ipv, (struct sockaddr *)&local_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset); + tcp_server_sustained_6((struct sockaddr_in6 *)&local_addr, op, cnt, details, &passed); + } + else if(mode == TEST_MODE_CLIENT) { + str2addr(remote_ipstr6, port, ipv, (struct sockaddr *)&remote_addr); + wait_until_tplus_s(selftest_start_time, subtest_start_time_offset+5); + tcp_client_sustained_6((struct sockaddr_in6 *)&remote_addr, op, cnt, details, &passed); + } + RECORD_RESULTS(passed, details, &results); + port++; +#endif // LIBZT_IPV6 + // Print results of all tests printf("--------------------------------------------------------------------------------\n"); for(int i=0;i." - exit -fi - -echo "killing $1" - -for f in "test/*.$1"; -do - pid=$(cat $f) - kill -9 $pid - rm -rf $f -done \ No newline at end of file