From 3793b23229a9212173e440802a75fcadbb6c520a Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Sun, 11 Jun 2017 20:24:11 -0700 Subject: [PATCH] fixed connect/accept behaviour, added to selftest, renamed BSD makefile --- Makefile | 4 +-- TESTING.md | 4 +-- artwork/ztapp.png | Bin 0 -> 27433 bytes make-freebsd.mk => make-bsd.mk | 0 make-mac.mk | 2 +- src/Connection.hpp | 3 +- src/SocketTap.cpp | 2 +- src/ZeroTierSDK.cpp | 46 +++++++++++++++++++++--------- src/picoTCP.cpp | 13 +++++---- test/selftest.cpp | 50 ++++++++++++++++++--------------- 10 files changed, 75 insertions(+), 49 deletions(-) create mode 100644 artwork/ztapp.png rename make-freebsd.mk => make-bsd.mk (100%) 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 0000000000000000000000000000000000000000..972ea959dfc09f29536a3e4c8df6c4c2fb12d7b6 GIT binary patch literal 27433 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 F{{#C@|8W2S literal 0 HcmV?d00001 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) {