diff --git a/Makefile b/Makefile index e6e51e0..fd94799 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,8 @@ ifeq ($(OSTYPE),Linux) endif ifeq ($(OSTYPE),FreeBSD) - include make-freebsd.mk + include make-bsd.mk endif ifeq ($(OSTYPE),OpenBSD) - include make-freebsd.mk + include make-bsd.mk endif diff --git a/TESTING.md b/TESTING.md index 40ddf4b..101a38c 100644 --- a/TESTING.md +++ b/TESTING.md @@ -4,9 +4,9 @@ After building the static library, you can run: - `make tests` - This will output `selftest` to `build/$PLATFORM/`. Using this, you can run the tests below. Note, the following examples assume your testing environment is `linux`, you'll see this in the build output path. If this is not true, change it to `darwin`, or `win` depending on what you're running. + This will output `selftest` to `build/$PLATFORM/`. Using this, you can run the tests below. Note, the following examples assume your testing environment is `linux`, you'll see this in the build output path. If this is not true, change it to `darwin`, `freebsd`, or `win` depending on what you're running. - It is probably easiest to add out your `host-1` and `host-2` address, port, and network information to `test/alice.conf` and `test/bob.conf`, this way you can use the selftest shorthand shown below. + Simply add your `host-1` and `host-2` address, port, and network information to `test/alice.conf` and `test/bob.conf`, this way you can use the selftest shorthand shown below. The file contain examples of what you should do. Build outputs are as follows: diff --git a/artwork/ztapp.png b/artwork/ztapp.png new file mode 100644 index 0000000..972ea95 Binary files /dev/null and b/artwork/ztapp.png differ diff --git a/make-freebsd.mk b/make-bsd.mk similarity index 100% rename from make-freebsd.mk rename to make-bsd.mk diff --git a/make-mac.mk b/make-mac.mk index 984a6be..1a82087 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -211,7 +211,7 @@ UNIT_TEST_LIBS := -L$(BUILD) -lzt $(TEST_BUILD_DIR)/%: $(UNIT_TEST_SRC_DIR)/%.cpp @mkdir -p $(TEST_BUILD_DIR) - @-$(CXX) $(UNIT_TEST_INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) + @-$(CXX) $(CXXFLAGS) $(UNIT_TEST_INCLUDES) $(INCLUDES) -o $@ $< $(UNIT_TEST_LIBS) @-./check.sh $@ unit_tests: $(UNIT_TEST_OBJ_FILES) diff --git a/src/Connection.hpp b/src/Connection.hpp index cae7c4b..395795f 100644 --- a/src/Connection.hpp +++ b/src/Connection.hpp @@ -60,7 +60,7 @@ namespace ZeroTier { struct sockaddr_storage *peer_addr; // Address of connection call to remote host // RX/TX buffers - int txsz, rxsz; + int txsz = 0, rxsz = 0; unsigned char txbuf[ZT_TCP_TX_BUF_SZ]; unsigned char rxbuf[ZT_TCP_RX_BUF_SZ]; @@ -89,6 +89,7 @@ namespace ZeroTier { } sdk_fd = fdpair[0]; app_fd = fdpair[1]; + if(ZT_SOCK_BEHAVIOR_LINGER) { struct linger so_linger; so_linger.l_onoff = true; diff --git a/src/SocketTap.cpp b/src/SocketTap.cpp index 7e4d624..152fbd2 100644 --- a/src/SocketTap.cpp +++ b/src/SocketTap.cpp @@ -289,7 +289,7 @@ namespace ZeroTier { } picostack->pico_Close(conn); if(!conn->sock) { - DEBUG_EXTRA("invalid PhySocket"); + // DEBUG_EXTRA("invalid PhySocket"); return; } // Here we assume _tcpconns_m is already locked by caller diff --git a/src/ZeroTierSDK.cpp b/src/ZeroTierSDK.cpp index f2ced00..85a33c2 100644 --- a/src/ZeroTierSDK.cpp +++ b/src/ZeroTierSDK.cpp @@ -429,10 +429,11 @@ Darwin: [ ] [ECONNRESET] Remote host reset the connection request. */ int zts_connect(ZT_CONNECT_SIG) { - DEBUG_INFO("fd = %d", fd); + // DEBUG_INFO("fd = %d", fd); int err = 0; if(fd < 0) { errno = EBADF; + DEBUG_ERROR("EBADF"); err = -1; } if(!zt1Service) { @@ -460,8 +461,8 @@ int zts_connect(ZT_CONNECT_SIG) { // TODO: This is a hack, determine a proper way to do this iaddr.fromString(ipstr + std::string("/88")); } - DEBUG_INFO("ipstr= %s", ipstr); - DEBUG_INFO("iaddr= %s", iaddr.toString().c_str()); + //DEBUG_INFO("ipstr= %s", ipstr); + //DEBUG_INFO("iaddr= %s", iaddr.toString().c_str()); tap = zt1Service->getTap(iaddr); if(!tap) { DEBUG_ERROR("no route to host"); @@ -471,7 +472,7 @@ int zts_connect(ZT_CONNECT_SIG) { else { // pointer to tap we use in callbacks from the stack conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn); - DEBUG_INFO("found appropriate SocketTap"); + //DEBUG_INFO("found appropriate SocketTap"); // Semantically: tap->stack->connect err = tap->Connect(conn, fd, addr, addrlen); if(err == 0) { @@ -500,12 +501,18 @@ int zts_connect(ZT_CONNECT_SIG) { // to the multiplexer logic that this connection is complete and a success value can be sent to the // user application - socklen_t optlen; - socklen_t blocking; - zts_getsockopt(fd, SOL_SOCKET, O_NONBLOCK, &blocking, &optlen); + int f_err, blocking = 1; + if ((f_err = fcntl(fd, F_GETFL, 0)) < 0) { + DEBUG_ERROR("fcntl error, err = %s, errno = %d", f_err, errno); + err = -1; + } + else { + blocking = !(f_err & O_NONBLOCK); + } // non-blocking if(err == 0 && !blocking) { + DEBUG_EXTRA("EINPROGRESS, not a real error, assuming non-blocking mode"); errno = EINPROGRESS; err = -1; } @@ -524,6 +531,7 @@ int zts_connect(ZT_CONNECT_SIG) { { if(tap->_Connections[i]->state == PICO_ERR_ECONNRESET) { errno = ECONNRESET; + DEBUG_ERROR("ECONNRESET"); err = -1; } if(tap->_Connections[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) { @@ -666,7 +674,7 @@ Darwin: [ ] [EOPNOTSUPP] The referenced socket is not of type SOCK_STREAM. [ ] [EFAULT] The addr parameter is not in a writable part of the user address space. - [ ] [EWOULDBLOCK] The socket is marked non-blocking and no connections + [--] [EWOULDBLOCK] The socket is marked non-blocking and no connections are present to be accepted. [--] [EMFILE] The per-process descriptor table is full. [ ] [ENFILE] The system file table is full. @@ -697,19 +705,31 @@ int zts_accept(ZT_ACCEPT_SIG) { ZeroTier::Connection *conn = p->first; ZeroTier::SocketTap *tap = p->second; ZeroTier::Connection *accepted_conn; + // BLOCKING: loop and keep checking until we find a newly accepted connection - if(true) { + int f_err, blocking = 1; + if ((f_err = fcntl(fd, F_GETFL, 0)) < 0) { + DEBUG_ERROR("fcntl error, err = %s, errno = %d", f_err, errno); + err = -1; + } + else { + blocking = !(f_err & O_NONBLOCK); + } + if(!err && !blocking) { // non-blocking + DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode"); + errno = EWOULDBLOCK; + err = -1; + accepted_conn = tap->Accept(conn); + } + else if (!err && blocking) { // blocking while(true) { + DEBUG_EXTRA("checking..."); usleep(ZT_ACCEPT_RECHECK_DELAY * 1000); accepted_conn = tap->Accept(conn); if(accepted_conn) break; // accepted fd = err } } - // NON-BLOCKING: only check for a new connection once - else - accepted_conn = tap->Accept(conn); - if(accepted_conn) { ZeroTier::fdmap[accepted_conn->app_fd] = new std::pair(accepted_conn, tap); err = accepted_conn->app_fd; diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp index 4e9a8c2..e3e942c 100644 --- a/src/picoTCP.cpp +++ b/src/picoTCP.cpp @@ -143,7 +143,7 @@ namespace ZeroTier { void picoTCP::pico_cb_tcp_read(ZeroTier::SocketTap *tap, struct pico_socket *s) { - //DEBUG_INFO(); + DEBUG_INFO(); Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; if(conn) { int r; @@ -227,7 +227,7 @@ namespace ZeroTier { void picoTCP::pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s) { - //DEBUG_INFO(); + DEBUG_INFO(); Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; if(!conn) { DEBUG_ERROR("invalid connection"); @@ -259,7 +259,7 @@ namespace ZeroTier { void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s) { - //DEBUG_INFO(); + DEBUG_INFO(); if(!(SocketTap*)((ConnectionPair*)(s->priv))) return; SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap; @@ -312,7 +312,7 @@ namespace ZeroTier { } } if (ev & PICO_SOCK_EV_FIN) { - DEBUG_INFO("PICO_SOCK_EV_FIN (socket closed), picosock=%p, conn=%p", s, conn); + // DEBUG_EXTRA("PICO_SOCK_EV_FIN (socket closed), picosock=%p, conn=%p", s, conn); conn->closure_ts = std::time(nullptr); } if (ev & PICO_SOCK_EV_ERR) { @@ -488,7 +488,7 @@ namespace ZeroTier { inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); // TODO: This isn't proper pico_string_to_ipv6("::", pip6.addr); - DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port)); + DEBUG_INFO("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port)); err = pico_socket_bind(conn->picosock, &pip6, (uint16_t *)&(in6->sin6_port)); } if(err < 0) { @@ -635,6 +635,7 @@ namespace ZeroTier { void picoTCP::pico_Write(Connection *conn, void *data, ssize_t len) { + DEBUG_INFO(); if(conn->picosock->state & PICO_SOCKET_STATE_CLOSED){ DEBUG_ERROR("socket is CLOSED, this write() will fail"); return; @@ -677,7 +678,7 @@ namespace ZeroTier { int picoTCP::pico_Close(Connection *conn) { - //DEBUG_INFO("conn = %p, picosock=%p, fd = %d", conn, conn->picosock, conn->app_fd); + DEBUG_INFO("conn = %p, picosock=%p, fd = %d", conn, conn->picosock, conn->app_fd); if(!conn || !conn->picosock) return ZT_ERR_GENERAL_FAILURE; int err; diff --git a/test/selftest.cpp b/test/selftest.cpp index 0d24895..0e97ea9 100644 --- a/test/selftest.cpp +++ b/test/selftest.cpp @@ -138,6 +138,7 @@ void loadTestConfigFile(std::string filepath) // int ipv4_tcp_client_test(struct sockaddr_in *addr, int port) { + printf("ipv4_tcp_client_test\n"); int r, w, sockfd, err, len = strlen(str); char rbuf[STR_SIZE]; if((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -155,6 +156,7 @@ int ipv4_tcp_client_test(struct sockaddr_in *addr, int port) // int ipv6_tcp_client_test(struct sockaddr_in6 *addr, int port) { + printf("ipv6_tcp_client_test\n"); int r, w, sockfd, err, len = strlen(str); char rbuf[STR_SIZE]; if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) { @@ -205,6 +207,7 @@ int ipv4_tcp_server_test(struct sockaddr_in *addr, int port) // int ipv6_tcp_server_test(struct sockaddr_in6 *addr, int port) { + printf("ipv6_tcp_server_test\n"); int w=0, r=0, sockfd, accfd, err, len = strlen(str); char rbuf[STR_SIZE]; if((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) { @@ -238,6 +241,7 @@ int ipv6_tcp_server_test(struct sockaddr_in6 *addr, int port) // Maintain transfer for n_count OR n_count int ipv4_tcp_client_sustained_test(struct sockaddr_in *addr, int port, int operation, int n_count, int delay) { + printf("ipv4_tcp_client_sustained_test\n"); int w=0, r=0, sockfd, accfd, err, len = strlen(str); int tot, n=0; char rbuf[STR_SIZE]; @@ -260,6 +264,7 @@ int ipv4_tcp_client_sustained_test(struct sockaddr_in *addr, int port, int opera r += n; } err = zts_close(sockfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) && !strcmp(rbuf, str) ? PASSED : FAILED; } if(operation == TEST_OP_N_BYTES) { @@ -276,6 +281,7 @@ int ipv4_tcp_client_sustained_test(struct sockaddr_in *addr, int port, int opera r += n; } err = zts_close(sockfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) ? PASSED : FAILED; } return FAILED; @@ -284,6 +290,7 @@ int ipv4_tcp_client_sustained_test(struct sockaddr_in *addr, int port, int opera // Maintain transfer for n_count OR n_count int ipv6_tcp_client_sustained_test(struct sockaddr_in6 *addr, int port, int operation, int n_count, int delay) { + printf("ipv6_tcp_client_sustained_test\n"); int w=0, r=0, sockfd, accfd, err, len = strlen(str); int tot, n=0; char rbuf[STR_SIZE]; @@ -306,6 +313,7 @@ int ipv6_tcp_client_sustained_test(struct sockaddr_in6 *addr, int port, int oper r += n; } err = zts_close(sockfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) && !strcmp(rbuf, str) ? PASSED : FAILED; } if(operation == TEST_OP_N_BYTES) { @@ -322,6 +330,7 @@ int ipv6_tcp_client_sustained_test(struct sockaddr_in6 *addr, int port, int oper r += n; } err = zts_close(sockfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) ? PASSED : FAILED; } return FAILED; @@ -338,6 +347,7 @@ int ipv6_tcp_client_sustained_test(struct sockaddr_in6 *addr, int port, int oper // Maintain transfer for n_count OR n_count int ipv4_tcp_server_sustained_test(struct sockaddr_in *addr, int port, int operation, int n_count, int delay) { + printf("ipv4_tcp_server_sustained_test\n"); int w=0, r=0, sockfd, accfd, err, len = strlen(str); int tot, n=0; char rbuf[STR_SIZE]; @@ -364,6 +374,7 @@ int ipv4_tcp_server_sustained_test(struct sockaddr_in *addr, int port, int opera } zts_close(sockfd); zts_close(accfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) && !strcmp(rbuf, str) ? PASSED : FAILED; } if(operation == TEST_OP_N_BYTES) { @@ -381,6 +392,7 @@ int ipv4_tcp_server_sustained_test(struct sockaddr_in *addr, int port, int opera } zts_close(sockfd); zts_close(accfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) ? PASSED : FAILED; } return FAILED; @@ -389,6 +401,7 @@ int ipv4_tcp_server_sustained_test(struct sockaddr_in *addr, int port, int opera // Maintain transfer for n_count OR n_count int ipv6_tcp_server_sustained_test(struct sockaddr_in6 *addr, int port, int operation, int n_count, int delay) { + printf("ipv6_tcp_server_sustained_test\n"); int w=0, r=0, sockfd, accfd, err, len = strlen(str); int tot, n=0; char rbuf[STR_SIZE]; @@ -415,6 +428,7 @@ int ipv6_tcp_server_sustained_test(struct sockaddr_in6 *addr, int port, int oper } zts_close(sockfd); zts_close(accfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) && !strcmp(rbuf, str) ? PASSED : FAILED; } if(operation == TEST_OP_N_BYTES) { @@ -432,6 +446,7 @@ int ipv6_tcp_server_sustained_test(struct sockaddr_in6 *addr, int port, int oper } zts_close(sockfd); zts_close(accfd); + printf("n_count = %d", n_count); return (r == tot && w == tot && !err) ? PASSED : FAILED; } return FAILED;} @@ -723,7 +738,8 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc struct sockaddr_in6 addr6; struct sockaddr_in addr; - printf("\n\nNEXT TEST parameters:\n"); + printf("\n\n\n\n\n--------------------------------------------------------------------------------\n"); + printf("TEST parameters:\n"); printf("\tname = %s\n", name); printf("\tpath = %s\n", path.c_str()); printf("\tnwid = %s\n", nwid.c_str()); @@ -734,7 +750,7 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc printf("\tport = %d\n", port); printf("\toperation = %d\n", operation); printf("\tn_count = %d\n", n_count); - printf("\tdelay = %d\n\n", delay); + printf("\tdelay = %d\n", delay); int err = 0; @@ -747,7 +763,6 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc // For instance (ipv4 client, ipv6 server, etc) if(type == TEST_TYPE_SIMPLE) { if(mode == TEST_MODE_CLIENT) { - std::cout << "connecting to " << ipstr << " on port " << port << std::endl; // IPv4 if(protocol == 4) { @@ -771,8 +786,7 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc } if(mode == TEST_MODE_SERVER) { - - //printf("serving on port %s\n", port); + std::cout << "binding on " << ipstr << " : " << port << std::endl; // IPv4 if(protocol == 4) { addr.sin_port = htons(port); @@ -807,8 +821,7 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc // Performs a stress test for benchmarking performance if(type == TEST_TYPE_SUSTAINED) { if(mode == TEST_MODE_CLIENT) { - - //printf("connecting to %s on port %d\n", ipstr, port); + std::cout << "connecting to " << ipstr << " on port " << port << std::endl; // IPv4 if(protocol == 4) { addr.sin_port = htons(port); @@ -831,7 +844,7 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc if(mode == TEST_MODE_SERVER) { - //printf("serving on port %d\n", port); + std::cout << "binding on " << ipstr << " : " << port << std::endl; // IPv4 if(protocol == 4) { addr.sin_port = htons(port); @@ -855,10 +868,12 @@ int do_test(char *name, std::string path, std::string nwid, int type, int protoc } } } + + printf("--------------------------------------------------------------------------------\n"); if(err == PASSED) - printf("PASSED\n"); + printf("Result: PASSED\n"); else - printf("FAILED\n"); + printf("Result: FAILED\n"); return err; } @@ -1028,16 +1043,10 @@ int main(int argc , char *argv[]) if(stype == "comprehensive") { - //printf("performing COMPREHENSIVE ipv4 test\n"); - /* Each host must operate as the counterpart to the other, thus, each mode - * will call the same test helper functions in different orders - * Additionally, the test will use the preset paremeters below for the test: - */ - // Establish initial IPV4 connection between Alice and Bob delay = 0; - n_count = 10; + n_count = 100; operation = TEST_OP_N_TIMES; if(mode == TEST_MODE_SERVER) { @@ -1072,11 +1081,6 @@ int main(int argc , char *argv[]) // IPV6 - /* Each host must operate as the counterpart to the other, thus, each mode - * will call the same test helper functions in different orders - * Additionally, the test will use the preset paremeters below for the test: - */ - if(mode == TEST_MODE_SERVER) { port = local_port6; ipstr6 = local_ipstr6; @@ -1091,7 +1095,7 @@ int main(int argc , char *argv[]) // Perform sustained transfer - err += do_test("ipv6_sustained", path, nwid, TEST_TYPE_SUSTAINED, 6, mode, ipstr, port, operation, n_count, delay); + err += do_test("ipv6_sustained", path, nwid, TEST_TYPE_SUSTAINED, 6, mode, ipstr6, port, operation, n_count, delay); // swtich modes (client/server) if(mode == TEST_MODE_SERVER) {