diff options
| author | Joseph Henry <[email protected]> | 2017-06-16 16:58:30 -0700 |
|---|---|---|
| committer | Joseph Henry <[email protected]> | 2017-06-16 16:58:30 -0700 |
| commit | 195cac6d552d67f59055267adc6d69c3eccfbb19 (patch) | |
| tree | a7e17d1395347ac04a3ad1964bbb34f35c1f2ced /src/picoTCP.cpp | |
| parent | 4403f902a4f6159d41ab5d64583bb4fc054a5880 (diff) | |
significant upgrade to selftest, added echotest, better checks for data in queue before socket closure
Diffstat (limited to 'src/picoTCP.cpp')
| -rw-r--r-- | src/picoTCP.cpp | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp index 248ee90..3fee591 100644 --- a/src/picoTCP.cpp +++ b/src/picoTCP.cpp @@ -175,6 +175,7 @@ namespace ZeroTier { { DEBUG_INFO(); Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; + Mutex::Lock _l(conn->_rx_m); if(conn) { uint16_t port = 0; @@ -229,6 +230,7 @@ namespace ZeroTier { { //DEBUG_INFO(); Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn; + Mutex::Lock _l(conn->_tx_m); if(!conn) { DEBUG_ERROR("invalid connection"); return; @@ -248,18 +250,17 @@ namespace ZeroTier { if(sz) memmove(&conn->txbuf, (conn->txbuf+r), sz); conn->txsz -= r; + //DEBUG_INFO("conn->txsz = %d, r = %d, sz = %d", conn->txsz, r, sz); #if DEBUG_LEVEL >= MSG_TRANSFER int max = conn->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_UDP_TX_BUF_SZ; - DEBUG_TRANS("[ TCP TX -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); + DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r); #endif } } void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s) { - //DEBUG_INFO(); if(!(SocketTap*)((ConnectionPair*)(s->priv))) return; SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap; @@ -268,18 +269,19 @@ namespace ZeroTier { DEBUG_ERROR("invalid tap or conn"); return; } - - int err; - Mutex::Lock _l(tap->_tcpconns_m); + int err = 0; if(!conn) { DEBUG_ERROR("invalid connection"); + return; } - //DEBUG_INFO("conn = %p", conn); - //DEBUG_ERROR(" STATE = %d", conn->picosock->state); - // accept() + // PICO_SOCK_EV_CONN - triggered when connection is established (TCP only). This event is + // received either after a successful call to pico socket connect to indicate that the connection + // has been established, or on a listening socket, indicating that a call to pico socket accept + // may now be issued in order to accept the incoming connection from a remote host. if (ev & PICO_SOCK_EV_CONN) { if(conn->state == ZT_SOCK_STATE_LISTENING) { + Mutex::Lock _l(tap->_tcpconns_m); uint32_t peer; uint16_t port; struct pico_socket *client_psock = pico_socket_accept(s, &peer, &port); @@ -311,33 +313,46 @@ namespace ZeroTier { conn->state = ZT_SOCK_STATE_UNHANDLED_CONNECTED; } } + + // PICO_SOCK_EV_FIN - triggered when the socket is closed. No further communication is + // possible from this point on the socket. if (ev & PICO_SOCK_EV_FIN) { // DEBUG_EXTRA("PICO_SOCK_EV_FIN (socket closed), picosock=%p, conn=%p", s, conn); conn->closure_ts = std::time(nullptr); } + + // PICO_SOCK_EV_ERR - triggered when an error occurs. if (ev & PICO_SOCK_EV_ERR) { if(pico_err == PICO_ERR_ECONNRESET) { DEBUG_ERROR("PICO_ERR_ECONNRESET"); conn->state = PICO_ERR_ECONNRESET; } - //DEBUG_INFO("PICO_SOCK_EV_ERR (socket error received) err=%d, picosock=%p", pico_err, s); + // DEBUG_INFO("PICO_SOCK_EV_ERR (socket error received) err=%d, picosock=%p", pico_err, s); } + // PICO_SOCK_EV_CLOSE - triggered when a FIN segment is received (TCP only). This event + // indicates that the oher endpont has closed the connection, so the local TCP layer is only + // allowed to send new data until a local shutdown or close is initiated. PicoTCP is able to + // keep the connection half-open (only for sending) after the FIN packet has been received, + // allowing new data to be sent in the TCP CLOSE WAIT state. if (ev & PICO_SOCK_EV_CLOSE) { err = pico_socket_close(s); - //DEBUG_INFO("PICO_SOCK_EV_CLOSE (socket closure) err = %d, picosock=%p, conn=%p", err, s, conn); + // DEBUG_INFO("PICO_SOCK_EV_CLOSE (socket closure) err = %d, picosock=%p, conn=%p", err, s, conn); conn->closure_ts = std::time(nullptr); return; } - // Read from picoTCP socket + // PICO_SOCK_EV_RD - triggered when new data arrives on the socket. A new receive action + // can be taken by the socket owner because this event indicates there is new data to receive. if (ev & PICO_SOCK_EV_RD) { if(conn->socket_type==SOCK_STREAM) pico_cb_tcp_read(tap, s); if(conn->socket_type==SOCK_DGRAM) pico_cb_udp_read(tap, s); } - // Write to picoTCP socket - if (ev & PICO_SOCK_EV_WR) + // PICO_SOCK_EV_WR - triggered when ready to write to the socket. Issuing a write/send call + // will now succeed if the buffer has enough space to allocate new outstanding data + if (ev & PICO_SOCK_EV_WR) { pico_cb_tcp_write(tap, s); + } } int pico_eth_send(struct pico_device *dev, void *buf, int len) @@ -362,7 +377,7 @@ namespace ZeroTier { void picoTCP::pico_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType, const void *data,unsigned int len) { - DEBUG_INFO("len = %d", len); + //DEBUG_INFO("len = %d", len); if(!tap) { DEBUG_ERROR("invalid tap"); return; @@ -405,7 +420,7 @@ namespace ZeroTier { Mutex::Lock _l(tap->_pico_frame_rxbuf_m); unsigned char frame[ZT_SDK_MTU]; int len; - int err; + int err = 0; while (tap->pico_frame_rxbuf_tot > 0 && loop_score > 0) { //DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", tap->pico_frame_rxbuf_tot); memset(frame, 0, sizeof(frame)); @@ -435,13 +450,14 @@ namespace ZeroTier { int err = 0; if(conn->socket_family == AF_INET) { struct pico_ip4 zaddr; + memset(&zaddr, 0, sizeof (struct pico_ip4)); struct sockaddr_in *in4 = (struct sockaddr_in*)addr; char ipv4_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN); - pico_string_to_ipv4(ipv4_str, &(zaddr.addr)); - //DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh( in4->sin_port )); + uint32_t ipval = 0; + pico_string_to_ipv4(ipv4_str, &ipval); + zaddr.addr = ipval; err = pico_socket_connect(conn->picosock, &zaddr, in4->sin_port); - //DEBUG_INFO("connect_err = %d", err); } if(conn->socket_family == AF_INET6) { struct pico_ip6 zaddr; @@ -449,10 +465,8 @@ namespace ZeroTier { char ipv6_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); pico_string_to_ipv6(ipv6_str, zaddr.addr); - //DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port)); err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port); } - memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage)); if(err == PICO_ERR_EPROTONOSUPPORT) @@ -474,11 +488,13 @@ namespace ZeroTier { int err = 0; if(conn->socket_family == AF_INET) { struct pico_ip4 zaddr; + memset(&zaddr, 0, sizeof (struct pico_ip4)); struct sockaddr_in *in4 = (struct sockaddr_in*)addr; char ipv4_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&in4->sin_addr.s_addr, ipv4_str, INET_ADDRSTRLEN); + uint32_t ipval = 0; pico_string_to_ipv4(ipv4_str, &(zaddr.addr)); - // DEBUG_ATTN("addr=%s: %d ntoh()=%d", ipv4_str, in4->sin_port, Utils::ntoh(in4->sin_port)); + DEBUG_EXTRA("addr=%s:%d", ipv4_str, Utils::ntoh(in4->sin_port)); err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)&(in4->sin_port)); } if(conn->socket_family == AF_INET6) { @@ -488,7 +504,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_INFO("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port)); + DEBUG_EXTRA("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) { @@ -521,7 +537,7 @@ namespace ZeroTier { DEBUG_ERROR("invalid conn or conn->picosock"); return ZT_ERR_GENERAL_FAILURE; } - int err; + int err = 0; if((err = pico_socket_listen(conn->picosock, backlog)) < 0) { if(err == PICO_ERR_EINVAL) { @@ -611,8 +627,7 @@ namespace ZeroTier { if(conn->socket_type==SOCK_STREAM) { #if DEBUG_LEVEL >= MSG_TRANSFER float max = conn->socket_type == SOCK_STREAM ? (float)ZT_TCP_RX_BUF_SZ : (float)ZT_UDP_RX_BUF_SZ; - DEBUG_TRANS("[ TCP RX <- STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n); + DEBUG_TRANS("[ TCP RX <- STACK] :: conn = %p, len = %d", conn, n); #endif } if(conn->rxsz == 0) { @@ -635,7 +650,11 @@ namespace ZeroTier { void picoTCP::pico_Write(Connection *conn, void *data, ssize_t len) { - //DEBUG_INFO(); + Mutex::Lock _l(conn->_tx_m); + if(len <= 0) { + DEBUG_ERROR("invalid write length"); + return; + } if(conn->picosock->state & PICO_SOCKET_STATE_CLOSED){ DEBUG_ERROR("socket is CLOSED, this write() will fail"); return; @@ -644,6 +663,12 @@ namespace ZeroTier { DEBUG_ERROR("invalid connection"); return; } + if(conn->txsz + len >= ZT_TCP_TX_BUF_SZ) { + DEBUG_ERROR("TX buffer is too small, try increasing ZT_TCP_TX_BUF_SZ in libzt.h"); + return; + } + + // DEBUG_INFO("conn->txsz = %d, len = %d", conn->txsz, len); unsigned char *buf = (unsigned char*)data; memcpy(conn->txbuf + conn->txsz, buf, len); conn->txsz += len; @@ -661,18 +686,18 @@ namespace ZeroTier { // adjust buffer int sz = (conn->txsz)-r; if(sz) + { memmove(&conn->txbuf, (conn->txbuf+r), sz); + } conn->txsz -= r; if(conn->socket_type == SOCK_STREAM) { max = ZT_TCP_TX_BUF_SZ; - DEBUG_TRANS("[ TCP TX -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); + DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r); } if(conn->socket_type == SOCK_DGRAM) { max = ZT_UDP_TX_BUF_SZ; - DEBUG_TRANS("[ UDP TX -> STACK] :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); + DEBUG_TRANS("[ UDP TX -> STACK] :: conn = %p, len = %d", conn, r); } } @@ -681,12 +706,11 @@ namespace ZeroTier { 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; + int err = 0; Mutex::Lock _l(conn->tap->_tcpconns_m); if(conn->closure_ts != -1) // it was closed at some point in the past, it'll work itself out return ZT_ERR_OK; if((err = pico_socket_close(conn->picosock)) < 0) { - DEBUG_ERROR("closing pico_socket..."); errno = pico_err; DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock)); } |
