Renamed SocketTap to VirtualTap and Connection to VirtualSocket to prevent confusion

This commit is contained in:
Joseph Henry
2017-08-15 18:15:06 -07:00
parent cb93c752f0
commit 7d551d6198
15 changed files with 671 additions and 672 deletions

View File

@@ -90,7 +90,7 @@ struct zts_ifreq {
#define LWIP_APPLICATION_POLL_FREQ 2
#define LWIP_TCP_TIMER_INTERVAL 50
#define LWIP_STATUS_TMR_INTERVAL 500 // How often we check connection statuses (in ms)
#define LWIP_STATUS_TMR_INTERVAL 500 // How often we check VirtualSocket statuses (in ms)
/****************************************************************************/
/* Defines */
@@ -155,11 +155,11 @@ struct zts_ifreq {
#define ZT_SDK_CLTIME 60
// After closing a pico_socket, other threads might still try to use the
// Connection object for remaining data I/O, as a safety measure we will wait to
// delete this Connection object until the socket has been closed for some arbitrary
// VirtualSocket object for remaining data I/O, as a safety measure we will wait to
// delete this VirtualSocket object until the socket has been closed for some arbitrary
// amount of time and it is safe to assume any clients interacting with this
// socket have read some sort of error code from the API.
#define ZT_CONNECTION_DELETE_WAIT_TIME 30 // s
#define ZT_VirtualSocket_DELETE_WAIT_TIME 30 // s
// Interval for performing cleanup tasks on Tap/Stack objects
#define ZT_HOUSEKEEPING_INTERVAL 10 // s
@@ -351,30 +351,30 @@ int zts_connect(ZT_CONNECT_SIG);
/**
* Binds a socket to a specific address
* - To accept connections on a specific ZeroTier network you must
* - To accept VirtualSockets on a specific ZeroTier network you must
* use this bind call with an address which is associated with that network
*
* For instance, given the following networks:
* - nwid = 97afaf1963cc6a90 (10.9.0.0/24)
* - nwid = 23bfae5663c8b188 (192.168.0.0/24)
*
* In order to accept a connection on 97afaf1963cc6a90, you
* In order to accept a VirtualSocket on 97afaf1963cc6a90, you
* should bind to 10.9.0.0
*/
int zts_bind(ZT_BIND_SIG);
/**
* Listen for incoming connections
* Listen for incoming VirtualSockets
*/
int zts_listen(ZT_LISTEN_SIG);
/**
* Accept a connection
* Accept a VirtualSocket
*/
int zts_accept(ZT_ACCEPT_SIG);
/**
* Accept a connection
* Accept a VirtualSocket
*/
#if defined(__linux__)
int zts_accept4(ZT_ACCEPT4_SIG);
@@ -485,7 +485,7 @@ namespace ZeroTier
class lwIP;
extern ZeroTier::lwIP *lwipstack;
class SocketTap;
class VirtualTap;
struct InetAddress;
}
@@ -521,10 +521,10 @@ int pico_ntimers();
/* ZeroTier Core helper functions for libzt - DON'T CALL THESE DIRECTLY */
/****************************************************************************/
ZeroTier::SocketTap *getTapByNWID(uint64_t nwid);
ZeroTier::SocketTap *getTapByAddr(ZeroTier::InetAddress &addr);
ZeroTier::SocketTap *getTapByName(char *ifname);
ZeroTier::SocketTap *getTapByIndex(int index);
ZeroTier::VirtualTap *getTapByNWID(uint64_t nwid);
ZeroTier::VirtualTap *getTapByAddr(ZeroTier::InetAddress &addr);
ZeroTier::VirtualTap *getTapByName(char *ifname);
ZeroTier::VirtualTap *getTapByIndex(int index);
/*
* Destroys all virtual tap devices

View File

@@ -136,11 +136,11 @@ CXXFLAGS+=-DSDK_IPV6
##############################################################################
STACK_DRIVER_FILES:=src/picoTCP.cpp
TAP_FILES:=src/SocketTap.cpp \
TAP_FILES:=src/VirtualTap.cpp \
src/libzt.cpp \
src/Utilities.cpp
SDK_OBJS+= SocketTap.o \
SDK_OBJS+= VirtualTap.o \
picoTCP.o \
libzt.o \
Utilities.o

View File

@@ -150,7 +150,7 @@ STACK_FLAGS+=LIBZT_IPV4=1
endif
endif
LIBZT_FILES:=src/SocketTap.cpp src/libzt.cpp src/Utilities.cpp
LIBZT_FILES:=src/VirtualTap.cpp src/libzt.cpp src/Utilities.cpp
ifeq ($(STACK_PICO),1)
CXXFLAGS+=-DSTACK_PICO

View File

@@ -149,7 +149,7 @@ STACK_FLAGS+=LIBZT_IPV4=1
endif
endif
LIBZT_FILES:=src/SocketTap.cpp src/libzt.cpp src/Utilities.cpp
LIBZT_FILES:=src/VirtualTap.cpp src/libzt.cpp src/Utilities.cpp
ifeq ($(STACK_PICO),1)
CXXFLAGS+=-DSTACK_PICO

View File

@@ -24,7 +24,7 @@
* of your own application.
*/
// General connection object used by SocketTap and network stack drivers
// General connection object used by VirtualTap and network stack drivers
#ifndef ZT_CONNECTION_HPP
#define ZT_CONNECTION_HPP
@@ -39,19 +39,24 @@
#include "Phy.hpp"
#include "libzt.h"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
#include "RingBuffer.hpp"
namespace ZeroTier {
class SocketTap;
class VirtualTap;
struct Connection
/*
* Something analogous to a socket. This is a common object used by the
* libzt API, VirtualTap, and the userspace network stack driver implementations.
* In some situations the word 'Connection' would capture the meaning and
* function of this object, however I'd like to discourage this since this
* object also handles non-connection-based traffic as well.
*/
struct VirtualSocket
{
int tot = 0;
RingBuffer<unsigned char> *TXbuf;
RingBuffer<unsigned char> *RXbuf;
Mutex _tx_m, _rx_m;
PhySocket *sock;
@@ -62,6 +67,7 @@ namespace ZeroTier {
#if defined(STACK_LWIP)
void *pcb;
#endif
// 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
@@ -71,14 +77,14 @@ namespace ZeroTier {
int app_fd; // used by app for I/O
int sdk_fd; // used by lib for I/O
std::queue<Connection*> _AcceptedConnections;
SocketTap *tap;
std::queue<VirtualSocket*> _AcceptedConnections;
VirtualTap *tap;
int state; // See libzt.h for (ZT_SOCK_STATE_*)
// timestamp for closure event
std::time_t closure_ts;
Connection() {
VirtualSocket() {
TXbuf = new RingBuffer<unsigned char>(ZT_TCP_TX_BUF_SZ);
RXbuf = new RingBuffer<unsigned char>(ZT_TCP_RX_BUF_SZ);
@@ -93,17 +99,17 @@ namespace ZeroTier {
sdk_fd = fdpair[0];
app_fd = fdpair[1];
}
~Connection() { }
~VirtualSocket() { }
};
/*
* A helper object for passing SocketTap(s) and Connection(s) through the stack
* A helper object for passing VirtualTap(s) and VirtualSocket(s) through the stack
*/
struct ConnectionPair
struct VirtualBindingPair
{
SocketTap *tap;
Connection *conn;
ConnectionPair(SocketTap *_tap, Connection *conn) : tap(_tap), conn(conn) {}
VirtualTap *tap;
VirtualSocket *vs;
VirtualBindingPair(VirtualTap *_tap, VirtualSocket *_vs) : tap(_tap), vs(_vs) {}
};
}
#endif

View File

@@ -35,7 +35,7 @@
#include <utility>
#include <string>
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
#include "libzt.h"
#if defined(STACK_PICO)
@@ -58,23 +58,21 @@
#include "Constants.hpp"
#include "Phy.hpp"
class SocketTap;
class VirtualTap;
extern std::vector<void*> vtaps;
//extern ZeroTier::OneService *zt1Service;
namespace ZeroTier {
int SocketTap::devno = 0;
int VirtualTap::devno = 0;
/****************************************************************************/
/* SocketTap Service */
/* - For each joined network a SocketTap will be created to administer I/O */
/* VirtualTap Service */
/* - For each joined network a VirtualTap will be created to administer I/O */
/* calls to the stack and the ZT virtual wire */
/****************************************************************************/
SocketTap::SocketTap(
VirtualTap::VirtualTap(
const char *homePath,
const MAC &mac,
unsigned int mtu,
@@ -107,26 +105,26 @@ namespace ZeroTier {
_thread = Thread::start(this);
}
SocketTap::~SocketTap()
VirtualTap::~VirtualTap()
{
_run = false;
_phy.whack();
Thread::join(_thread);
_phy.close(_unixListenSocket,false);
for(int i=0; i<_Connections.size(); i++) delete _Connections[i];
for(int i=0; i<_VirtualSockets.size(); i++) delete _VirtualSockets[i];
}
void SocketTap::setEnabled(bool en)
void VirtualTap::setEnabled(bool en)
{
_enabled = en;
}
bool SocketTap::enabled() const
bool VirtualTap::enabled() const
{
return _enabled;
}
bool SocketTap::registerIpWithStack(const InetAddress &ip)
bool VirtualTap::registerIpWithStack(const InetAddress &ip)
{
#if defined(STACK_PICO)
if(picostack){
@@ -143,7 +141,7 @@ namespace ZeroTier {
return false;
}
bool SocketTap::addIp(const InetAddress &ip)
bool VirtualTap::addIp(const InetAddress &ip)
{
#if defined(NO_STACK)
char ipbuf[64];
@@ -163,7 +161,7 @@ namespace ZeroTier {
return false;
}
bool SocketTap::removeIp(const InetAddress &ip)
bool VirtualTap::removeIp(const InetAddress &ip)
{
Mutex::Lock _l(_ips_m);
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
@@ -179,13 +177,13 @@ namespace ZeroTier {
return true;
}
std::vector<InetAddress> SocketTap::ips() const
std::vector<InetAddress> VirtualTap::ips() const
{
Mutex::Lock _l(_ips_m);
return _ips;
}
void SocketTap::put(const MAC &from,const MAC &to,unsigned int etherType,
void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
#if defined(STACK_PICO)
@@ -198,18 +196,18 @@ namespace ZeroTier {
#endif
}
std::string SocketTap::deviceName() const
std::string VirtualTap::deviceName() const
{
return _dev;
}
void SocketTap::setFriendlyName(const char *friendlyName)
void VirtualTap::setFriendlyName(const char *friendlyName)
{
DEBUG_INFO("%s", friendlyName);
// Someday
}
void SocketTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
void VirtualTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
std::vector<MulticastGroup> &removed)
{
std::vector<MulticastGroup> newGroups;
@@ -233,14 +231,14 @@ namespace ZeroTier {
_multicastGroups.swap(newGroups);
}
void SocketTap::setMtu(unsigned int mtu)
void VirtualTap::setMtu(unsigned int mtu)
{
if (_mtu != mtu) {
_mtu = mtu;
}
}
void SocketTap::threadMain()
void VirtualTap::threadMain()
throw()
{
#if defined(STACK_PICO)
@@ -253,35 +251,35 @@ namespace ZeroTier {
#endif
}
void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr)
void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr)
{
if(sock) {
Connection *conn = (Connection*)uptr;
if(conn)
Close(conn);
VirtualSocket *vs = (VirtualSocket*)uptr;
if(vs)
Close(vs);
}
}
void SocketTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
void VirtualTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
{
DEBUG_ATTN("sock->fd=%d", _phy.getDescriptor(sock));
Connection *conn = (Connection*)*uptr;
if(!conn)
VirtualSocket *vs = (VirtualSocket*)*uptr;
if(!vs)
return;
if(len){
Write(conn, data, len);
Write(vs, data, len);
}
return;
}
void SocketTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked)
void VirtualTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked)
{
if(sock)
Read(sock,uptr,stack_invoked);
}
// Adds a route to the virtual tap
bool SocketTap::routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw)
bool VirtualTap::routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw)
{
#if defined(STACK_PICO)
if(picostack)
@@ -294,7 +292,7 @@ namespace ZeroTier {
}
// Deletes a route from the virtual tap
bool SocketTap::routeDelete(const InetAddress &addr, const InetAddress &nm)
bool VirtualTap::routeDelete(const InetAddress &addr, const InetAddress &nm)
{
#if defined(STACK_PICO)
if(picostack)
@@ -311,94 +309,94 @@ namespace ZeroTier {
/****************************************************************************/
// Connect
int SocketTap::Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) {
int VirtualTap::Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen) {
#if defined(NO_STACK)
return -1;
#endif
#if defined(STACK_PICO)
if(picostack)
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Connect(conn, addr, addrlen);
return picostack->pico_Connect(vs, addr, addrlen);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Connect(conn, addr, addrlen);
return lwipstack->lwip_Connect(vs, addr, addrlen);
#endif
return ZT_ERR_GENERAL_FAILURE;
}
// Bind VirtualSocket to a network stack's interface
int SocketTap::Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) {
int VirtualTap::Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen) {
#if defined(NO_STACK)
return -1;
#endif
Mutex::Lock _l(_tcpconns_m);
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Bind(conn, addr, addrlen);
return picostack->pico_Bind(vs, addr, addrlen);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Bind(this, conn, addr, addrlen);
return lwipstack->lwip_Bind(this, vs, addr, addrlen);
#endif
return ZT_ERR_GENERAL_FAILURE;
}
// Listen for an incoming connection
int SocketTap::Listen(Connection *conn, int backlog) {
// Listen for an incoming VirtualSocket
int VirtualTap::Listen(VirtualSocket *vs, int backlog) {
#if defined(NO_STACK)
return -1;
#endif
Mutex::Lock _l(_tcpconns_m);
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Listen(conn, backlog);
return picostack->pico_Listen(vs, backlog);
return ZT_ERR_GENERAL_FAILURE;
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Listen(conn, backlog);
return lwipstack->lwip_Listen(vs, backlog);
return ZT_ERR_GENERAL_FAILURE;
#endif
return ZT_ERR_GENERAL_FAILURE;
}
// Accept a connection
Connection* SocketTap::Accept(Connection *conn) {
// Accept a VirtualSocket
VirtualSocket* VirtualTap::Accept(VirtualSocket *vs) {
#if defined(NO_STACK)
return NULL;
#endif
#if defined(STACK_PICO)
if(picostack)
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Accept(conn);
return picostack->pico_Accept(vs);
return NULL;
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Accept(conn);
return lwipstack->lwip_Accept(vs);
return NULL;
#endif
return NULL;
}
// Read from stack/buffers into the app's socket
int SocketTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) {
int VirtualTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) {
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Read(this, sock, (Connection*)uptr, stack_invoked);
return picostack->pico_Read(this, sock, (VirtualSocket*)uptr, stack_invoked);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Read((Connection*)*(_phy.getuptr(sock)), stack_invoked);
return lwipstack->lwip_Read((VirtualSocket*)*(_phy.getuptr(sock)), stack_invoked);
#endif
return -1;
}
// Write data from app socket to the virtual wire, either raw over VL2, or via network stack
int SocketTap::Write(Connection *conn, void *data, ssize_t len) {
int VirtualTap::Write(VirtualSocket *vs, void *data, ssize_t len) {
// VL2, SOCK_RAW, no network stack
if(conn->socket_type == SOCK_RAW) {
if(vs->socket_type == SOCK_RAW) {
struct ether_header *eh = (struct ether_header *) data;
MAC src_mac;
MAC dest_mac;
@@ -409,49 +407,49 @@ namespace ZeroTier {
}
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Write(conn, data, len);
return picostack->pico_Write(vs, data, len);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Write(conn, data, len);
return lwipstack->lwip_Write(vs, data, len);
#endif
return -1;
}
// Send data to a specified host
int SocketTap::SendTo(Connection *conn, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen)
int VirtualTap::SendTo(VirtualSocket *vs, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen)
{
// TODO: flags
int err = 0;
DEBUG_INFO();
#if defined(STACK_PICO)
if(picostack) {
err = picostack->pico_Connect(conn, addr, addrlen); // implicit
err = picostack->pico_Write(conn, (void*)buf, len);
err = picostack->pico_Connect(vs, addr, addrlen); // implicit
err = picostack->pico_Write(vs, (void*)buf, len);
}
#endif
#if defined(STACK_LWIP)
if(lwipstack)
err = lwipstack->lwip_Connect(conn, addr, addrlen); // implicit
err = lwipstack->lwip_Write(conn, (void*)buf, len);
err = lwipstack->lwip_Connect(vs, addr, addrlen); // implicit
err = lwipstack->lwip_Write(vs, (void*)buf, len);
#endif
return err;
}
int SocketTap::Close(Connection *conn) {
int VirtualTap::Close(VirtualSocket *vs) {
#if defined(STACK_PICO)
if(!conn) {
DEBUG_ERROR("invalid connection");
if(!vs) {
DEBUG_ERROR("invalid VirtualSocket");
return -1;
}
picostack->pico_Close(conn);
if(!conn->sock) {
picostack->pico_Close(vs);
if(!vs->sock) {
// DEBUG_EXTRA("invalid PhySocket");
return -1;
}
// Here we assume _tcpconns_m is already locked by caller
// FIXME: is this assumption still valid
if(conn->state==ZT_SOCK_STATE_LISTENING)
if(vs->state==ZT_SOCK_STATE_LISTENING)
{
// since we never wrapped this socket
DEBUG_INFO("in LISTENING state, no need to close in PhyIO");
@@ -459,14 +457,14 @@ namespace ZeroTier {
}
else
{
if(conn->sock)
_phy.close(conn->sock, false);
if(vs->sock)
_phy.close(vs->sock, false);
}
close(_phy.getDescriptor(conn->sock));
for(size_t i=0;i<_Connections.size();++i) {
if(_Connections[i] == conn){
close(_phy.getDescriptor(vs->sock));
for(size_t i=0;i<_VirtualSockets.size();++i) {
if(_VirtualSockets[i] == vs){
// FIXME: double free issue exists here (potentially)
// _Connections.erase(_Connections.begin() + i);
// _VirtualSockets.erase(_VirtualSockets.begin() + i);
//delete conn;
break;
}
@@ -474,12 +472,12 @@ namespace ZeroTier {
#endif
#if defined(STACK_LWIP)
if(lwipstack)
lwipstack->lwip_Close(conn);
lwipstack->lwip_Close(vs);
#endif
return 0; // TODO
}
void SocketTap::Housekeeping()
void VirtualTap::Housekeeping()
{
Mutex::Lock _l(_tcpconns_m);
std::time_t current_ts = std::time(nullptr);
@@ -537,7 +535,7 @@ namespace ZeroTier {
}
}
// TODO: Clean up Connection objects
// TODO: Clean up VirtualSocket objects
last_housekeeping_ts = std::time(nullptr);
}
@@ -547,14 +545,14 @@ namespace ZeroTier {
/* Not used in this implementation */
/****************************************************************************/
void SocketTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
void VirtualTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len) {}
void SocketTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
void SocketTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
void VirtualTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
void VirtualTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,
const struct sockaddr *from) {}
void SocketTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
void SocketTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
void SocketTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
void VirtualTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
void VirtualTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
void VirtualTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
} // namespace ZeroTier

View File

@@ -24,8 +24,8 @@
* of your own application.
*/
#ifndef ZT_SOCKETTAP_HPP
#define ZT_SOCKETTAP_HPP
#ifndef ZT_VIRTUALTAP_HPP
#define ZT_VIRTUALTAP_HPP
#include <stdio.h>
#include <stdlib.h>
@@ -44,7 +44,7 @@
#include "Phy.hpp"
#include "libzt.h"
#include "Connection.hpp"
#include "VirtualSocket.hpp"
#if defined(STACK_PICO)
#include "picoTCP.hpp"
@@ -66,12 +66,12 @@ namespace ZeroTier {
/*
* Socket Tap -- emulates an Ethernet tap device
*/
class SocketTap
class VirtualTap
{
friend class Phy<SocketTap *>;
friend class Phy<VirtualTap *>;
public:
SocketTap(
VirtualTap(
const char *homePath,
const MAC &mac,
unsigned int mtu,
@@ -81,7 +81,7 @@ namespace ZeroTier {
void (*handler)(void *, void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
~SocketTap();
~VirtualTap();
void setEnabled(bool en);
bool enabled() const;
@@ -92,13 +92,13 @@ namespace ZeroTier {
bool registerIpWithStack(const InetAddress &ip);
/*
* Adds an address to the userspace stack interface associated with this SocketTap
* - Starts SocketTap main thread ONLY if successful
* Adds an address to the userspace stack interface associated with this VirtualTap
* - Starts VirtualTap main thread ONLY if successful
*/
bool addIp(const InetAddress &ip);
/*
* Removes an address from the userspace stack interface associated with this SocketTap
* Removes an address from the userspace stack interface associated with this VirtualTap
*/
bool removeIp(const InetAddress &ip);
@@ -141,7 +141,7 @@ namespace ZeroTier {
const void *, unsigned int);
/*
* Signals us to close the TcpConnection associated with this PhySocket
* Signals us to close the TcpVirtualSocket associated with this PhySocket
*/
void phyOnUnixClose(PhySocket *sock, void **uptr);
@@ -210,9 +210,9 @@ namespace ZeroTier {
unsigned int _mtu;
uint64_t _nwid;
PhySocket *_unixListenSocket;
Phy<SocketTap *> _phy;
Phy<VirtualTap *> _phy;
std::vector<Connection*> _Connections;
std::vector<VirtualSocket*> _VirtualSockets;
Thread _thread;
std::string _dev; // path to Unix domain socket
@@ -233,24 +233,24 @@ namespace ZeroTier {
/****************************************************************************/
/*
* Connect to a remote host via the userspace stack interface associated with this SocketTap
* Connect to a remote host via the userspace stack interface associated with this VirtualTap
*/
int Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/*
* Bind to the userspace stack interface associated with this SocketTap
* Bind to the userspace stack interface associated with this VirtualTap
*/
int Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/*
* Listen for a Connection
* Listen for a VirtualSocket
*/
int Listen(Connection *conn, int backlog);
int Listen(VirtualSocket *vs, int backlog);
/*
* Accepts an incoming Connection
* Accepts an incoming VirtualSocket
*/
Connection* Accept(Connection *conn);
VirtualSocket* Accept(VirtualSocket *vs);
/*
* Move data from RX buffer to application's "socket"
@@ -260,20 +260,20 @@ namespace ZeroTier {
/*
* Move data from application's "socket" into network stack
*/
int Write(Connection *conn, void *data, ssize_t len);
int Write(VirtualSocket *vs, void *data, ssize_t len);
/*
* Send data to specified host
*/
int SendTo(Connection *conn, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
int SendTo(VirtualSocket *vs, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
/*
* Closes a Connection
* Closes a VirtualSocket
*/
int Close(Connection *conn);
int Close(VirtualSocket *vs);
/*
* Disposes of previously-closed Connections
* Disposes of previously-closed VirtualSockets
*/
void Housekeeping();

View File

@@ -67,7 +67,7 @@ for applications to use. See also: include/libzt.h */
#include "InetAddress.hpp"
#include "ZeroTierOne.h"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
#include "libzt.h"
#ifdef __cplusplus
@@ -89,14 +89,14 @@ namespace ZeroTier {
#endif
/*
* "sockets" that have been created but not bound to a SocketTap interface yet
* "sockets" that have been created but not bound to a VirtualTap interface yet
*/
std::map<int, Connection*> unmap;
std::map<int, VirtualSocket*> unmap;
/*
* For fast lookup of Connections and SocketTaps via given file descriptor
* For fast lookup of VirtualSockets and VirtualTaps via given file descriptor
*/
std::map<int, std::pair<Connection*,SocketTap*>*> fdmap;
std::map<int, std::pair<VirtualSocket*,VirtualTap*>*> fdmap;
/*
* Virtual tap interfaces, one per virtual network
@@ -105,7 +105,7 @@ namespace ZeroTier {
ZeroTier::Mutex _vtaps_lock;
ZeroTier::Mutex _multiplexer_lock;
ZeroTier::Mutex _accepted_connection_lock;
ZeroTier::Mutex _accepted_VirtualSocket_lock;
}
/****************************************************************************/
@@ -165,7 +165,7 @@ void zts_join(const char * nwid) {
// provide ZTO service reference to virtual taps
// TODO: This might prove to be unreliable, but it works for now
for(int i=0;i<ZeroTier::vtaps.size(); i++) {
ZeroTier::SocketTap *s = (ZeroTier::SocketTap*)ZeroTier::vtaps[i];
ZeroTier::VirtualTap *s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
s->zt1ServiceRef=(void*)ZeroTier::zt1Service;
}
}
@@ -263,7 +263,7 @@ void zts_get_ipv4_address(const char *nwid, char *addrstr, const int addrlen)
{
if(ZeroTier::zt1Service) {
uint64_t nwid_int = strtoull(nwid, NULL, 16);
ZeroTier::SocketTap *tap = getTapByNWID(nwid_int);
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
if(tap && tap->_ips.size()){
for(int i=0; i<tap->_ips.size(); i++) {
if(tap->_ips[i].isV4()) {
@@ -285,7 +285,7 @@ void zts_get_ipv6_address(const char *nwid, char *addrstr, const int addrlen)
{
if(ZeroTier::zt1Service) {
uint64_t nwid_int = strtoull(nwid, NULL, 16);
ZeroTier::SocketTap *tap = getTapByNWID(nwid_int);
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
if(tap && tap->_ips.size()){
for(int i=0; i<tap->_ips.size(); i++) {
if(tap->_ips[i].isV6()) {
@@ -351,11 +351,11 @@ void zts_disable_http_control_plane()
}
/****************************************************************************/
/* SocketTap Multiplexer Functionality */
/* VirtualTap Multiplexer Functionality */
/* - This section of the API is used to implement the general socket */
/* controls. Basically this is designed to handle socket provisioning */
/* requests when no SocketTap is yet initialized, and as a way to */
/* determine which SocketTap is to be used for a particular connect() or */
/* requests when no VirtualTap is yet initialized, and as a way to */
/* determine which VirtualTap is to be used for a particular connect() or */
/* bind() call. This enables multi-network support */
/****************************************************************************/
@@ -396,25 +396,25 @@ int zts_socket(ZT_SOCKET_SIG) {
if(socket_type == SOCK_RAW)
{
// Connection is only used to associate a socket with a SocketTap, it has no other implication
ZeroTier::Connection *conn = new ZeroTier::Connection();
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->protocol = protocol;
ZeroTier::unmap[conn->app_fd] = conn;
return conn->app_fd;
// VirtualSocket is only used to associate a socket with a VirtualTap, it has no other implication
ZeroTier::VirtualSocket *vs = new ZeroTier::VirtualSocket();
vs->socket_family = socket_family;
vs->socket_type = socket_type;
vs->protocol = protocol;
ZeroTier::unmap[vs->app_fd] = vs;
return vs->app_fd;
}
#if defined(STACK_PICO)
struct pico_socket *p;
err = ZeroTier::picostack->pico_Socket(&p, socket_family, socket_type, protocol);
if(p) {
ZeroTier::Connection *conn = new ZeroTier::Connection();
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->picosock = p;
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
ZeroTier::VirtualSocket *vs = new ZeroTier::VirtualSocket();
vs->socket_family = socket_family;
vs->socket_type = socket_type;
vs->picosock = p;
ZeroTier::unmap[vs->app_fd] = vs;
err = vs->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create pico_socket");
@@ -427,12 +427,12 @@ int zts_socket(ZT_SOCKET_SIG) {
void *pcb;
err = ZeroTier::lwipstack->lwip_Socket(&pcb, socket_family, socket_type, protocol);
if(pcb) {
ZeroTier::Connection *conn = new ZeroTier::Connection();
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->pcb = pcb;
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
ZeroTier::VirtualSocket *vs = new ZeroTier::VirtualSocket();
vs->socket_family = socket_family;
vs->socket_type = socket_type;
vs->pcb = pcb;
ZeroTier::unmap[vs->app_fd] = vs;
err = vs->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create lwip pcb");
@@ -453,12 +453,12 @@ Darwin:
[ ] [EADDRINUSE] The address is already in use.
[ ] [EADDRNOTAVAIL] The specified address is not available on this machine.
[ ] [EAFNOSUPPORT] Addresses in the specified address family cannot be used with this socket.
[ ] [EALREADY] The socket is non-blocking and a previous connection attempt has not yet been completed.
[ ] [EALREADY] The socket is non-blocking and a previous VirtualSocket attempt has not yet been completed.
[--] [EBADF] socket is not a valid descriptor.
[ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for connections) or explicitly rejected.
[ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for VirtualSockets) 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.
[--] [EINPROGRESS] The socket is non-blocking and the VirtualSocket 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).
@@ -467,26 +467,26 @@ Darwin:
[--] [ENETUNREACH] The network isn't reachable from this host.
[ ] [ENOBUFS] The system call was unable to allocate a needed memory buffer.
[ ] [ENOTSOCK] socket is not a file descriptor for a socket.
[ ] [EOPNOTSUPP] Because socket is listening, no connection is allowed.
[ ] [EOPNOTSUPP] Because socket is listening, no VirtualSocket is allowed.
[ ] [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.
[ ] [ETIMEDOUT] VirtualSocket establishment timed out without establishing a VirtualSocket.
[ ] [ECONNRESET] Remote host reset the VirtualSocket 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.
VirtualSocket 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.
[ ] [EALREADY] The socket is nonblocking and a previous VirtualSocket 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
[ ] [EINPROGRESS] The socket is nonblocking and the VirtualSocket 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).
@@ -494,7 +494,7 @@ Linux:
[ ] [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
[ ] [ETIMEDOUT] Timeout while attempting VirtualSocket. The server may be too busy to accept new VirtualSockets. Note that for
IP sockets the timeout may be very long when syncookies are enabled on the server.
*/
@@ -512,22 +512,22 @@ int zts_connect(ZT_CONNECT_SIG) {
return -1;
}
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
ZeroTier::SocketTap *tap;
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
ZeroTier::VirtualTap *tap;
if(conn) {
if(vs) {
char ipstr[INET6_ADDRSTRLEN];
memset(ipstr, 0, INET6_ADDRSTRLEN);
ZeroTier::InetAddress iaddr;
int port = 0;
if(conn->socket_family == AF_INET) {
if(vs->socket_family == AF_INET) {
inet_ntop(AF_INET,
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
iaddr.fromString(ipstr);
port = ((struct sockaddr_in*)addr)->sin_port;
}
if(conn->socket_family == AF_INET6) {
if(vs->socket_family == AF_INET6) {
inet_ntop(AF_INET6,
(const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
// TODO: This is a hack, determine a proper way to do this
@@ -546,33 +546,33 @@ int zts_connect(ZT_CONNECT_SIG) {
else {
#if defined(STACK_PICO)
// pointer to tap we use in callbacks from the stack
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
vs->picosock->priv = new ZeroTier::VirtualBindingPair(tap, vs);
#endif
#if defined(STACK_LWIP)
#endif
err = tap->Connect(conn, addr, addrlen);
err = tap->Connect(vs, addr, addrlen);
if(err == 0) {
tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
conn->tap = tap;
tap->_VirtualSockets.push_back(vs); // Give this VirtualSocket to the tap we decided on
vs->tap = tap;
}
// Wrap the socketpair we created earlier
// For I/O loop participation and referencing the PhySocket's parent Connection in callbacks
conn->sock = tap->_phy.wrapSocket(conn->sdk_fd, conn);
// For I/O loop participation and referencing the PhySocket's parent VirtualSocket in callbacks
vs->sock = tap->_phy.wrapSocket(vs->sdk_fd, vs);
}
}
else {
DEBUG_ERROR("unable to locate connection");
DEBUG_ERROR("unable to locate VirtualSocket");
errno = EBADF;
err = -1;
}
ZeroTier::unmap.erase(fd);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(vs, tap);
ZeroTier::_multiplexer_lock.unlock();
// NOTE: pico_socket_connect() will return 0 if no error happens immediately, but that doesn't indicate
// the connection was completed, for that we must wait for a callback from the stack. During that
// callback we will place the Connection in a ZT_SOCK_STATE_UNHANDLED_CONNECTED state to signal
// to the multiplexer logic that this connection is complete and a success value can be sent to the
// the VirtualSocket was completed, for that we must wait for a callback from the stack. During that
// callback we will place the VirtualSocket in a ZT_SOCK_STATE_UNHANDLED_CONNECTED state to signal
// to the multiplexer logic that this VirtualSocket is complete and a success value can be sent to the
// user application
int f_err, blocking = 1;
@@ -596,15 +596,15 @@ int zts_connect(ZT_CONNECT_SIG) {
bool complete = false;
while(true)
{
// FIXME: locking and unlocking so often might cause a performance bottleneck while outgoing connections
// FIXME: locking and unlocking so often might cause a performance bottleneck while outgoing VirtualSockets
// are being established (also applies to accept())
usleep(ZT_CONNECT_RECHECK_DELAY * 1000);
//DEBUG_ERROR("waiting to connect...\n");
tap->_tcpconns_m.lock();
for(int i=0; i<tap->_Connections.size(); i++)
for(int i=0; i<tap->_VirtualSockets.size(); i++)
{
#if defined(STACK_PICO)
if(tap->_Connections[i]->state == PICO_ERR_ECONNRESET) {
if(tap->_VirtualSockets[i]->state == PICO_ERR_ECONNRESET) {
errno = ECONNRESET;
DEBUG_ERROR("ECONNRESET");
err = -1;
@@ -612,8 +612,8 @@ int zts_connect(ZT_CONNECT_SIG) {
#endif
#if defined(STACK_LWIP)
#endif
if(tap->_Connections[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) {
tap->_Connections[i]->state = ZT_SOCK_STATE_CONNECTED;
if(tap->_VirtualSockets[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) {
tap->_VirtualSockets[i]->state = ZT_SOCK_STATE_CONNECTED;
errno = 0;
err = 0; // complete
complete = true;
@@ -655,20 +655,20 @@ int zts_bind(ZT_BIND_SIG) {
return -1;
}
ZeroTier::_multiplexer_lock.lock();
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
ZeroTier::SocketTap *tap;
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
ZeroTier::VirtualTap *tap;
if(conn) {
if(vs) {
char ipstr[INET6_ADDRSTRLEN];
memset(ipstr, 0, INET6_ADDRSTRLEN);
ZeroTier::InetAddress iaddr;
int port = 0;
if(conn->socket_family == AF_INET) {
if(vs->socket_family == AF_INET) {
inet_ntop(AF_INET,
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
port = ((struct sockaddr_in*)addr)->sin_port;
}
if(conn->socket_family == AF_INET6) {
if(vs->socket_family == AF_INET6) {
inet_ntop(AF_INET6,
(const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
port = ((struct sockaddr_in6*)addr)->sin6_port;
@@ -684,30 +684,30 @@ int zts_bind(ZT_BIND_SIG) {
}
#if defined(STACK_PICO)
else {
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
err = tap->Bind(conn, addr, addrlen);
conn->tap = tap;
vs->picosock->priv = new ZeroTier::VirtualBindingPair(tap, vs);
tap->_VirtualSockets.push_back(vs); // Give this VirtualSocket to the tap we decided on
err = tap->Bind(vs, addr, addrlen);
vs->tap = tap;
if(err == 0) { // success
ZeroTier::unmap.erase(fd);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(vs, tap);
}
}
#endif
#if defined(STACK_LWIP)
else {
tap->_Connections.push_back(conn);
err = tap->Bind(conn, addr, addrlen);
conn->tap = tap;
tap->_VirtualSockets.push_back(vs);
err = tap->Bind(vs, addr, addrlen);
vs->tap = tap;
if(err == 0) { // success
ZeroTier::unmap.erase(fd);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(vs, tap);
}
}
#endif
}
else {
DEBUG_ERROR("unable to locate connection");
DEBUG_ERROR("unable to locate VirtualSocket");
errno = EBADF;
err = -1;
}
@@ -746,23 +746,23 @@ int zts_listen(ZT_LISTEN_SIG) {
return -1;
}
ZeroTier::_multiplexer_lock.lock();
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *p = ZeroTier::fdmap[fd];
if(!p) {
DEBUG_ERROR("unable to locate connection pair. did you bind?");
DEBUG_ERROR("unable to locate VirtualSocket pair. did you bind?");
errno = EDESTADDRREQ;
return -1;
}
ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second;
if(!tap || !conn) {
ZeroTier::VirtualSocket *vs = p->first;
ZeroTier::VirtualTap *tap = p->second;
if(!tap || !vs) {
DEBUG_ERROR("unable to locate tap interface for file descriptor");
errno = EBADF;
return -1;
}
if(!err) {
backlog = backlog > 128 ? 128 : backlog; // See: /proc/sys/net/core/somaxconn
err = tap->Listen(conn, backlog);
conn->state = ZT_SOCK_STATE_LISTENING;
err = tap->Listen(vs, backlog);
vs->state = ZT_SOCK_STATE_LISTENING;
ZeroTier::_multiplexer_lock.unlock();
}
return err;
@@ -777,7 +777,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 VirtualSockets
are present to be accepted.
[--] [EMFILE] The per-process descriptor table is full.
[ ] [ENFILE] The system file table is full.
@@ -789,24 +789,24 @@ int zts_accept(ZT_ACCEPT_SIG) {
errno = EBADF;
return -1;
}
// +1 since we'll be creating a new pico_socket when we accept the connection
// +1 since we'll be creating a new pico_socket when we accept the VirtualSocket
if(!can_provision_new_socket()) {
DEBUG_ERROR("cannot provision additional socket due to limitation of network stack");
errno = EMFILE;
return -1;
}
ZeroTier::_multiplexer_lock.lock();
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *p = ZeroTier::fdmap[fd];
if(!p) {
DEBUG_ERROR("unable to locate connection pair (did you zts_bind())?");
DEBUG_ERROR("unable to locate VirtualSocket pair (did you zts_bind())?");
errno = EBADF;
err = -1;
}
else {
ZeroTier::Connection *conn = p->first;
ZeroTier::SocketTap *tap = p->second;
ZeroTier::VirtualSocket *vs = p->first;
ZeroTier::VirtualTap *tap = p->second;
// BLOCKING: loop and keep checking until we find a newly accepted connection
// BLOCKING: loop and keep checking until we find a newly accepted VirtualSocket
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);
@@ -817,24 +817,24 @@ int zts_accept(ZT_ACCEPT_SIG) {
}
if(!err) {
ZeroTier::Connection *accepted_conn;
ZeroTier::VirtualSocket *accepted_vs;
if(!blocking) { // non-blocking
DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode");
errno = EWOULDBLOCK;
err = -1;
accepted_conn = tap->Accept(conn);
accepted_vs = tap->Accept(vs);
}
else { // blocking
while(true) {
usleep(ZT_ACCEPT_RECHECK_DELAY * 1000);
accepted_conn = tap->Accept(conn);
if(accepted_conn)
accepted_vs = tap->Accept(vs);
if(accepted_vs)
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;
if(accepted_vs) {
ZeroTier::fdmap[accepted_vs->app_fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(accepted_vs, tap);
err = accepted_vs->app_fd;
}
}
}
@@ -847,12 +847,12 @@ 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.
[ ] [EAGAIN or EWOULDBLOCK] The socket is marked nonblocking and no VirtualSockets 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.
[ ] [ECONNABORTED] A VirtualSocket 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).
[NA] [EINTR] The system call was interrupted by a signal that was caught before a valid VirtualSocket arrived; see signal(7).
[ ] [EINVAL] Socket is not listening for VirtualSockets, 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.
@@ -863,7 +863,7 @@ Errors
In addition, Linux accept() may fail if:
EPERM Firewall rules forbid connection.
EPERM Firewall rules forbid VirtualSocket.
*/
#if defined(__linux__)
int zts_accept4(ZT_ACCEPT4_SIG)
@@ -1016,36 +1016,36 @@ 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];
// First, look for for unassigned VirtualSockets
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
// Since we found an unassigned connection, we don't need to consult the stack or tap
// Since we found an unassigned VirtualSocket, we don't need to consult the stack or tap
// during closure - it isn't yet stitched into the clockwork
if(conn) // unassigned
if(vs) // unassigned
{
DEBUG_ERROR("unassigned closure");
if((err = pico_socket_close(conn->picosock)) < 0)
if((err = pico_socket_close(vs->picosock)) < 0)
DEBUG_ERROR("error calling pico_socket_close()");
if((err = close(conn->app_fd)) < 0)
if((err = close(vs->app_fd)) < 0)
DEBUG_ERROR("error closing app_fd");
if((err = close(conn->sdk_fd)) < 0)
if((err = close(vs->sdk_fd)) < 0)
DEBUG_ERROR("error closing sdk_fd");
delete conn;
delete vs;
ZeroTier::unmap.erase(fd);
}
else // assigned
{
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *p = ZeroTier::fdmap[fd];
if(!p)
{
DEBUG_ERROR("unable to locate connection pair.");
DEBUG_ERROR("unable to locate VirtualSocket pair.");
errno = EBADF;
err = -1;
}
else // found everything, begin closure
{
conn = p->first;
ZeroTier::SocketTap *tap = p->second;
vs = p->first;
ZeroTier::VirtualTap *tap = p->second;
// check if socket is blocking
int f_err, blocking = 1;
@@ -1060,7 +1060,7 @@ int zts_close(ZT_CLOSE_SIG)
if(blocking) {
DEBUG_INFO("blocking, waiting for write operations before closure...");
for(int i=0; i<ZT_SDK_CLTIME; i++) {
if(conn->TXbuf->count() == 0)
if(vs->TXbuf->count() == 0)
break;
usleep(ZT_API_CHECK_INTERVAL * 1000);
}
@@ -1087,8 +1087,8 @@ int zts_close(ZT_CLOSE_SIG)
}
*/
//DEBUG_INFO("s->state = %s", ZeroTier::picoTCP::beautify_pico_state(conn->picosock->state));
tap->Close(conn);
//DEBUG_INFO("s->state = %s", ZeroTier::picoTCP::beautify_pico_state(vs->picosock->state));
tap->Close(vs);
ZeroTier::fdmap.erase(fd);
err = 0;
}
@@ -1165,23 +1165,23 @@ int zts_ioctl(ZT_IOCTL_SIG)
if(argp)
{
struct ifreq *ifr = (struct ifreq *)argp;
ZeroTier::SocketTap *tap = getTapByName(ifr->ifr_name);
ZeroTier::VirtualTap *tap = getTapByName(ifr->ifr_name);
if(!tap) {
DEBUG_ERROR("unable to locate tap interface with that name");
err = -1;
errno = EINVAL;
}
// index of SocketTap interface
// index of VirtualTap interface
if(request == SIOCGIFINDEX) {
ifr->ifr_ifindex = tap->ifindex;
err = 0;
}
// MAC addres or SocketTap
// MAC addres or VirtualTap
if(request == SIOCGIFHWADDR) {
tap->_mac.copyTo(&(ifr->ifr_hwaddr.sa_data), sizeof(ifr->ifr_hwaddr.sa_data));
err = 0;
}
// IP address of SocketTap
// IP address of VirtualTap
if(request == SIOCGIFADDR) {
struct sockaddr_in *in4 = (struct sockaddr_in *)&(ifr->ifr_addr);
memcpy(&(in4->sin_addr.s_addr), tap->_ips[0].rawIpData(), sizeof(ifr->ifr_addr));
@@ -1206,19 +1206,19 @@ Linux:
[ ] [EAGAIN or EWOULDBLOCK] The socket is marked nonblocking and the requested operation would block. 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] An invalid descriptor was specified.
[ ] [ECONNRESET] Connection reset by peer.
[ ] [EDESTADDRREQ] The socket is not connection-mode, and no peer address is set.
[ ] [ECONNRESET] VirtualSocket reset by peer.
[ ] [EDESTADDRREQ] The socket is not VirtualSocket-mode, and no peer address is set.
[ ] [EFAULT] An invalid user space address was specified for an argument.
[ ] [EINTR] A signal occurred before any data was transmitted; see signal(7).
[ ] [EINVAL] Invalid argument passed.
[ ] [EISCONN] The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)
[ ] [EISCONN] The VirtualSocket-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)
[ ] [EMSGSIZE] The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.
[ ] [ENOBUFS] The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)
[ ] [ENOMEM] No memory available.
[ ] [ENOTCONN] The socket is not connected, and no target has been given.
[ ] [ENOTSOCK] The argument sockfd is not a socket.
[ ] [EOPNOTSUPP] Some bit in the flags argument is inappropriate for the socket type.
[ ] [EPIPE] The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
[ ] [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.
*/
ssize_t zts_sendto(ZT_SENDTO_SIG)
@@ -1230,21 +1230,21 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
err = -1;
}
else {
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
ZeroTier::InetAddress iaddr;
ZeroTier::SocketTap *tap;
ZeroTier::VirtualTap *tap;
char ipstr[INET6_ADDRSTRLEN];
int port;
memset(ipstr, 0, INET6_ADDRSTRLEN);
if(conn->socket_type == SOCK_DGRAM) {
if(conn->socket_family == AF_INET) {
if(vs->socket_type == SOCK_DGRAM) {
if(vs->socket_family == AF_INET) {
inet_ntop(AF_INET,
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
iaddr.fromString(ipstr);
port = ((struct sockaddr_in*)addr)->sin_port;
}
if(conn->socket_family == AF_INET6) {
if(vs->socket_family == AF_INET6) {
inet_ntop(AF_INET6,
(const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
// TODO: This is a hack, determine a proper way to do this
@@ -1255,7 +1255,7 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
}
tap = getTapByAddr(iaddr);
if(tap) {
tap->SendTo(conn, buf, len, flags, addr, addrlen);
tap->SendTo(vs, buf, len, flags, addr, addrlen);
}
else {
DEBUG_INFO("SOCK_DGRAM, tap not found");
@@ -1263,19 +1263,19 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
return -1;
}
}
if(conn->socket_type == SOCK_RAW)
if(vs->socket_type == SOCK_RAW)
{
struct sockaddr_ll *socket_address = (struct sockaddr_ll *)addr;
ZeroTier::SocketTap *tap = getTapByIndex(socket_address->sll_ifindex);
ZeroTier::VirtualTap *tap = getTapByIndex(socket_address->sll_ifindex);
if(tap)
{
DEBUG_INFO("found interface of ifindex=%d", tap->ifindex);
if(conn) {
DEBUG_INFO("located connection object for fd=%d", fd);
err = tap->Write(conn, (void*)buf, len);
if(vs) {
DEBUG_INFO("located VirtualSocket object for fd=%d", fd);
err = tap->Write(vs, (void*)buf, len);
}
else {
DEBUG_ERROR("unable to locate connection object for fd=%d", fd);
DEBUG_ERROR("unable to locate VirtualSocket object for fd=%d", fd);
err = -1;
errno = EINVAL;
}
@@ -1371,11 +1371,11 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
else
{
ZeroTier::_multiplexer_lock.lock();
// First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
// Since we found an unassigned connection, we don't need to consult the stack or tap
// First, look for for unassigned VirtualSockets
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
// Since we found an unassigned VirtualSocket, we don't need to consult the stack or tap
// during closure - it isn't yet stitched into the clockwork
if(conn) // unassigned
if(vs) // unassigned
{
DEBUG_ERROR("unassigned shutdown");
/*
@@ -1383,24 +1383,24 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
PICO_SHUT_WR
PICO_SHUT_RDWR
*/
if((err = pico_socket_shutdown(conn->picosock, mode)) < 0)
if((err = pico_socket_shutdown(vs->picosock, mode)) < 0)
DEBUG_ERROR("error calling pico_socket_shutdown()");
delete conn;
delete vs;
ZeroTier::unmap.erase(fd);
// FIXME: Is deleting this correct behaviour?
}
else // assigned
{
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *p = ZeroTier::fdmap[fd];
if(!p)
{
DEBUG_ERROR("unable to locate connection pair.");
DEBUG_ERROR("unable to locate VirtualSocket pair.");
errno = EBADF;
err = -1;
}
else // found everything, begin closure
{
conn = p->first;
vs = p->first;
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);
@@ -1412,13 +1412,13 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
if(blocking) {
DEBUG_INFO("blocking, waiting for write operations before shutdown...");
for(int i=0; i<ZT_SDK_CLTIME; i++) {
if(conn->TXbuf->count() == 0)
if(vs->TXbuf->count() == 0)
break;
usleep(ZT_API_CHECK_INTERVAL * 1000);
}
}
if((err = pico_socket_shutdown(conn->picosock, mode)) < 0)
if((err = pico_socket_shutdown(vs->picosock, mode)) < 0)
DEBUG_ERROR("error calling pico_socket_shutdown()");
}
}
@@ -1704,19 +1704,19 @@ int zts_get_pico_socket(int fd, struct pico_socket **s)
else
{
ZeroTier::_multiplexer_lock.lock();
// First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
if(conn)
// First, look for for unassigned VirtualSockets
ZeroTier::VirtualSocket *vs = ZeroTier::unmap[fd];
if(vs)
{
*s = conn->picosock;
*s = vs->picosock;
err = 1; // unassigned
}
else
{
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *p = ZeroTier::fdmap[fd];
if(!p)
{
DEBUG_ERROR("unable to locate connection pair.");
DEBUG_ERROR("unable to locate VirtualSocket pair.");
errno = EBADF;
err = -1;
}
@@ -1774,25 +1774,25 @@ std::vector<ZT_VirtualNetworkRoute> *zts_get_network_routes(char *nwid)
return ZeroTier::zt1Service->getRoutes(nwid_int);
}
ZeroTier::SocketTap *getTapByNWID(uint64_t nwid)
ZeroTier::VirtualTap *getTapByNWID(uint64_t nwid)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::SocketTap *s, *tap = nullptr;
ZeroTier::VirtualTap *s, *tap = nullptr;
for(int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::SocketTap*)ZeroTier::vtaps[i];
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if(s->_nwid == nwid) { tap = s; }
}
ZeroTier::_vtaps_lock.unlock();
return tap;
}
ZeroTier::SocketTap *getTapByAddr(ZeroTier::InetAddress &addr)
ZeroTier::VirtualTap *getTapByAddr(ZeroTier::InetAddress &addr)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::SocketTap *s, *tap = nullptr;
ZeroTier::VirtualTap *s, *tap = nullptr;
char ipbuf[64], ipbuf2[64], ipbuf3[64];
for(int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::SocketTap*)ZeroTier::vtaps[i];
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
// check address schemes
for(int j=0; j<s->_ips.size(); j++) {
if(s->_ips[j].isEqualPrefix(addr)
@@ -1824,12 +1824,12 @@ ZeroTier::SocketTap *getTapByAddr(ZeroTier::InetAddress &addr)
return tap;
}
ZeroTier::SocketTap *getTapByName(char *ifname)
ZeroTier::VirtualTap *getTapByName(char *ifname)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::SocketTap *s, *tap = nullptr;
ZeroTier::VirtualTap *s, *tap = nullptr;
for(int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::SocketTap*)ZeroTier::vtaps[i];
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if(!strcmp(s->_dev.c_str(), ifname)) {
tap = s;
}
@@ -1838,12 +1838,12 @@ ZeroTier::SocketTap *getTapByName(char *ifname)
return tap;
}
ZeroTier::SocketTap *getTapByIndex(int index)
ZeroTier::VirtualTap *getTapByIndex(int index)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::SocketTap *s, *tap = nullptr;
ZeroTier::VirtualTap *s, *tap = nullptr;
for(int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::SocketTap*)ZeroTier::vtaps[i];
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if(s->ifindex == index) {
tap = s;
}
@@ -1855,7 +1855,7 @@ ZeroTier::SocketTap *getTapByIndex(int index)
void dismantleTaps()
{
ZeroTier::_vtaps_lock.lock();
for(int i=0; i<ZeroTier::vtaps.size(); i++) { delete (ZeroTier::SocketTap*)ZeroTier::vtaps[i]; }
for(int i=0; i<ZeroTier::vtaps.size(); i++) { delete (ZeroTier::VirtualTap*)ZeroTier::vtaps[i]; }
ZeroTier::vtaps.clear();
ZeroTier::_vtaps_lock.unlock();
}

View File

@@ -29,7 +29,7 @@
#include <algorithm>
#include "libzt.h"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
#include "Utilities.hpp"
#include "lwIP.hpp"
@@ -57,7 +57,7 @@ err_t low_level_output(struct netif *netif, struct pbuf *p)
char *bufptr;
int totalLength = 0;
ZeroTier::SocketTap *tap = (ZeroTier::SocketTap*)netif->state;
ZeroTier::VirtualTap *tap = (ZeroTier::VirtualTap*)netif->state;
bufptr = buf;
// Copy data from each pbuf, one at a time
for(q = p; q != NULL; q = q->next) {
@@ -81,7 +81,7 @@ err_t low_level_output(struct netif *netif, struct pbuf *p)
namespace ZeroTier
{
void lwIP::lwip_init_interface(SocketTap *tap, const InetAddress &ip)
void lwIP::lwip_init_interface(VirtualTap *tap, const InetAddress &ip)
{
DEBUG_INFO();
Mutex::Lock _l(tap->_ips_m);
@@ -140,7 +140,7 @@ namespace ZeroTier
}
}
void lwIP::lwip_loop(SocketTap *tap)
void lwIP::lwip_loop(VirtualTap *tap)
{
DEBUG_INFO();
uint64_t prev_tcp_time = 0, prev_discovery_time = 0;
@@ -181,7 +181,7 @@ namespace ZeroTier
}
}
void lwIP::lwip_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void lwIP::lwip_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;
@@ -249,7 +249,7 @@ namespace ZeroTier
return -1;
}
int lwIP::lwip_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen)
int lwIP::lwip_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
DEBUG_INFO();
ip_addr_t ba;
@@ -269,7 +269,7 @@ namespace ZeroTier
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&addr;
in6_to_ip6((ip6_addr *)&ba, in6);
if(addr->sa_family == AF_INET6) {
struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr;
struct sockaddr_in6 *vsaddr6 = (struct sockaddr_in6 *)addr;
inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN);
DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(connaddr6->sin6_port));
}
@@ -277,25 +277,25 @@ namespace ZeroTier
DEBUG_INFO("addr=%s", addrstr);
if(conn->socket_type == SOCK_DGRAM) {
if(vs->socket_type == SOCK_DGRAM) {
// Generates no network traffic
if((err = udp_connect((struct udp_pcb*)conn->pcb,(ip_addr_t *)&ba,port)) < 0) {
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*)conn->pcb, nc_udp_recved, conn);
udp_recv((struct udp_pcb*)vs->pcb, nc_udp_recved, vs);
return ERR_OK;
}
if(conn->socket_type == SOCK_STREAM) {
struct tcp_pcb *tpcb = (struct tcp_pcb*)conn->pcb;
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_arg(tpcb, conn);
tcp_arg(tpcb, vs);
//DEBUG_EXTRA(" pcb->state=%x", conn->TCP_pcb->state);
//if(conn->TCP_pcb->state != CLOSED) {
//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;
@@ -343,7 +343,7 @@ namespace ZeroTier
return err;
}
int lwIP::lwip_Bind(SocketTap *tap, Connection *conn, const struct sockaddr *addr, socklen_t addrlen)
int lwIP::lwip_Bind(VirtualTap *tap, VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
DEBUG_INFO();
ip_addr_t ba;
@@ -363,26 +363,26 @@ namespace ZeroTier
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&addr;
in6_to_ip6((ip6_addr *)&ba, in6);
if(addr->sa_family == AF_INET6) {
struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr;
struct sockaddr_in6 *vsaddr6 = (struct sockaddr_in6 *)addr;
inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN);
DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(connaddr6->sin6_port));
}
#endif
if(conn->socket_type == SOCK_DGRAM) {
err = udp_bind((struct udp_pcb*)conn->pcb, (const ip_addr_t *)&ba, port);
if(vs->socket_type == SOCK_DGRAM) {
err = udp_bind((struct udp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port);
if(err == ERR_USE) {
err = -1;
errno = EADDRINUSE; // port in use
}
else {
// set the recv callback
udp_recv((struct udp_pcb*)conn->pcb, nc_udp_recved, new ConnectionPair(tap, conn));
udp_recv((struct udp_pcb*)vs->pcb, nc_udp_recved, new VirtualBindingPair(tap, vs));
err = ERR_OK;
errno = ERR_OK; // success
}
}
else if (conn->socket_type == SOCK_STREAM) {
err = tcp_bind((struct tcp_pcb*)conn->pcb, (const ip_addr_t *)&ba, port);
else if (vs->socket_type == SOCK_STREAM) {
err = tcp_bind((struct tcp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port);
if(err != ERR_OK) {
DEBUG_ERROR("err=%d", err);
if(err == ERR_USE){
@@ -406,103 +406,103 @@ namespace ZeroTier
return err;
}
int lwIP::lwip_Listen(Connection *conn, int backlog)
int lwIP::lwip_Listen(VirtualSocket *vs, int backlog)
{
DEBUG_INFO("conn=%p", conn);
DEBUG_INFO("vs=%p", vs);
struct tcp_pcb* listeningPCB;
#ifdef TCP_LISTEN_BACKLOG
listeningPCB = tcp_listen_with_backlog((struct tcp_pcb*)conn->pcb, backlog);
listeningPCB = tcp_listen_with_backlog((struct tcp_pcb*)vs->pcb, backlog);
#else
listeningPCB = tcp_listen((struct tcp_pcb*)conn->pcb);
listeningPCB = tcp_listen((struct tcp_pcb*)vs->pcb);
#endif
if(listeningPCB != NULL) {
conn->pcb = listeningPCB;
vs->pcb = listeningPCB;
tcp_accept(listeningPCB, nc_accept); // set callback
tcp_arg(listeningPCB, conn);
//fcntl(tap->_phy.getDescriptor(conn->sock), F_SETFL, O_NONBLOCK);
tcp_arg(listeningPCB, vs);
//fcntl(tap->_phy.getDescriptor(vs->sock), F_SETFL, O_NONBLOCK);
}
return 0;
}
Connection* lwIP::lwip_Accept(Connection *conn)
VirtualSocket* lwIP::lwip_Accept(VirtualSocket *vs)
{
if(!conn) {
DEBUG_ERROR("invalid conn");
if(!vs) {
DEBUG_ERROR("invalid virtual socket");
handle_general_failure();
return NULL;
}
// Retreive first of queued Connections from parent connection
Connection *new_conn = NULL;
Mutex::Lock _l(conn->tap->_tcpconns_m);
if(conn->_AcceptedConnections.size()) {
new_conn = conn->_AcceptedConnections.front();
conn->_AcceptedConnections.pop();
// Retreive first of queued VirtualSockets from parent VirtualSocket
VirtualSocket *new_vs = NULL;
Mutex::Lock _l(vs->tap->_tcpconns_m);
if(vs->_AcceptedConnections.size()) {
new_vs = vs->_AcceptedConnections.front();
vs->_AcceptedConnections.pop();
}
return new_conn;
return new_vs;
}
int lwIP::lwip_Read(Connection *conn, bool lwip_invoked)
int lwIP::lwip_Read(VirtualSocket *vs, bool lwip_invoked)
{
DEBUG_EXTRA("conn=%p", conn);
DEBUG_EXTRA("vs=%p", vs);
int err = 0;
if(!conn) {
DEBUG_ERROR("no connection");
if(!vs) {
DEBUG_ERROR("no VirtualSocket");
return -1;
}
if(!lwip_invoked) {
DEBUG_INFO("!lwip_invoked");
conn->tap->_tcpconns_m.lock();
conn->_rx_m.lock();
vs->tap->_tcpconns_m.lock();
vs->_rx_m.lock();
}
if(conn->RXbuf->count()) {
int max = conn->socket_type == SOCK_STREAM ? ZT_STACK_TCP_SOCKET_RX_SZ : ZT_STACK_TCP_SOCKET_RX_SZ;
int wr = std::min((ssize_t)max, (ssize_t)conn->RXbuf->count());
int n = conn->tap->_phy.streamSend(conn->sock, conn->RXbuf->get_buf(), wr);
if(vs->RXbuf->count()) {
int max = vs->socket_type == SOCK_STREAM ? ZT_STACK_TCP_SOCKET_RX_SZ : ZT_STACK_TCP_SOCKET_RX_SZ;
int wr = std::min((ssize_t)max, (ssize_t)vs->RXbuf->count());
int n = vs->tap->_phy.streamSend(vs->sock, vs->RXbuf->get_buf(), wr);
char str[22];
memcpy(str, conn->RXbuf->get_buf(), 22);
conn->RXbuf->consume(n);
memcpy(str, vs->RXbuf->get_buf(), 22);
vs->RXbuf->consume(n);
if(conn->socket_type == SOCK_DGRAM)
if(vs->socket_type == SOCK_DGRAM)
{
// TODO
}
if(conn->socket_type == SOCK_STREAM) { // Only acknolwedge receipt of TCP packets
tcp_recved((struct tcp_pcb*)conn->pcb, n);
if(vs->socket_type == SOCK_STREAM) { // Only acknolwedge receipt of TCP packets
tcp_recved((struct tcp_pcb*)vs->pcb, n);
DEBUG_TRANS("TCP RX %d bytes", n);
}
}
if(conn->RXbuf->count() == 0) {
if(vs->RXbuf->count() == 0) {
DEBUG_INFO("wrote everything");
conn->tap->_phy.setNotifyWritable(conn->sock, false); // nothing else to send to the app
vs->tap->_phy.setNotifyWritable(vs->sock, false); // nothing else to send to the app
}
if(!lwip_invoked) {
conn->tap->_tcpconns_m.unlock();
conn->_rx_m.unlock();
vs->tap->_tcpconns_m.unlock();
vs->_rx_m.unlock();
}
return err;
}
int lwIP::lwip_Write(Connection *conn, void *data, ssize_t len)
int lwIP::lwip_Write(VirtualSocket *vs, void *data, ssize_t len)
{
DEBUG_EXTRA("conn=%p, len=%d", (void*)&conn, len);
DEBUG_EXTRA("vs=%p, len=%d", (void*)&vs, len);
int err = 0;
if(!conn) {
DEBUG_ERROR("no connection");
if(!vs) {
DEBUG_ERROR("no VirtualSocket");
return -1;
}
if(conn->socket_type == SOCK_DGRAM)
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)conn->TXbuf->count(), (ssize_t)ZT_MAX_MTU);
DEBUG_EXTRA("allocating pbuf chain of size=%d for UDP packet, txsz=%d", udp_trans_len, conn->TXbuf->count());
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){
DEBUG_ERROR("unable to allocate new pbuf of size=%d", conn->TXbuf->count());
DEBUG_ERROR("unable to allocate new pbuf of size=%d", vs->TXbuf->count());
return -1;
}
memcpy(pb->payload, conn->TXbuf->get_buf(), udp_trans_len);
int err = udp_send((struct udp_pcb*)conn->pcb, pb);
memcpy(pb->payload, vs->TXbuf->get_buf(), udp_trans_len);
int err = udp_send((struct udp_pcb*)vs->pcb, pb);
if(err == ERR_MEM) {
DEBUG_ERROR("error sending packet. out of memory");
@@ -511,48 +511,48 @@ namespace ZeroTier
} else if(err != ERR_OK) {
DEBUG_ERROR("error sending packet - %d", err);
} else {
conn->TXbuf->consume(udp_trans_len); // success
vs->TXbuf->consume(udp_trans_len); // success
}
pbuf_free(pb);
return ERR_OK;
}
if(conn->socket_type == SOCK_STREAM)
if(vs->socket_type == SOCK_STREAM)
{
DEBUG_ERROR("socket_type==SOCK_STREAM");
// How much we are currently allowed to write to the connection
ssize_t sndbuf = ((struct tcp_pcb*)conn->pcb)->snd_buf;
// How much we are currently allowed to write to the VirtualSocket
ssize_t sndbuf = ((struct tcp_pcb*)vs->pcb)->snd_buf;
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
// now space on the buffer
DEBUG_ERROR("lwIP stack is full, sndbuf == 0");
conn->tap->_phy.setNotifyReadable(conn->sock, false);
vs->tap->_phy.setNotifyReadable(vs->sock, false);
return -1;
}
int buf_w = conn->TXbuf->write((const unsigned char*)data, len);
int buf_w = vs->TXbuf->write((const unsigned char*)data, len);
if (buf_w != len) {
// because we checked ZT_TCP_TX_BUF_SZ above, this should not happen
DEBUG_ERROR("TX wrote only %d but expected to write %d", buf_w, len);
exit(0);
}
if(conn->TXbuf->count() <= 0) {
if(vs->TXbuf->count() <= 0) {
return -1; // nothing to write
}
if(conn->sock) {
r = std::min((ssize_t)conn->TXbuf->count(), sndbuf);
if(vs->sock) {
r = std::min((ssize_t)vs->TXbuf->count(), sndbuf);
// Writes data pulled from the client's socket buffer to LWIP. This merely sends the
// data to LWIP to be enqueued and eventually sent to the network.
if(r > 0) {
err = tcp_write((struct tcp_pcb*)conn->pcb, conn->TXbuf->get_buf(), r, TCP_WRITE_FLAG_COPY);
tcp_output((struct tcp_pcb*)conn->pcb);
err = tcp_write((struct tcp_pcb*)vs->pcb, vs->TXbuf->get_buf(), r, TCP_WRITE_FLAG_COPY);
tcp_output((struct tcp_pcb*)vs->pcb);
if(err != ERR_OK) {
DEBUG_ERROR("error while writing to lwIP tcp_pcb, err=%d", err);
if(err == -1)
DEBUG_ERROR("lwIP out of memory");
return -1;
} else {
conn->TXbuf->consume(r); // success
vs->TXbuf->consume(r); // success
return ERR_OK;
}
}
@@ -561,22 +561,22 @@ namespace ZeroTier
return err;
}
int lwIP::lwip_Close(Connection *conn)
int lwIP::lwip_Close(VirtualSocket *vs)
{
DEBUG_INFO();
if(conn->socket_type == SOCK_DGRAM) {
udp_remove((struct udp_pcb*)conn->pcb);
if(vs->socket_type == SOCK_DGRAM) {
udp_remove((struct udp_pcb*)vs->pcb);
}
// FIXME: check if already closed? conn->TCP_pcb->state != CLOSED
if(conn->pcb) {
//DEBUG_EXTRA("conn=%p, sock=%p, PCB->state = %d",
// (void*)&conn, (void*)&sock, conn->TCP_pcb->state);
if(((struct tcp_pcb*)conn->pcb)->state == SYN_SENT /*|| conn->TCP_pcb->state == CLOSE_WAIT*/) {
DEBUG_EXTRA("ignoring close request. invalid PCB state for this operation. sock=%p", conn->sock);
// 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);
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;
}
struct tcp_pcb* tpcb = (struct tcp_pcb*)conn->pcb;
struct tcp_pcb* tpcb = (struct tcp_pcb*)vs->pcb;
if(tcp_close(tpcb) == ERR_OK) {
// Unregister callbacks for this PCB
tcp_arg(tpcb, NULL);
@@ -586,7 +586,7 @@ namespace ZeroTier
tcp_poll(tpcb, NULL, 1);
}
else {
DEBUG_EXTRA("error while calling tcp_close() sock=%p", conn->sock);
DEBUG_EXTRA("error while calling tcp_close() sock=%p", vs->sock);
}
}
return 0;
@@ -599,22 +599,22 @@ namespace ZeroTier
err_t lwIP::nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err)
{
DEBUG_INFO();
Connection *conn = (Connection *)arg;
VirtualSocket *vs = (VirtualSocket *)arg;
int tot = 0;
if(!conn) {
DEBUG_ERROR("no connection");
if(!vs) {
DEBUG_ERROR("no VirtualSocket");
return ERR_OK; // FIXME: Determine if this is correct behaviour expected by the stack
}
//Mutex::Lock _l(conn->tap->_tcpconns_m);
//Mutex::Lock _l2(conn->_rx_m);
conn->tap->_tcpconns_m.lock();
conn->_rx_m.lock();
//Mutex::Lock _l(vs->tap->_tcpconns_m);
//Mutex::Lock _l2(vs->_rx_m);
vs->tap->_tcpconns_m.lock();
vs->_rx_m.lock();
struct pbuf* q = p;
if(p == NULL) {
if(((struct tcp_pcb*)conn->pcb)->state == CLOSE_WAIT) {
if(((struct tcp_pcb*)vs->pcb)->state == CLOSE_WAIT) {
// FIXME: Implement?
}
DEBUG_INFO("p == NULL");
@@ -626,24 +626,24 @@ namespace ZeroTier
while(p != NULL) {
if(p->len <= 0)
break;
int avail = ZT_TCP_RX_BUF_SZ - conn->RXbuf->count();
int avail = ZT_TCP_RX_BUF_SZ - vs->RXbuf->count();
int len = p->len;
if(avail < len) {
DEBUG_ERROR("not enough room (%d bytes) on RX buffer", avail);
}
memcpy(conn->RXbuf->get_buf(), p->payload, len);
conn->RXbuf->produce(len);
memcpy(vs->RXbuf->get_buf(), p->payload, len);
vs->RXbuf->produce(len);
p = p->next;
tot += len;
}
DEBUG_INFO("tot=%d", tot);
conn->tap->_tcpconns_m.unlock();
conn->_rx_m.unlock();
vs->tap->_tcpconns_m.unlock();
vs->_rx_m.unlock();
if(tot) {
conn->tap->_phy.setNotifyWritable(conn->sock, true);
//conn->tap->phyOnUnixWritable(conn->sock, NULL, true); // to app
vs->tap->_phy.setNotifyWritable(vs->sock, true);
//vs->tap->phyOnUnixWritable(vs->sock, NULL, true); // to app
}
pbuf_free(q);
return ERR_OK;
@@ -651,27 +651,27 @@ namespace ZeroTier
err_t lwIP::nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err)
{
Connection *conn = (Connection*)arg;
DEBUG_INFO("conn=%p", conn);
//Mutex::Lock _l(conn->tap->_tcpconns_m);
// create and populate new Connection object
Connection *new_conn = new Connection();
new_conn->socket_type = SOCK_STREAM;
new_conn->pcb = newPCB;
new_conn->tap = conn->tap;
new_conn->sock = conn->tap->_phy.wrapSocket(new_conn->sdk_fd, new_conn);
//memcpy(new_conn->tap->_phy.getuptr(new_conn->sock), new_conn, sizeof(conn));
DEBUG_INFO("new_conn=%p", new_conn);
// add new Connection object to parent connection so that we can find it via lwip_Accept()
conn->_AcceptedConnections.push(new_conn);
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;
new_vs->tap = vs->tap;
new_vs->sock = vs->tap->_phy.wrapSocket(new_vs->sdk_fd, new_vs);
//memcpy(new_vs->tap->_phy.getuptr(new_vs->sock), new_vs, sizeof(vs));
DEBUG_INFO("new_vs=%p", new_vs);
// add new VirtualSocket object to parent VirtualSocket so that we can find it via lwip_Accept()
vs->_AcceptedConnections.push(new_vs);
// set callbacks
tcp_arg(newPCB, new_conn);
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);
// let lwIP know that it can queue additional incoming connections
tcp_accepted((struct tcp_pcb*)conn->pcb);
// let lwIP know that it can queue additional incoming VirtualSockets
tcp_accepted((struct tcp_pcb*)vs->pcb);
return 0;
}
@@ -684,13 +684,13 @@ namespace ZeroTier
err_t lwIP::nc_sent(void* arg, struct tcp_pcb *PCB, u16_t len)
{
DEBUG_EXTRA("pcb=%p", (void*)&PCB);
Connection *conn = (Connection *)arg;
Mutex::Lock _l(conn->tap->_tcpconns_m);
if(conn && len) {
int softmax = conn->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_UDP_TX_BUF_SZ;
if(conn->TXbuf->count() < softmax) {
conn->tap->_phy.setNotifyReadable(conn->sock, true);
conn->tap->_phy.whack();
VirtualSocket *vs = (VirtualSocket *)arg;
Mutex::Lock _l(vs->tap->_tcpconns_m);
if(vs && len) {
int softmax = vs->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_UDP_TX_BUF_SZ;
if(vs->TXbuf->count() < softmax) {
vs->tap->_phy.setNotifyReadable(vs->sock, true);
vs->tap->_phy.whack();
}
}
return ERR_OK;
@@ -699,8 +699,8 @@ namespace ZeroTier
err_t lwIP::nc_connected(void *arg, struct tcp_pcb *PCB, err_t err)
{
DEBUG_ATTN("pcb=%p", (void*)&PCB);
Connection *conn = (Connection *)arg;
if(conn)
VirtualSocket *vs = (VirtualSocket *)arg;
if(vs)
return ERR_OK;
return -1;
// FIXME: check stack for expected return values
@@ -714,16 +714,16 @@ namespace ZeroTier
void lwIP::nc_err(void *arg, err_t err)
{
DEBUG_ERROR("err=%d", err);
Connection *conn = (Connection *)arg;
if(!conn){
DEBUG_ERROR("conn==NULL");
VirtualSocket *vs = (VirtualSocket *)arg;
if(!vs){
DEBUG_ERROR("vs==NULL");
errno = -1; // FIXME: Find more appropriate value
}
Mutex::Lock _l(conn->tap->_tcpconns_m);
int fd = conn->tap->_phy.getDescriptor(conn->sock);
DEBUG_ERROR("conn=%p, pcb=%p, fd=%d, err=%d", conn, conn->pcb, fd, err);
DEBUG_ERROR("closing connection");
conn->tap->Close(conn);
Mutex::Lock _l(vs->tap->_tcpconns_m);
int fd = vs->tap->_phy.getDescriptor(vs->sock);
DEBUG_ERROR("vs=%p, pcb=%p, fd=%d, err=%d", vs, vs->pcb, fd, err);
DEBUG_ERROR("closing VirtualSocket");
vs->tap->Close(vs);
switch(err)
{
case ERR_MEM:
@@ -759,7 +759,7 @@ namespace ZeroTier
errno = EADDRINUSE;
break;
case ERR_ISCONN:
DEBUG_ERROR("ERR_ISCONN->EISCONN");
DEBUG_ERROR("ERR_ISvs->EISCONN");
errno = EISCONN;
break;
case ERR_ABRT:

View File

@@ -45,7 +45,7 @@
#include "OSUtils.hpp"
#include "libzt.h"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
struct tcp_pcb;
struct netif;
@@ -162,36 +162,36 @@ extern "C" err_t ip_input(LWIP_IP_INPUT_SIG);
namespace ZeroTier {
class SocketTap;
struct Connection;
class VirtualTap;
struct VirtualSocket;
class lwIP
{
public:
/*
* Set up an interface in the network stack for the SocketTap
* Set up an interface in the network stack for the VirtualTap
*/
void lwip_init_interface(SocketTap *tap, const InetAddress &ip);
void lwip_init_interface(VirtualTap *tap, const InetAddress &ip);
/*
* Main stack loop
*/
void lwip_loop(SocketTap *tap);
void lwip_loop(VirtualTap *tap);
/*
* Packets from the ZeroTier virtual wire enter the stack here
*/
void lwip_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
void lwip_rx(VirtualTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
int lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol);
int lwip_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Bind(SocketTap *tap, Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Listen(Connection *conn, int backlog);
Connection* lwip_Accept(Connection *conn);
int lwip_Read(Connection *conn, bool lwip_invoked);
int lwip_Write(Connection *conn, void *data, ssize_t len);
int lwip_Close(Connection *conn);
int lwip_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Bind(VirtualTap *tap, VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Listen(VirtualSocket *vs, int backlog);
VirtualSocket* lwip_Accept(VirtualSocket *vs);
int lwip_Read(VirtualSocket *vs, bool lwip_invoked);
int lwip_Write(VirtualSocket *vs, void *data, ssize_t len);
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);

View File

@@ -38,7 +38,7 @@
#include "libzt.h"
#include "Utilities.hpp"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
#include "picoTCP.hpp"
#include "RingBuffer.hpp"
@@ -83,7 +83,7 @@ namespace ZeroTier {
struct pico_device picodev;
bool picoTCP::pico_init_interface(SocketTap *tap, const InetAddress &ip)
bool picoTCP::pico_init_interface(VirtualTap *tap, const InetAddress &ip)
{
char ipbuf[64];
if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) {
@@ -136,7 +136,7 @@ namespace ZeroTier {
// pico_ipv6_route_add
// pico_ipv6_route_del
bool picoTCP::pico_route_add(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric)
bool picoTCP::pico_route_add(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric)
{
struct pico_ipv4_link *link = NULL;
struct pico_ip4 address;
@@ -152,7 +152,7 @@ namespace ZeroTier {
return err;
}
bool picoTCP::pico_route_del(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, int metric)
bool picoTCP::pico_route_del(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, int metric)
{
struct pico_ip4 address;
address.addr = *((uint32_t *)addr.rawIpData());
@@ -165,7 +165,7 @@ namespace ZeroTier {
return err;
}
void picoTCP::pico_loop(SocketTap *tap)
void picoTCP::pico_loop(VirtualTap *tap)
{
while(tap->_run)
{
@@ -176,13 +176,13 @@ namespace ZeroTier {
}
// from stack socket to app socket
void picoTCP::pico_cb_tcp_read(ZeroTier::SocketTap *tap, struct pico_socket *s)
void picoTCP::pico_cb_tcp_read(ZeroTier::VirtualTap *tap, struct pico_socket *s)
{
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
Mutex::Lock _l(conn->_rx_m);
VirtualSocket *vs = (VirtualSocket*)((VirtualBindingPair*)(s->priv))->vs;
Mutex::Lock _l(vs->_rx_m);
if(!conn || !tap) {
DEBUG_ERROR("invalid tap or conn");
if(!vs || !tap) {
DEBUG_ERROR("invalid tap or vs");
handle_general_failure();
return;
}
@@ -196,37 +196,32 @@ namespace ZeroTier {
do {
n = 0;
//DEBUG_INFO("RXbuf->count() = %d", conn->RXbuf->count());
int avail = ZT_TCP_RX_BUF_SZ - conn->RXbuf->count();
//DEBUG_INFO("RXbuf->count() = %d", vs->RXbuf->count());
int avail = ZT_TCP_RX_BUF_SZ - vs->RXbuf->count();
if(avail) {
r = pico_socket_recvfrom(s, conn->RXbuf->get_buf(), ZT_STACK_SOCKET_RD_MAX,
r = pico_socket_recvfrom(s, vs->RXbuf->get_buf(), ZT_STACK_SOCKET_RD_MAX,
(void *)&peer.ip4.addr, &port);
conn->tot += r;
if (r > 0)
{
conn->RXbuf->produce(r);
//DEBUG_INFO("RXbuf->count() = %d", conn->RXbuf->count());
n = tap->_phy.streamSend(conn->sock, conn->RXbuf->get_buf(), r);
vs->RXbuf->produce(r);
//DEBUG_INFO("RXbuf->count() = %d", vs->RXbuf->count());
n = tap->_phy.streamSend(vs->sock, vs->RXbuf->get_buf(), r);
if(n>0)
conn->RXbuf->consume(n);
//DEBUG_INFO("pico_recv = %d, streamSend = %d, rxsz = %d, tot = %d", r, n, conn->RXbuf->count(), conn->tot);
vs->RXbuf->consume(n);
//DEBUG_INFO("pico_recv = %d, streamSend = %d, rxsz = %d, tot = %d", r, n, vs->RXbuf->count(), vs->tot);
//DEBUG_TRANS("[ TCP RX <- STACK] :: conn = %p, len = %d", conn, n);
//DEBUG_TRANS("[ TCP RX <- STACK] :: vs = %p, len = %d", vs, n);
}
if(conn->RXbuf->count() == 0) {
tap->_phy.setNotifyWritable(conn->sock, false);
if(vs->RXbuf->count() == 0) {
tap->_phy.setNotifyWritable(vs->sock, false);
}
else {
tap->_phy.setNotifyWritable(conn->sock, true);
tap->_phy.setNotifyWritable(vs->sock, true);
}
}
else {
//tap->_phy.setNotifyWritable(conn->sock, false);
//tap->_phy.setNotifyWritable(vs->sock, false);
DEBUG_ERROR("not enough space left on I/O RX buffer for pico_socket(%p)", s);
handle_general_failure();
}
@@ -235,13 +230,13 @@ namespace ZeroTier {
}
// from stack socket to app socket
void picoTCP::pico_cb_udp_read(SocketTap *tap, struct pico_socket *s)
void picoTCP::pico_cb_udp_read(VirtualTap *tap, struct pico_socket *s)
{
/*
DEBUG_INFO();
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
Mutex::Lock _l(conn->_rx_m);
if(conn) {
VirtualSocket *vs = (VirtualSocket*)((VirtualBindingPair*)(s->priv))->vs;
Mutex::Lock _l(vs->_rx_m);
if(vs) {
uint16_t port = 0;
union {
@@ -259,15 +254,15 @@ namespace ZeroTier {
int r = pico_socket_recvfrom(s, tmpbuf, ZT_SDK_MTU, (void *)&peer.ip4.addr, &port);
//DEBUG_FLOW(" [ RXBUF <- STACK] Receiving (%d) from stack, copying to receving buffer", r);
if(conn->rxsz == ZT_UDP_RX_BUF_SZ) { // if UDP buffer full
if(vs->rxsz == ZT_UDP_RX_BUF_SZ) { // if UDP buffer full
//DEBUG_FLOW(" [ RXBUF <- STACK] UDP RX buffer full. Discarding oldest payload segment");
memmove(conn->rxbuf, conn->rxbuf + ZT_SDK_MTU, ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU);
addr_pos = conn->rxbuf + (ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU); // TODO:
memmove(vs->rxbuf, vs->rxbuf + ZT_SDK_MTU, ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU);
addr_pos = vs->rxbuf + (ZT_UDP_RX_BUF_SZ - ZT_SDK_MTU); // TODO:
sz_pos = addr_pos + sizeof(struct sockaddr_storage);
conn->rxsz -= ZT_SDK_MTU;
vs->rxsz -= ZT_SDK_MTU;
}
else {
addr_pos = conn->rxbuf + conn->rxsz; // where we'll prepend the size of the address
addr_pos = vs->rxbuf + vs->rxsz; // where we'll prepend the size of the address
sz_pos = addr_pos + sizeof(struct sockaddr_storage);
}
payload_pos = addr_pos + sizeof(struct sockaddr_storage) + sizeof(r);
@@ -276,7 +271,7 @@ namespace ZeroTier {
// Adjust buffer size
if(r) {
conn->rxsz += ZT_SDK_MTU;
vs->rxsz += ZT_SDK_MTU;
memcpy(sz_pos, &r, sizeof(r));
}
if (r < 0) {
@@ -286,38 +281,38 @@ namespace ZeroTier {
tap->_rx_buf_m.unlock();
if(r)
tap->phyOnUnixWritable(conn->sock, NULL, true);
tap->phyOnUnixWritable(vs->sock, NULL, true);
//DEBUG_EXTRA(" Copied onto rxbuf (%d) from stack socket", r);
return;
}
*/
}
void picoTCP::pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s)
void picoTCP::pico_cb_tcp_write(VirtualTap *tap, struct pico_socket *s)
{
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
Mutex::Lock _l(conn->_tx_m);
if(!conn) {
DEBUG_ERROR("invalid connection");
VirtualSocket *vs = (VirtualSocket*)((VirtualBindingPair*)(s->priv))->vs;
Mutex::Lock _l(vs->_tx_m);
if(!vs) {
DEBUG_ERROR("invalid VirtualSocket");
handle_general_failure();
return;
}
int txsz = conn->TXbuf->count();
int txsz = vs->TXbuf->count();
if(txsz <= 0)
return;
//DEBUG_INFO("TXbuf->count() = %d", conn->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(conn->picosock, conn->TXbuf->get_buf(), max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r);
if((r = pico_socket_write(vs->picosock, vs->TXbuf->get_buf(), max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", vs->picosock, r);
handle_general_failure();
return;
}
if(conn->socket_type == SOCK_STREAM) {
//DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r);
if(vs->socket_type == SOCK_STREAM) {
//DEBUG_TRANS("[ TCP TX -> STACK] :: vs = %p, len = %d", vs, r);
}
if(conn->socket_type == SOCK_DGRAM) {
//DEBUG_TRANS("[ UDP TX -> STACK] :: conn = %p, len = %d", conn, r);
if(vs->socket_type == SOCK_DGRAM) {
//DEBUG_TRANS("[ UDP TX -> STACK] :: vs = %p, len = %d", vs, r);
}
if(r == 0) {
// This is a peciliarity of the picoTCP network stack, if we receive no error code, and the size of
@@ -326,32 +321,32 @@ namespace ZeroTier {
// handle_general_failure();
}
if(r>0)
conn->TXbuf->consume(r);
vs->TXbuf->consume(r);
}
void picoTCP::pico_cb_socket_activity(uint16_t ev, struct pico_socket *s)
{
if(!(SocketTap*)((ConnectionPair*)(s->priv)))
if(!(VirtualTap*)((VirtualBindingPair*)(s->priv)))
return;
SocketTap *tap = (SocketTap*)((ConnectionPair*)(s->priv))->tap;
Connection *conn = (Connection*)((ConnectionPair*)(s->priv))->conn;
if(!tap || !conn) {
DEBUG_ERROR("invalid tap or conn");
VirtualTap *tap = (VirtualTap*)((VirtualBindingPair*)(s->priv))->tap;
VirtualSocket *vs = (VirtualSocket*)((VirtualBindingPair*)(s->priv))->vs;
if(!tap || !vs) {
DEBUG_ERROR("invalid tap or vs");
handle_general_failure();
return;
}
int err = 0;
if(!conn) {
DEBUG_ERROR("invalid connection");
if(!vs) {
DEBUG_ERROR("invalid VirtualSocket");
handle_general_failure();
return;
}
// 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
// PICO_SOCK_EV_vs - triggered when VirtualSocket is established (TCP only). This event is
// received either after a successful call to pico socket vsect to indicate that the VirtualSocket
// 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.
// may now be issued in order to accept the incoming VirtualSocket from a remote host.
if (ev & PICO_SOCK_EV_CONN) {
if(conn->state == ZT_SOCK_STATE_LISTENING)
if(vs->state == ZT_SOCK_STATE_LISTENING)
{
Mutex::Lock _l(tap->_tcpconns_m);
uint32_t peer;
@@ -362,78 +357,78 @@ namespace ZeroTier {
return;
}
// Create a new Connection and add it to the queue,
// Create a new VirtualSocket and add it to the queue,
// some time in the future a call to zts_multiplex_accept() will pick up
// this new connection, add it to the connection list and return its
// Connection->sock to the application
// this new VirtualSocket, add it to the VirtualSocket list and return its
// VirtualSocket->sock to the application
Connection *newConn = new Connection();
newConn->socket_type = SOCK_STREAM;
newConn->picosock = client_psock;
newConn->tap = tap;
newConn->picosock->priv = new ConnectionPair(tap,newConn);
tap->_Connections.push_back(newConn);
conn->_AcceptedConnections.push(newConn);
VirtualSocket *new_vs = new VirtualSocket();
new_vs->socket_type = SOCK_STREAM;
new_vs->picosock = client_psock;
new_vs->tap = tap;
new_vs->picosock->priv = new VirtualBindingPair(tap,new_vs);
tap->_VirtualSockets.push_back(new_vs);
vs->_AcceptedConnections.push(new_vs);
int value = 1;
pico_socket_setoption(newConn->picosock, PICO_TCP_NODELAY, &value);
pico_socket_setoption(new_vs->picosock, PICO_TCP_NODELAY, &value);
if(ZT_SOCK_BEHAVIOR_LINGER) {
int linger_time_ms = ZT_SOCK_BEHAVIOR_LINGER_TIME;
int t_err = 0;
if((t_err = pico_socket_setoption(newConn->picosock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0)
DEBUG_ERROR("unable to set LINGER size, err = %d, pico_err = %d, app_fd=%d, sdk_fd=%d", t_err, pico_err, conn->app_fd, conn->sdk_fd);
if((t_err = pico_socket_setoption(new_vs->picosock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0)
DEBUG_ERROR("unable to set LINGER size, err = %d, pico_err = %d, app_fd=%d, sdk_fd=%d", t_err, pico_err, vs->app_fd, vs->sdk_fd);
}
/*
linger_time_ms = 0;
if((t_err = pico_socket_getoption(newConn->picosock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0)
if((t_err = pico_socket_getoption(new_vs->picosock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0)
DEBUG_ERROR("unable to set LINGER size, err = %d, pico_err = %d", t_err, pico_err);
DEBUG_TEST("getting linger = %d", linger_time_ms);
*/
// For I/O loop participation and referencing the PhySocket's parent Connection in callbacks
newConn->sock = tap->_phy.wrapSocket(newConn->sdk_fd, newConn);
//DEBUG_ERROR("sock->fd = %d", tap->_phy.getDescriptor(newConn->sock));
// For I/O loop participation and referencing the PhySocket's parent VirtualSocket in callbacks
new_vs->sock = tap->_phy.wrapSocket(new_vs->sdk_fd, new_vs);
//DEBUG_ERROR("sock->fd = %d", tap->_phy.getDescriptor(new_vs->sock));
}
if(conn->state != ZT_SOCK_STATE_LISTENING) {
if(vs->state != ZT_SOCK_STATE_LISTENING) {
// set state so socket multiplexer logic will pick this up
conn->state = ZT_SOCK_STATE_UNHANDLED_CONNECTED;
vs->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, app_fd=%d, sdk_fd=%d", s, conn, conn->app_fd, conn->sdk_fd);
conn->closure_ts = std::time(nullptr);
//DEBUG_EXTRA("PICO_SOCK_EV_FIN (socket closed), picosock=%p, vs=%p, app_fd=%d, sdk_fd=%d", s, vs, vs->app_fd, vs->sdk_fd);
vs->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;
vs->state = PICO_ERR_ECONNRESET;
}
DEBUG_ERROR("PICO_SOCK_EV_ERR, err=%s, picosock=%p, app_fd=%d, sdk_fd=%d", beautify_pico_error(pico_err), s, conn->app_fd, conn->sdk_fd);
DEBUG_ERROR("PICO_SOCK_EV_ERR, err=%s, picosock=%p, app_fd=%d, sdk_fd=%d", beautify_pico_error(pico_err), s, vs->app_fd, vs->sdk_fd);
}
// 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
// indicates that the oher endpont has closed the VirtualSocket, 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,
// keep the VirtualSocket 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, app_fd=%d, sdk_fd=%d", err, s, conn, conn->app_fd, conn->sdk_fd);
conn->closure_ts = std::time(nullptr);
//DEBUG_INFO("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;
}
// 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)
if(vs->socket_type==SOCK_STREAM)
pico_cb_tcp_read(tap, s);
if(conn->socket_type==SOCK_DGRAM)
if(vs->socket_type==SOCK_DGRAM)
pico_cb_udp_read(tap, s);
}
// PICO_SOCK_EV_WR - triggered when ready to write to the socket. Issuing a write/send call
@@ -446,7 +441,7 @@ namespace ZeroTier {
int pico_eth_send(struct pico_device *dev, void *buf, int len)
{
//DEBUG_INFO("len = %d", len);
SocketTap *tap = (SocketTap*)(dev->tap);
VirtualTap *tap = (VirtualTap*)(dev->tap);
if(!tap) {
DEBUG_ERROR("invalid dev->tap");
handle_general_failure();
@@ -464,7 +459,7 @@ namespace ZeroTier {
}
// receive frames from zerotier virtual wire and copy them to a guarded buffer awaiting placement into network stack
void picoTCP::pico_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,
void picoTCP::pico_rx(VirtualTap *tap, const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
DEBUG_INFO("len = %d", len);
@@ -502,14 +497,14 @@ namespace ZeroTier {
// feed frames on the guarded RX buffer (from zerotier virtual wire) into the network stack
int pico_eth_poll(struct pico_device *dev, int loop_score)
{
SocketTap *tap = (SocketTap*)(dev->tap);
VirtualTap *tap = (VirtualTap*)(dev->tap);
if(!tap) {
DEBUG_ERROR("invalid dev->tap");
handle_general_failure();
return ZT_ERR_GENERAL_FAILURE;
}
// FIXME: The copy logic and/or buffer structure should be reworked for better performance after the BETA
// SocketTap *tap = (SocketTap*)netif->state;
// VirtualTap *tap = (VirtualTap*)netif->state;
Mutex::Lock _l(tap->_pico_frame_rxbuf_m);
unsigned char frame[ZT_SDK_MTU];
int len;
@@ -588,15 +583,15 @@ namespace ZeroTier {
return err;
}
int picoTCP::pico_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen)
int picoTCP::pico_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
if(!conn || !conn->picosock) {
DEBUG_ERROR("invalid conn or conn->picosock");
if(!vs || !vs->picosock) {
DEBUG_ERROR("invalid vs or vs->picosock");
handle_general_failure();
return ZT_ERR_GENERAL_FAILURE;
}
int err = 0;
if(conn->socket_family == AF_INET) {
if(vs->socket_family == AF_INET) {
struct pico_ip4 zaddr;
memset(&zaddr, 0, sizeof (struct pico_ip4));
struct sockaddr_in *in4 = (struct sockaddr_in*)addr;
@@ -605,20 +600,20 @@ namespace ZeroTier {
uint32_t ipval = 0;
pico_string_to_ipv4(ipv4_str, &ipval);
zaddr.addr = ipval;
err = pico_socket_connect(conn->picosock, &zaddr, in4->sin_port);
err = pico_socket_connect(vs->picosock, &zaddr, in4->sin_port);
}
if(conn->socket_family == AF_INET6) {
if(vs->socket_family == AF_INET6) {
struct pico_ip6 zaddr;
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
char ipv6_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
pico_string_to_ipv6(ipv6_str, zaddr.addr);
err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port);
err = pico_socket_connect(vs->picosock, &zaddr, in6->sin6_port);
}
if(err) {
DEBUG_ERROR("err=%d, %s", err, beautify_pico_error(pico_err));
}
memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage));
memcpy(&(vs->peer_addr), &addr, sizeof(struct sockaddr_storage));
if(err == PICO_ERR_EPROTONOSUPPORT)
DEBUG_ERROR("PICO_ERR_EPROTONOSUPPORT");
@@ -629,16 +624,16 @@ namespace ZeroTier {
return err;
}
int picoTCP::pico_Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen)
int picoTCP::pico_Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
//DEBUG_INFO();
if(!conn || !conn->picosock) {
DEBUG_ERROR("invalid conn or conn->picosock");
if(!vs || !vs->picosock) {
DEBUG_ERROR("invalid vs or vs->picosock");
handle_general_failure();
return ZT_ERR_GENERAL_FAILURE;
}
int err = 0;
if(conn->socket_family == AF_INET) {
if(vs->socket_family == AF_INET) {
struct pico_ip4 zaddr;
uint32_t tempaddr;
memset(&zaddr, 0, sizeof (struct pico_ip4));
@@ -648,9 +643,9 @@ namespace ZeroTier {
pico_string_to_ipv4(ipv4_str, &tempaddr);
zaddr.addr = tempaddr;
//DEBUG_EXTRA("addr=%s:%d", ipv4_str, Utils::ntoh(in4->sin_port));
err = pico_socket_bind(conn->picosock, &zaddr, (uint16_t *)&(in4->sin_port));
err = pico_socket_bind(vs->picosock, &zaddr, (uint16_t *)&(in4->sin_port));
}
if(conn->socket_family == AF_INET6) {
if(vs->socket_family == AF_INET6) {
struct pico_ip6 pip6;
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
char ipv6_str[INET6_ADDRSTRLEN];
@@ -658,12 +653,12 @@ namespace ZeroTier {
// TODO: This isn't proper
pico_string_to_ipv6("::", pip6.addr);
//DEBUG_EXTRA("addr=%s:%d", ipv6_str, Utils::ntoh(in6->sin6_port));
err = pico_socket_bind(conn->picosock, &pip6, (uint16_t *)&(in6->sin6_port));
err = pico_socket_bind(vs->picosock, &pip6, (uint16_t *)&(in6->sin6_port));
}
if(err < 0) {
if(pico_err < 0)
DEBUG_ERROR("pico_err = %d", pico_err);
DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), err);
DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (vs->picosock), err);
if(err == PICO_ERR_EINVAL) {
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
errno = EINVAL;
@@ -683,16 +678,16 @@ namespace ZeroTier {
return err;
}
int picoTCP::pico_Listen(Connection *conn, int backlog)
int picoTCP::pico_Listen(VirtualSocket *vs, int backlog)
{
//DEBUG_INFO();
if(!conn || !conn->picosock) {
DEBUG_ERROR("invalid conn or conn->picosock");
if(!vs || !vs->picosock) {
DEBUG_ERROR("invalid vs or vs->picosock");
handle_general_failure();
return ZT_ERR_GENERAL_FAILURE;
}
int err = 0;
if((err = pico_socket_listen(conn->picosock, backlog)) < 0)
if((err = pico_socket_listen(vs->picosock, backlog)) < 0)
{
if(err == PICO_ERR_EINVAL) {
DEBUG_ERROR("PICO_ERR_EINVAL");
@@ -705,33 +700,33 @@ namespace ZeroTier {
return -1;
}
}
conn->state = ZT_SOCK_STATE_LISTENING;
vs->state = ZT_SOCK_STATE_LISTENING;
return ZT_ERR_OK;
}
Connection* picoTCP::pico_Accept(Connection *conn)
VirtualSocket* picoTCP::pico_Accept(VirtualSocket *vs)
{
if(!conn) {
DEBUG_ERROR("invalid conn");
if(!vs) {
DEBUG_ERROR("invalid vs");
handle_general_failure();
return NULL;
}
// Retreive first of queued Connections from parent connection
Connection *new_conn = NULL;
if(conn->_AcceptedConnections.size()) {
new_conn = conn->_AcceptedConnections.front();
conn->_AcceptedConnections.pop();
// Retreive first of queued VirtualSockets from parent VirtualSocket
VirtualSocket *new_vs = NULL;
if(vs->_AcceptedConnections.size()) {
new_vs = vs->_AcceptedConnections.front();
vs->_AcceptedConnections.pop();
}
return new_conn;
return new_vs;
}
int picoTCP::pico_Read(SocketTap *tap, PhySocket *sock, Connection* conn, bool stack_invoked)
int picoTCP::pico_Read(VirtualTap *tap, PhySocket *sock, VirtualSocket* vs, bool stack_invoked)
{
DEBUG_INFO();
//exit(0);
/*
if(!conn || !tap || !conn) {
DEBUG_ERROR("invalid tap, sock, or conn");
if(!vs || !tap || !vs) {
DEBUG_ERROR("invalid tap, sock, or vs");
handle_general_failure();
return;
}
@@ -743,14 +738,14 @@ namespace ZeroTier {
}
int tot = 0, n = -1, write_attempts = 0;
if(conn && conn->rxsz) {
//DEBUG_INFO("conn = %p", conn);
if(vs && vs->rxsz) {
//DEBUG_INFO("vs = %p", vs);
//
if(conn->socket_type==SOCK_DGRAM) {
if(vs->socket_type==SOCK_DGRAM) {
// Try to write ZT_SDK_MTU-sized chunk to app socket
while(tot < ZT_SDK_MTU) {
write_attempts++;
n = tap->_phy.streamSend(conn->sock, (conn->rxbuf)+tot, ZT_SDK_MTU);
n = tap->_phy.streamSend(vs->sock, (vs->rxbuf)+tot, ZT_SDK_MTU);
tot += n;
//DEBUG_FLOW("[ ZTSOCK <- RXBUF] wrote = %d, errno=%d", n, errno);
// If socket is unavailable, attempt to write N times before giving up
@@ -762,33 +757,33 @@ namespace ZeroTier {
}
}
int payload_sz, addr_sz_offset = sizeof(struct sockaddr_storage);
memcpy(&payload_sz, conn->rxbuf + addr_sz_offset, sizeof(int));
memcpy(&payload_sz, vs->rxbuf + addr_sz_offset, sizeof(int));
struct sockaddr_storage addr;
memcpy(&addr, conn->rxbuf, addr_sz_offset);
memcpy(&addr, vs->rxbuf, addr_sz_offset);
// adjust buffer
if(conn->rxsz-n > 0) { // If more remains on buffer
memcpy(conn->rxbuf, conn->rxbuf+ZT_SDK_MTU, conn->rxsz - ZT_SDK_MTU);
if(vs->rxsz-n > 0) { // If more remains on buffer
memcpy(vs->rxbuf, vs->rxbuf+ZT_SDK_MTU, vs->rxsz - ZT_SDK_MTU);
}
conn->rxsz -= ZT_SDK_MTU;
vs->rxsz -= ZT_SDK_MTU;
}
//
if(conn->socket_type==SOCK_STREAM) {
//DEBUG_INFO("writing to conn->sock = %p, conn->sdk_fd=%d, conn->app_fd=%d", conn->sock, conn->sdk_fd, conn->app_fd);
n = tap->_phy.streamSend(conn->sock, conn->rxbuf, conn->rxsz);
if(vs->socket_type==SOCK_STREAM) {
//DEBUG_INFO("writing to vs->sock = %p, vs->sdk_fd=%d, vs->app_fd=%d", vs->sock, vs->sdk_fd, vs->app_fd);
n = tap->_phy.streamSend(vs->sock, vs->rxbuf, vs->rxsz);
// FIXME: Revisit the idea of writing directly to the app socketpair instead of using Phy I/O
// n = write(conn->sdk_fd, conn->rxbuf, conn->rxsz);
if(conn->rxsz-n > 0) // If more remains on buffer
memcpy(conn->rxbuf, conn->rxbuf+n, conn->rxsz - n);
conn->rxsz -= n;
// n = write(vs->sdk_fd, vs->rxbuf, vs->rxsz);
if(vs->rxsz-n > 0) // If more remains on buffer
memcpy(vs->rxbuf, vs->rxbuf+n, vs->rxsz - n);
vs->rxsz -= n;
}
// Notify ZT I/O loop that it has new buffer contents
if(n) {
if(conn->socket_type==SOCK_STREAM) {
if(vs->socket_type==SOCK_STREAM) {
//#if DEBUG_LEVEL >= MSG_TRANSFER
// DEBUG_TRANS("[ TCP RX <- STACK] :: conn = %p, len = %d", conn, n);
// DEBUG_TRANS("[ TCP RX <- STACK] :: vs = %p, len = %d", vs, n);
//#endif
}
if(conn->rxsz == 0) {
if(vs->rxsz == 0) {
tap->_phy.setNotifyWritable(sock, false);
}
else {
@@ -803,91 +798,91 @@ namespace ZeroTier {
tap->_tcpconns_m.unlock();
tap->_rx_buf_m.unlock();
}
// DEBUG_FLOW("[ ZTSOCK <- RXBUF] Emitted (%d) from RXBUF(%d) to socket", tot, conn->rxsz);
// DEBUG_FLOW("[ ZTSOCK <- RXBUF] Emitted (%d) from RXBUF(%d) to socket", tot, vs->rxsz);
*/
return 0;
}
int picoTCP::pico_Write(Connection *conn, void *data, ssize_t len)
int picoTCP::pico_Write(VirtualSocket *vs, void *data, ssize_t len)
{
int err = 0;
// TODO: Add RingBuffer overflow checks
DEBUG_INFO("conn=%p, len=%d", conn, len);
Mutex::Lock _l(conn->_tx_m);
DEBUG_INFO("vs=%p, len=%d", vs, len);
Mutex::Lock _l(vs->_tx_m);
if(len <= 0) {
DEBUG_ERROR("invalid write length (len=%d)", len);
handle_general_failure();
return -1;
}
if(conn->picosock->state & PICO_SOCKET_STATE_CLOSED){
if(vs->picosock->state & PICO_SOCKET_STATE_CLOSED){
DEBUG_ERROR("socket is CLOSED, this write() will fail");
return -1;
}
if(!conn) {
DEBUG_ERROR("invalid connection (len=%d)", len);
if(!vs) {
DEBUG_ERROR("invalid VirtualSocket (len=%d)", len);
handle_general_failure();
return -1;
}
if(conn->socket_type == SOCK_DGRAM)
if(vs->socket_type == SOCK_DGRAM)
{
int r;
if((r = pico_socket_write(conn->picosock, data, len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r);
if((r = pico_socket_write(vs->picosock, data, len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", vs->picosock, r);
err = -1;
}
else {
err = r; // successful write
}
DEBUG_TRANS("[ UDP TX -> STACK] :: conn=%p, len=%d, err=%s", conn, r, beautify_pico_error(pico_err));
DEBUG_TRANS("[ UDP TX -> STACK] :: vs=%p, len=%d, err=%s", vs, r, beautify_pico_error(pico_err));
}
if(conn->socket_type == SOCK_STREAM)
if(vs->socket_type == SOCK_STREAM)
{
int original_txsz = conn->TXbuf->count();
int original_txsz = vs->TXbuf->count();
if(original_txsz + len >= ZT_TCP_TX_BUF_SZ) {
DEBUG_ERROR("txsz=%d, len=%d", original_txsz, len);
DEBUG_ERROR("TX buffer is too small, try increasing ZT_TCP_TX_BUF_SZ in libzt.h");
exit(0);
}
int buf_w = conn->TXbuf->write((const unsigned char*)data, len);
int buf_w = vs->TXbuf->write((const unsigned char*)data, len);
if (buf_w != len) {
// because we checked ZT_TCP_TX_BUF_SZ above, this should not happen
DEBUG_ERROR("TX wrote only %d but expected to write %d", buf_w, len);
exit(0);
}
//DEBUG_INFO("TXbuf->count() = %d", conn->TXbuf->count());
int txsz = conn->TXbuf->count();
//DEBUG_INFO("TXbuf->count() = %d", vs->TXbuf->count());
int txsz = vs->TXbuf->count();
int r, max_write_len = std::min(std::min(txsz, ZT_SDK_MTU),ZT_STACK_SOCKET_WR_MAX);
//int buf_r = conn->TXbuf->read(conn->tmptxbuf, max_write_len);
//int buf_r = vs->TXbuf->read(vs->tmptxbuf, max_write_len);
if((r = pico_socket_write(conn->picosock, conn->TXbuf->get_buf(), max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r);
if((r = pico_socket_write(vs->picosock, vs->TXbuf->get_buf(), max_write_len)) < 0) {
DEBUG_ERROR("unable to write to picosock=%p, r=%d", vs->picosock, r);
err = -1;
}
else {
err = r; // successful write
}
if(r>0){
conn->TXbuf->consume(r);
vs->TXbuf->consume(r);
}
DEBUG_TRANS("[ TCP TX -> STACK] :: conn=%p, len=%d", conn, r);
DEBUG_TRANS("[ TCP TX -> STACK] :: vs=%p, len=%d", vs, r);
}
return err;
}
int picoTCP::pico_Close(Connection *conn)
int picoTCP::pico_Close(VirtualSocket *vs)
{
DEBUG_INFO("conn=%p, picosock=%p, fd=%d", conn, conn->picosock, conn->app_fd);
if(!conn || !conn->picosock)
DEBUG_INFO("vs=%p, picosock=%p, fd=%d", vs, vs->picosock, vs->app_fd);
if(!vs || !vs->picosock)
return ZT_ERR_GENERAL_FAILURE;
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
Mutex::Lock _l(vs->tap->_tcpconns_m);
if(vs->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) {
if((err = pico_socket_close(vs->picosock)) < 0) {
errno = pico_err;
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock));
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(vs->picosock));
}
return err;
}

View File

@@ -37,7 +37,7 @@
#include "pico_device.h"
#include "pico_ipv6.h"
#include "SocketTap.hpp"
#include "VirtualTap.hpp"
/****************************************************************************/
/* PicoTCP API Signatures (See libzt.h for the API an app should use) */
@@ -84,47 +84,47 @@ namespace ZeroTier
*/
int pico_eth_poll(struct pico_device *dev, int loop_score);
class SocketTap;
struct Connection;
class VirtualTap;
struct VirtualSocket;
class picoTCP
{
public:
/*
* Set up an interface in the network stack for the SocketTap
* Set up an interface in the network stack for the VirtualTap
*/
bool pico_init_interface(ZeroTier::SocketTap *tap, const ZeroTier::InetAddress &ip);
bool pico_init_interface(ZeroTier::VirtualTap *tap, const ZeroTier::InetAddress &ip);
/*
* Adds a route to the picoTCP device
*/
bool pico_route_add(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric);
bool pico_route_add(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric);
/*
* Deletes a route from the picoTCP device
*/
bool pico_route_del(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, int metric);
bool pico_route_del(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, int metric);
/*
* Main stack loop
*/
void pico_loop(SocketTap *tap);
void pico_loop(VirtualTap *tap);
/*
* Read bytes from the stack to the RX buffer (prepare to be read by app)
*/
static void pico_cb_tcp_read(SocketTap *tap, struct pico_socket *s);
static void pico_cb_tcp_read(VirtualTap *tap, struct pico_socket *s);
/*
* Read bytes from the stack to the RX buffer (prepare to be read by app)
*/
static void pico_cb_udp_read(SocketTap *tap, struct pico_socket *s);
static void pico_cb_udp_read(VirtualTap *tap, struct pico_socket *s);
/*
* Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
*/
static void pico_cb_tcp_write(SocketTap *tap, struct pico_socket *s);
static void pico_cb_tcp_write(VirtualTap *tap, struct pico_socket *s);
/*
* Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
@@ -134,47 +134,47 @@ namespace ZeroTier
/*
* Packets from the ZeroTier virtual wire enter the stack here
*/
void pico_rx(SocketTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len);
void pico_rx(VirtualTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len);
/*
* Creates a stack-specific "socket" or "connection object"
* Creates a stack-specific "socket" or "VirtualSocket object"
*/
int pico_Socket(struct pico_socket **p, int socket_family, int socket_type, int protocol);
/*
* Connect to remote host via userspace network stack interface - Called from SocketTap
* Connect to remote host via userspace network stack interface - Called from VirtualTap
*/
int pico_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int pico_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/*
* Bind to a userspace network stack interface - Called from SocketTap
* Bind to a userspace network stack interface - Called from VirtualTap
*/
int pico_Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen);
int pico_Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/*
* Listen for incoming connections - Called from SocketTap
* Listen for incoming VirtualSockets - Called from VirtualTap
*/
int pico_Listen(Connection *conn, int backlog);
int pico_Listen(VirtualSocket *vs, int backlog);
/*
* Accept an incoming connection - Called from SocketTap
* Accept an incoming VirtualSocket - Called from VirtualTap
*/
Connection* pico_Accept(Connection *conn);
VirtualSocket* pico_Accept(VirtualSocket *vs);
/*
* Read from RX buffer to application - Called from SocketTap
* Read from RX buffer to application - Called from VirtualTap
*/
int pico_Read(SocketTap *tap, ZeroTier::PhySocket *sock,Connection *conn,bool stack_invoked);
int pico_Read(VirtualTap *tap, ZeroTier::PhySocket *sock,VirtualSocket *vs,bool stack_invoked);
/*
* Write to userspace network stack - Called from SocketTap
* Write to userspace network stack - Called from VirtualTap
*/
int pico_Write(Connection *conn, void *data, ssize_t len);
int pico_Write(VirtualSocket *vs, void *data, ssize_t len);
/*
* Close a Connection - Called from SocketTap
* Close a VirtualSocket - Called from VirtualTap
*/
int pico_Close(Connection *conn);
int pico_Close(VirtualSocket *vs);
/*
* Converts picoTCP error codes to pretty string

View File

@@ -188,7 +188,7 @@ int main(int argc , char *argv[])
fprintf(stderr, "Send failed\n");
}
// dismantle all zt virtual taps (SocketTaps)
// dismantle all zt virtual taps
zts_stop();
#endif
return 0;

View File

@@ -220,31 +220,31 @@ namespace ZeroTier {
void ZTProxy::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
// Not used, connections are handled via user space network stack and VirtualTap
DEBUG_INFO("phyOnDatagram");
exit(0);
}
void ZTProxy::phyOnTcpWritable(PhySocket *sock,void **uptr)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
// Not used, connections are handled via user space network stack and VirtualTap
DEBUG_INFO("phyOnTcpWritable");
exit(0);
}
void ZTProxy::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
// Not used, connections are handled via user space network stack and VirtualTap
DEBUG_INFO("phyOnFileDescriptorActivity, sock=%p", sock);
exit(0);
}
void ZTProxy::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
// Not used, connections are handled via user space network stack and VirtualTap
DEBUG_INFO("phyOnTcpConnect, sock=%p", sock);
exit(0);
}
void ZTProxy::phyOnUnixClose(PhySocket *sock,void **uptr)
{
// Not used, connections are handled via user space network stack and SocketTap subsystem
// Not used, connections are handled via user space network stack and VirtualTap
DEBUG_INFO("phyOnUnixClose, sock=%p", sock);
exit(0);
}

2
zto

Submodule zto updated: ee1dc16e8f...59b7cbb591