significant upgrade to selftest, added echotest, better checks for data in queue before socket closure

This commit is contained in:
Joseph Henry
2017-06-16 16:58:30 -07:00
parent 4403f902a4
commit 195cac6d55
17 changed files with 1038 additions and 658 deletions

View File

@@ -39,7 +39,6 @@
// SDK
#include "libzt.h"
#include "SocketTap.hpp"
//#include "RingBuffer.hpp"
namespace ZeroTier {
@@ -48,8 +47,7 @@ namespace ZeroTier {
*/
struct Connection
{
//circular_buffer<char> crbuf = circular_buffer<char>(ZT_TCP_RX_BUF_SZ);
//circular_buffer<char> ctbuf = circular_buffer<char>(ZT_TCP_TX_BUF_SZ);
Mutex _tx_m, _rx_m;
int pid;
PhySocket *sock;
@@ -57,7 +55,7 @@ namespace ZeroTier {
// TODO: For getsockname, etc
struct sockaddr_storage *local_addr; // Address we've bound to locally
struct sockaddr_storage *peer_addr; // Address of connection call to remote host
struct sockaddr_storage *peer_addr; // Address of connection call to remote host
// RX/TX buffers
int txsz = 0, rxsz = 0;
@@ -72,14 +70,13 @@ namespace ZeroTier {
std::queue<Connection*> _AcceptedConnections;
SocketTap *tap; // Reference to SocketTap
int state; // See libzt.h for (ZT_SOCK_STATE_*)
int state; // See libzt.h for (ZT_SOCK_STATE_*)
// timestamp for closure event
std::time_t closure_ts;
Connection() {
closure_ts = -1;
// DEBUG_INFO("Connection() this = %p", this);
ZT_PHY_SOCKFD_TYPE fdpair[2];
if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fdpair) < 0) {
if(errno < 0) {

View File

@@ -27,13 +27,10 @@
// picoTCP
#include <algorithm>
#include <utility>
#include <dlfcn.h>
#include <sys/poll.h>
#include <stdint.h>
#include <utility>
#include <string>
#include <sys/resource.h>
#include <sys/syscall.h>
// SDK
#include "SocketTap.hpp"

View File

@@ -24,8 +24,14 @@
* of your own application.
*/
#include <dlfcn.h>
/* This file implements the libzt library API, it talks to the network
stack driver and core ZeroTier service to create a socket-like interface
for applications to use. See also: include/libzt.h */
#include <sys/socket.h>
//#include <sys/ioctl.h>
//#include <stropts.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -165,8 +171,8 @@ void zts_core_version(char *ver) {
sprintf(ver, "%d.%d.%d", major, minor, revision);
}
void zts_sdk_version(char *ver) {
sprintf(ver, "%d.%d.%d", ZT_SDK_VERSION_MAJOR, ZT_SDK_VERSION_MINOR, ZT_SDK_VERSION_REVISION);
void zts_lib_version(char *ver) {
sprintf(ver, "%d.%d.%d", ZT_LIB_VERSION_MAJOR, ZT_LIB_VERSION_MINOR, ZT_LIB_VERSION_REVISION);
}
int zts_get_device_id(char *devID) {
@@ -314,11 +320,11 @@ void zts_disable_http_control_plane()
/*
socket fd = 0 (nwid=X)---\ /--- SocketTap=A // e.x. 172.27.0.0/?
socket fd = 0 (nwid=X)---\ /--- SocketTap=A // e.x. 172.27.0.0 / 16
\ /
socket fd = 1 (nwid=Y)--------Multiplexed z* calls-------- SocketTap=B // e.x. 192.168.0.1/16
socket fd = 1 (nwid=Y)--------Multiplexed z* calls-------- SocketTap=B // e.x. 192.168.0.1 / 16
/ \
socket fd = 2 (nwid=Z)---/ \--- SocketTap=C // e.x. 10.9.9.0/24
socket fd = 2 (nwid=Z)---/ \--- SocketTap=C // e.x. 10.9.9.0 / 24
*/
@@ -332,72 +338,65 @@ Darwin:
[NA] [ENFILE] The system file table is full.
[ ] [ENOBUFS] Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed.
[ ] [ENOMEM] Insufficient memory was available to fulfill the request.
[ ] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain.
[--] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain.
[ ] [EPROTOTYPE] The socket type is not supported by the protocol.
*/
// int socket_family, int socket_type, int protocol
int zts_socket(ZT_SOCKET_SIG) {
DEBUG_INFO();
int err = 0;
if(!zt1Service) {
DEBUG_ERROR("cannot create socket, no service running. call zts_start() first.");
errno = EMFILE; // could also be ENFILE
return -1;
}
if(socket_type == SOCK_SEQPACKET) {
DEBUG_ERROR("SOCK_SEQPACKET not yet supported.");
errno = EPROTONOSUPPORT; // seemingly closest match
return -1;
}
ZeroTier::_multiplexer_lock.lock();
if(pico_ntimers() >= PICO_MAX_TIMERS) {
DEBUG_ERROR("cannot provision additional socket due to limitation of PICO_MAX_TIMERS. current = %d", pico_ntimers());
errno = EMFILE;
err = -1;
}
else {
ZeroTier::_multiplexer_lock.lock();
//DEBUG_INFO("unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
//DEBUG_INFO("timers = %d, max = %d", pico_ntimers(), PICO_MAX_TIMERS);
if(pico_ntimers() >= PICO_MAX_TIMERS) {
DEBUG_ERROR("cannot provision additional socket due to limitation of PICO_MAX_TIMERS. current = %d", pico_ntimers());
errno = EMFILE;
else
{
ZeroTier::Connection *conn = new ZeroTier::Connection();
int protocol_version = 0;
struct pico_socket *psock;
if(socket_family == AF_INET)
protocol_version = PICO_PROTO_IPV4;
if(socket_family == AF_INET6)
protocol_version = PICO_PROTO_IPV6;
if(socket_type == SOCK_DGRAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
if(socket_type == SOCK_STREAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
// set up Unix Domain socketpair (used for data later on)
if(psock) {
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->picosock = psock;
memset(conn->rxbuf, 0, ZT_UDP_RX_BUF_SZ);
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create pico_socket");
err = -1;
}
else
{
ZeroTier::Connection *conn = new ZeroTier::Connection();
int protocol_version = 0;
struct pico_socket *psock;
// TODO: check ifdef logic here
//#if defined(SDK_IPV4)
if(socket_family == AF_INET){
// DEBUG_ERROR("AF_INET");
protocol_version = PICO_PROTO_IPV4;
}
//#endif
//#if defined(SDK_IPV6)
if(socket_family == AF_INET6) {
// DEBUG_ERROR("AF_INET6");
protocol_version = PICO_PROTO_IPV6;
}
//#endif
if(socket_type == SOCK_DGRAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
if(socket_type == SOCK_STREAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_activity);
}
// set up Unix Domain socketpair (used for data later on)
if(psock) {
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->picosock = psock;
memset(conn->rxbuf, 0, ZT_UDP_RX_BUF_SZ);
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create pico_socket");
err = -1;
}
}
//DEBUG_INFO(" unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
ZeroTier::_multiplexer_lock.unlock();
}
ZeroTier::_multiplexer_lock.unlock();
return err;
}
@@ -415,7 +414,8 @@ Darwin:
[ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for connections) or explicitly rejected.
[ ] [EFAULT] The address parameter specifies an area outside the process address space.
[ ] [EHOSTUNREACH] The target host cannot be reached (e.g., down, disconnected).
[--] [EINPROGRESS] The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) for completion by selecting the socket for writing.
[--] [EINPROGRESS] The socket is non-blocking and the connection cannot be completed immediately.
It is possible to select(2) for completion by selecting the socket for writing.
[NA] [EINTR] Its execution was interrupted by a signal.
[ ] [EINVAL] An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
[ ] [EISCONN] The socket is already connected.
@@ -427,9 +427,35 @@ Darwin:
[ ] [EPROTOTYPE] address has a different type than the socket that is bound to the specified peer address.
[ ] [ETIMEDOUT] Connection establishment timed out without establishing a connection.
[ ] [ECONNRESET] Remote host reset the connection request.
Linux:
[ ] [EACCES] For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket file,
or search permission is denied for one of the directories in the path prefix. (See also path_resolution(7).)
[ ] [EACCES, EPERM] The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the
connection request failed because of a local firewall rule.
[ ] [EADDRINUSE] Local address is already in use.
[ ] [EAFNOSUPPORT] The passed address didn't have the correct address family in its sa_family field.
[ ] [EAGAIN] No more free local ports or insufficient entries in the routing cache. For AF_INET see the description
of /proc/sys/net/ipv4/ip_local_port_range ip(7) for information on how to increase the number of local ports.
[ ] [EALREADY] The socket is nonblocking and a previous connection attempt has not yet been completed.
[ ] [EBADF] The file descriptor is not a valid index in the descriptor table.
[ ] [ECONNREFUSED] No-one listening on the remote address.
[ ] [EFAULT] The socket structure address is outside the user's address space.
[ ] [EINPROGRESS] The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or
poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2)
to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero)
or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
[ ] [EINTR] The system call was interrupted by a signal that was caught; see signal(7).
[ ] [EISCONN] The socket is already connected.
[ ] [ENETUNREACH] Network is unreachable.
[ ] [ENOTSOCK] The file descriptor is not associated with a socket.
[ ] [ETIMEDOUT] Timeout while attempting connection. The server may be too busy to accept new connections. Note that for
IP sockets the timeout may be very long when syncookies are enabled on the server.
*/
int zts_connect(ZT_CONNECT_SIG) {
// DEBUG_INFO("fd = %d", fd);
DEBUG_INFO("fd = %d", fd);
int err = 0;
if(fd < 0) {
errno = EBADF;
@@ -566,16 +592,16 @@ Darwin:
address space.
*/
int zts_bind(ZT_BIND_SIG) {
//DEBUG_EXTRA("fd = %d", fd);
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
return -1;
}
if(!zt1Service) {
DEBUG_ERROR("Service not started. Call zts_start(path) first");
errno = EBADF;
err = -1;
return -1;
}
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
@@ -618,7 +644,6 @@ int zts_bind(ZT_BIND_SIG) {
errno = EBADF;
err = -1;
}
ZeroTier::_multiplexer_lock.unlock();
return err;
}
@@ -629,17 +654,24 @@ Darwin:
[--] [EACCES] The current process has insufficient privileges.
[--] [EBADF] The argument socket is not a valid file descriptor.
[ ] [EDESTADDRREQ] The socket is not bound to a local address and the protocol does not support listening on an unbound socket.
[--] [EDESTADDRREQ] The socket is not bound to a local address and the protocol does not support listening on an unbound socket.
[ ] [EINVAL] socket is already connected.
[ ] [ENOTSOCK] The argument socket does not reference a socket.
[ ] [EOPNOTSUPP] The socket is not of a type that supports the operation listen().
Linux:
[ ] [EADDRINUSE] Another socket is already listening on the same port.
[--] [EBADF] The argument sockfd is not a valid descriptor.
[ ] [ENOTSOCK] The argument sockfd is not a socket.
[ ] [EOPNOTSUPP] The socket is not of a type that supports the listen() operation.
*/
int zts_listen(ZT_LISTEN_SIG) {
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
return -1;
}
if(!zt1Service) {
DEBUG_ERROR("service not started. call zts_start(path) first");
@@ -650,18 +682,21 @@ int zts_listen(ZT_LISTEN_SIG) {
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
if(!p) {
DEBUG_ERROR("unable to locate connection pair. did you bind?");
errno = EDESTADDRREQ;
return -1;
}
ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second;
if(!tap || !conn) {
DEBUG_ERROR("unable to locate tap interface for file descriptor");
errno = EBADF;
return -1;
}
err = tap->Listen(conn, fd, backlog);
//DEBUG_INFO("put conn=%p into LISTENING state (err=%d)", conn, err);
ZeroTier::_multiplexer_lock.unlock();
if(!err) {
backlog = backlog > 128 ? 128 : backlog; // See: /proc/sys/net/core/somaxconn
err = tap->Listen(conn, fd, backlog);
ZeroTier::_multiplexer_lock.unlock();
}
return err;
}
@@ -684,7 +719,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
return -1;
}
else
{
@@ -704,7 +739,6 @@ int zts_accept(ZT_ACCEPT_SIG) {
else {
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
int f_err, blocking = 1;
@@ -715,24 +749,26 @@ int zts_accept(ZT_ACCEPT_SIG) {
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);
if(!err) {
ZeroTier::Connection *accepted_conn;
if(!blocking) { // non-blocking
DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode");
errno = EWOULDBLOCK;
err = -1;
accepted_conn = tap->Accept(conn);
if(accepted_conn)
break; // accepted fd = err
}
}
if(accepted_conn) {
ZeroTier::fdmap[accepted_conn->app_fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(accepted_conn, tap);
err = accepted_conn->app_fd;
else { // blocking
while(true) {
usleep(ZT_ACCEPT_RECHECK_DELAY * 1000);
accepted_conn = tap->Accept(conn);
if(accepted_conn)
break; // accepted fd = err
}
}
if(accepted_conn) {
ZeroTier::fdmap[accepted_conn->app_fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(accepted_conn, tap);
err = accepted_conn->app_fd;
}
}
}
ZeroTier::_multiplexer_lock.unlock();
@@ -745,19 +781,19 @@ int zts_accept(ZT_ACCEPT_SIG) {
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.
Errors
[ ] EAGAIN or EWOULDBLOCK The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
[--] EBADF The descriptor is invalid.
[ ] ECONNABORTED A connection has been aborted.
[ ] EFAULT The addr argument is not in a writable part of the user address space.
[NA] EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).
[ ] EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
[ ] EINVAL (accept4()) invalid value in flags.
[ ] EMFILE The per-process limit of open file descriptors has been reached.
[ ] ENFILE The system limit on the total number of open files has been reached.
[ ] ENOBUFS, ENOMEM Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory.
[ ] ENOTSOCK The descriptor references a file, not a socket.
[ ] EOPNOTSUPP The referenced socket is not of type SOCK_STREAM.
[ ] EPROTO Protocol error.
[ ] [EAGAIN or EWOULDBLOCK] The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
[--] [EBADF] The descriptor is invalid.
[ ] [ECONNABORTED] A connection has been aborted.
[ ] [EFAULT] The addr argument is not in a writable part of the user address space.
[NA] [EINTR] The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).
[ ] [EINVAL] Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
[ ] [EINVAL] (accept4()) invalid value in flags.
[ ] [EMFILE] The per-process limit of open file descriptors has been reached.
[ ] [ENFILE] The system limit on the total number of open files has been reached.
[ ] [ENOBUFS, ENOMEM] Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory.
[ ] [ENOTSOCK] The descriptor references a file, not a socket.
[ ] [EOPNOTSUPP] The referenced socket is not of type SOCK_STREAM.
[ ] [EPROTO] Protocol error.
In addition, Linux accept() may fail if:
@@ -870,7 +906,7 @@ Linux:
See: http://yarchive.net/comp/linux/close_return_value.html
Darwin:
Linux / Darwin:
[--] [EBADF] fildes is not a valid, active file descriptor.
[NA] [EINTR] Its execution was interrupted by a signal.
@@ -881,7 +917,7 @@ Darwin:
int zts_close(ZT_CLOSE_SIG)
{
//DEBUG_EXTRA("fd = %d", fd);
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
errno = EBADF;
@@ -898,7 +934,6 @@ int zts_close(ZT_CLOSE_SIG)
{
ZeroTier::_multiplexer_lock.lock();
//DEBUG_INFO("unmap=%d, fdmap=%d", ZeroTier::unmap.size(), ZeroTier::fdmap.size());
// First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
@@ -925,31 +960,44 @@ int zts_close(ZT_CLOSE_SIG)
errno = EBADF;
err = -1;
}
else
else // found everything, begin closure
{
conn = p->first;
ZeroTier::SocketTap *tap = p->second;
//DEBUG_ERROR("close...., conn = %p, fd = %d", conn, fd);
// check if socket is blocking
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(blocking) {
DEBUG_INFO("socket is blocking, waiting for write operations before closure");
for(int i=0; i<ZT_SDK_CLTIME; i++) {
if(conn->txsz == 0)
break;
sleep(1);
}
}
// For cases where data might still need to pass through the library
// before socket closure
if(ZT_SOCK_BEHAVIOR_LINGER) {
socklen_t optlen;
struct linger so_linger;
so_linger.l_linger = 0;
zts_getsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, &optlen);
if (so_linger.l_linger != 0) {
DEBUG_EXTRA("lingering before closure for (%d) seconds...", so_linger.l_linger);
sleep(so_linger.l_linger); // do the linger!
}
}
// Tell the tap to stop monitoring this PhySocket
//if((err = pico_socket_close(conn->picosock)) < 0)
// DEBUG_ERROR("error calling pico_socket_close()");
tap->Close(conn);
// delete objects
// FIXME: double check this
//delete p;
ZeroTier::fdmap.erase(fd);
err = 0;
}
@@ -964,7 +1012,7 @@ int zts_close(ZT_CLOSE_SIG)
int zts_fcntl(ZT_FCNTL_SIG)
{
//DEBUG_INFO("fd = %d", fd);
int err;
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
@@ -979,7 +1027,7 @@ int zts_fcntl(ZT_FCNTL_SIG)
ssize_t zts_sendto(ZT_SENDTO_SIG)
{
DEBUG_INFO("fd = %d", fd);
int err;
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
@@ -994,7 +1042,7 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
{
DEBUG_INFO("fd = %d", fd);
int err;
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
@@ -1009,7 +1057,7 @@ ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
{
DEBUG_INFO("fd = %d", fd);
int err;
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
@@ -1024,7 +1072,7 @@ ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
ssize_t zts_recvmsg(ZT_RECVMSG_SIG)
{
DEBUG_INFO("fd = %d", fd);
int err;
int err = 0;
if(fd < 0) {
errno = EBADF;
err = -1;
@@ -1353,10 +1401,10 @@ void *zts_start_service(void *thread_id) {
return NULL;
}
// rpc dir
if(!ZeroTier::OSUtils::mkdir(ZeroTier::homeDir + "/" + ZT_SDK_RPC_DIR_PREFIX)) {
DEBUG_ERROR("unable to create dir: " ZT_SDK_RPC_DIR_PREFIX);
return NULL;
}
// if(!ZeroTier::OSUtils::mkdir(ZeroTier::homeDir + "/" + ZT_SDK_RPC_DIR_PREFIX)) {
// DEBUG_ERROR("unable to create dir: " ZT_SDK_RPC_DIR_PREFIX);
// return NULL;
//}
// Generate random port for new service instance
unsigned int randp = 0;

View File

@@ -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));
}