Stubbed out some of the more obscure socket options for both drivers

This commit is contained in:
Joseph Henry
2017-09-15 19:45:49 -07:00
parent 87af06a834
commit 11dcc1e959
7 changed files with 1793 additions and 164 deletions

View File

@@ -84,6 +84,42 @@ struct zts_ifreq {
#endif #endif
// Provide missing optnames for setsockopt() implementations
#ifdef _WIN32
#ifdef _WIN64
#else
#endif
#elif __APPLE__
#define IP_BIND_ADDRESS_NO_PORT 201
#define IP_FREEBIND 202
#define IP_MTU 203
#define IP_MTU_DISCOVER 204
#define IP_MULTICAST_ALL 205
#define IP_NODEFRAG 206
#define IP_RECVORIGDSTADDR 207
#define IP_ROUTER_ALERT 208
#define IP_TRANSPARENT 209
#define TCP_INFO 210
#define SO_STYLE 100
#define TCP_CORK 101
#define TCP_DEFER_ACCEPT 102
#define TCP_KEEPIDLE 103
#define TCP_LINGER2 104
#define TCP_QUICKACK 105
#define TCP_SYNCNT 106
#define TCP_WINDOW_CLAMP 107
#define UDP_CORK 108
#elif __linux__
#define SO_STYLE 100
#define UDP_CORK 101
#define IP_BIND_ADDRESS_NO_PORT 201
#define IP_NODEFRAG 206
#elif __unix__
#elif defined(_POSIX_VERSION)
#else
# error "Unknown platform"
#endif
/****************************************************************************/ /****************************************************************************/
/* Legend */ /* Legend */
/****************************************************************************/ /****************************************************************************/
@@ -574,12 +610,12 @@ bool can_provision_new_socket(int socket_type);
* haven't passed that limit. Someday if multiple stacks are used simultaneously * haven't passed that limit. Someday if multiple stacks are used simultaneously
* the logic for this function should change accordingly. * the logic for this function should change accordingly.
*/ */
int zts_nsockets(); int zts_num_active_virt_sockets();
/* /*
* Returns maximum number of sockets allowed by network stack * Returns maximum number of sockets allowed by network stack
*/ */
int zts_maxsockets(); int zts_maxsockets(int socket_type);
int pico_ntimers(); int pico_ntimers();
@@ -596,31 +632,31 @@ ZeroTier::VirtualTap *getAnyTap();
/* /*
* Returns a pointer to a VirtualSocket for a given fd * Returns a pointer to a VirtualSocket for a given fd
*/ */
ZeroTier::VirtualSocket *get_virtual_socket(int fd); ZeroTier::VirtualSocket *get_virt_socket(int fd);
/* /*
* Removes a VirtualSocket * Removes a VirtualSocket
*/ */
int del_virtual_socket(int fd); int del_virt_socket(int fd);
/* /*
* Adds a virtualSocket * Adds a virtualSocket
*/ */
int add_unassigned_virtual_socket(int fd, ZeroTier::VirtualSocket *vs); int add_unassigned_virt_socket(int fd, ZeroTier::VirtualSocket *vs);
/* /*
* Removes unassigned VirtualSocket * Removes unassigned VirtualSocket
*/ */
int del_unassigned_virtual_socket(int fd); int del_unassigned_virt_socket(int fd);
/* /*
* Adds an assigned VirtualSocket * Adds an assigned VirtualSocket
*/ */
int add_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd); int add_assigned_virt_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd);
/* /*
* Removes an assigned VirtualSocket * Removes an assigned VirtualSocket
*/ */
int del_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd); int del_assigned_virt_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd);
/* /*
* Gets a pair of associated virtual objects (VirtualSocket bound to a VirtualTap) * Gets a pair of associated virtual objects (VirtualSocket bound to a VirtualTap)
@@ -628,9 +664,9 @@ int del_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSock
std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *get_assigned_virtual_pair(int fd); std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *get_assigned_virtual_pair(int fd);
/* /*
* Destroys all virtual tap devices * Disable all virtual tap devices
*/ */
void dismantleTaps(); void disableTaps();
/* /*
* Get device ID (from file) * Get device ID (from file)

View File

@@ -61,8 +61,6 @@ class VirtualTap;
extern std::vector<void*> vtaps; extern std::vector<void*> vtaps;
// static bool picodev_initialized;
namespace ZeroTier { namespace ZeroTier {
int VirtualTap::devno = 0; int VirtualTap::devno = 0;
@@ -135,12 +133,18 @@ namespace ZeroTier {
if (picostack) { if (picostack) {
picostack->pico_register_address(this, ip); picostack->pico_register_address(this, ip);
return true; return true;
} else {
handle_general_failure();
return false;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
lwipstack->lwip_init_interface(this, ip); lwipstack->lwip_init_interface(this, ip);
return true; return true;
} else {
handle_general_failure();
return false;
} }
#endif #endif
return false; return false;
@@ -148,12 +152,13 @@ namespace ZeroTier {
bool VirtualTap::addIp(const InetAddress &ip) bool VirtualTap::addIp(const InetAddress &ip)
{ {
int err = false;
#if defined(NO_STACK) #if defined(NO_STACK)
char ipbuf[INET6_ADDRSTRLEN]; char ipbuf[INET6_ADDRSTRLEN];
DEBUG_INFO("addIp (%s)", ip.toString(ipbuf)); DEBUG_INFO("addIp (%s)", ip.toString(ipbuf));
_ips.push_back(ip); _ips.push_back(ip);
std::sort(_ips.begin(),_ips.end()); std::sort(_ips.begin(),_ips.end());
return true; err = true;
#endif #endif
#if defined(STACK_PICO) || defined(STACK_LWIP) #if defined(STACK_PICO) || defined(STACK_LWIP)
char ipbuf[INET6_ADDRSTRLEN]; char ipbuf[INET6_ADDRSTRLEN];
@@ -165,16 +170,18 @@ namespace ZeroTier {
} }
return true; return true;
} }
return false; err = false;
#endif #endif
return err;
} }
bool VirtualTap::removeIp(const InetAddress &ip) bool VirtualTap::removeIp(const InetAddress &ip)
{ {
Mutex::Lock _l(_ips_m); Mutex::Lock _l(_ips_m);
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip)); std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (i == _ips.end()) if (i == _ips.end()) {
return false; return false;
}
_ips.erase(i); _ips.erase(i);
if (ip.isV4()) { if (ip.isV4()) {
// FIXME: De-register from network stacks // FIXME: De-register from network stacks
@@ -197,11 +204,15 @@ namespace ZeroTier {
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
picostack->pico_eth_rx(this,from,to,etherType,data,len); picostack->pico_eth_rx(this,from,to,etherType,data,len);
} else {
handle_general_failure();
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
lwipstack->lwip_eth_rx(this,from,to,etherType,data,len); lwipstack->lwip_eth_rx(this,from,to,etherType,data,len);
} else {
handle_general_failure();
} }
#endif #endif
} }
@@ -257,9 +268,7 @@ namespace ZeroTier {
void VirtualTap::setMtu(unsigned int mtu) void VirtualTap::setMtu(unsigned int mtu)
{ {
if (_mtu != mtu) { _mtu = mtu;
_mtu = mtu;
}
} }
void VirtualTap::threadMain() void VirtualTap::threadMain()
@@ -275,6 +284,8 @@ namespace ZeroTier {
//addIp(localhost); // Add a single link to localhost to the picoTCP device (TODO: should be placed elsewhere) //addIp(localhost); // Add a single link to localhost to the picoTCP device (TODO: should be placed elsewhere)
picostack->pico_loop(this); picostack->pico_loop(this);
} }
} else {
handle_general_failure();
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
@@ -283,33 +294,37 @@ namespace ZeroTier {
#endif #endif
} }
void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr) void VirtualTap::phyOnUnixClose(PhySocket *sock, void **uptr)
{ {
if (sock) { if (sock) {
VirtualSocket *vs = (VirtualSocket*)uptr; VirtualSocket *vs = (VirtualSocket*)uptr;
if (vs) { if (vs) {
Close(vs); Close(vs);
} }
} else {
handle_general_failure();
} }
} }
void VirtualTap::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));
VirtualSocket *vs = (VirtualSocket*)*uptr; VirtualSocket *vs = (VirtualSocket*)*uptr;
if (vs == NULL) { if (vs == NULL) {
handle_general_failure();
return; return;
} }
if (len > 0) { if (len > 0) {
Write(vs, data, len); Write(vs, data, len);
} }
return;
} }
void VirtualTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked) void VirtualTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked)
{ {
if (sock) if (sock) {
Read(sock,uptr,stack_invoked); Read(sock,uptr,stack_invoked);
} else {
handle_general_failure();
}
} }
// Adds a route to the virtual tap // Adds a route to the virtual tap
@@ -321,11 +336,18 @@ namespace ZeroTier {
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
return picostack->pico_route_add(this, addr, nm, gw, 0); return picostack->pico_route_add(this, addr, nm, gw, 0);
} else {
handle_general_failure();
return false;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
// TODO
return true; return true;
} else {
handle_general_failure();
return false;
} }
#endif #endif
return false; return false;
@@ -340,11 +362,18 @@ namespace ZeroTier {
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
return picostack->pico_route_del(this, addr, nm, 0); return picostack->pico_route_del(this, addr, nm, 0);
} else {
handle_general_failure();
return false;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
// TODO
return true; return true;
} else {
handle_general_failure();
return false;
} }
#endif #endif
return false; return false;
@@ -362,7 +391,6 @@ namespace ZeroTier {
for(int i=0; i<_VirtualSockets.size(); i++) { for(int i=0; i<_VirtualSockets.size(); i++) {
if (vs == _VirtualSockets[i]) { if (vs == _VirtualSockets[i]) {
_VirtualSockets.erase(_VirtualSockets.begin() + i); _VirtualSockets.erase(_VirtualSockets.begin() + i);
//DEBUG_EXTRA("Removed vs=%p from vt=%p", vs, this);
break; break;
} }
} }
@@ -375,22 +403,46 @@ namespace ZeroTier {
int VirtualTap::add_DNS_Nameserver(struct sockaddr *addr) int VirtualTap::add_DNS_Nameserver(struct sockaddr *addr)
{ {
int err = -1;
#if defined(STACK_PICO) #if defined(STACK_PICO)
return picostack->pico_add_dns_nameserver(addr); if (picostack) {
err = picostack->pico_add_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
return lwipstack->lwip_add_dns_nameserver(addr); if (lwipstack) {
err = lwipstack->lwip_add_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif #endif
return err;
} }
int VirtualTap::del_DNS_Nameserver(struct sockaddr *addr) int VirtualTap::del_DNS_Nameserver(struct sockaddr *addr)
{ {
int err = -1;
#if defined(STACK_PICO) #if defined(STACK_PICO)
return picostack->pico_del_dns_nameserver(addr); if (picostack) {
err = picostack->pico_del_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
return lwipstack->lwip_del_dns_nameserver(addr); if (lwipstack) {
err = lwipstack->lwip_del_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif #endif
return err;
} }
/****************************************************************************/ /****************************************************************************/
@@ -398,26 +450,35 @@ namespace ZeroTier {
/****************************************************************************/ /****************************************************************************/
// Connect // Connect
int VirtualTap::Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen) { int VirtualTap::Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
int err = -1;
#if defined(NO_STACK) #if defined(NO_STACK)
return -1; return err;
#endif #endif
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Connect(vs, addr, addrlen); err = picostack->pico_Connect(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
return lwipstack->lwip_Connect(vs, addr, addrlen); err = lwipstack->lwip_Connect(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return -1; return err;
} }
// Bind VirtualSocket to a network stack's interface // Bind VirtualSocket to a network stack's interface
int VirtualTap::Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen) { int VirtualTap::Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
{
#if defined(NO_STACK) #if defined(NO_STACK)
return -1; return -1;
#endif #endif
@@ -425,85 +486,111 @@ namespace ZeroTier {
if (picostack) { if (picostack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Bind(vs, addr, addrlen); return picostack->pico_Bind(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Bind(this, vs, addr, addrlen); return lwipstack->lwip_Bind(this, vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return -1; return -1;
} }
// Listen for an incoming VirtualSocket // Listen for an incoming VirtualSocket
int VirtualTap::Listen(VirtualSocket *vs, int backlog) { int VirtualTap::Listen(VirtualSocket *vs, int backlog)
{
int err = -1;
#if defined(NO_STACK) #if defined(NO_STACK)
return -1; return err;
#endif #endif
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Listen(vs, backlog); return picostack->pico_Listen(vs, backlog);
} } else {
else { handle_general_failure();
return ZT_ERR_GENERAL_FAILURE; return err;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Listen(vs, backlog); err = lwipstack->lwip_Listen(vs, backlog);
} } else {
else { handle_general_failure();
return ZT_ERR_GENERAL_FAILURE; return err;
} }
#endif #endif
return err;
} }
// Accept a VirtualSocket // Accept a VirtualSocket
VirtualSocket* VirtualTap::Accept(VirtualSocket *vs) { VirtualSocket* VirtualTap::Accept(VirtualSocket *vs)
{
VirtualSocket *new_vs = NULL;
#if defined(NO_STACK) #if defined(NO_STACK)
return NULL; new_vs = NULL;
#endif #endif
#if defined(STACK_PICO) #if defined(STACK_PICO)
// TODO: separation of church and state // TODO: separation of church and state
if (picostack) { if (picostack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Accept(vs); new_vs = picostack->pico_Accept(vs);
} } else {
else { handle_general_failure();
return NULL; return NULL;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
Mutex::Lock _l(_tcpconns_m); Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Accept(vs); new_vs = lwipstack->lwip_Accept(vs);
} } else {
else { handle_general_failure();
return NULL; return NULL;
} }
#endif #endif
return new_vs;
} }
// Read from stack/buffers into the app's socket // Read from stack/buffers into the app's socket
int VirtualTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) { int VirtualTap::Read(PhySocket *sock,void **uptr,bool stack_invoked)
{
int err = -1;
#if defined(NO_STACK)
#endif
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
return picostack->pico_Read(this, sock, (VirtualSocket*)uptr, stack_invoked); err = picostack->pico_Read(this, sock, (VirtualSocket*)uptr, stack_invoked);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
return lwipstack->lwip_Read((VirtualSocket*)*(_phy.getuptr(sock)), stack_invoked); err = lwipstack->lwip_Read((VirtualSocket*)*(_phy.getuptr(sock)), stack_invoked);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return -1; return err;
} }
// Write data from app socket to the virtual wire, either raw over VL2, or via network stack // Write data from app socket to the virtual wire, either raw over VL2, or via network stack
int VirtualTap::Write(VirtualSocket *vs, void *data, ssize_t len) { int VirtualTap::Write(VirtualSocket *vs, void *data, ssize_t len)
{
int err = -1;
#if defined(NO_STACK)
#endif
// VL2, SOCK_RAW, no network stack // VL2, SOCK_RAW, no network stack
if (vs->socket_type == SOCK_RAW) { if (vs->socket_type == SOCK_RAW) {
struct ether_header *eh = (struct ether_header *) data; struct ether_header *eh = (struct ether_header *) data;
@@ -516,15 +603,21 @@ namespace ZeroTier {
} }
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
return picostack->pico_Write(vs, data, len); err = picostack->pico_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
return lwipstack->lwip_Write(vs, data, len); err = lwipstack->lwip_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return -1; return err;
} }
// Send data to a specified host // Send data to a specified host
@@ -532,9 +625,8 @@ namespace ZeroTier {
{ {
/* FIXME: There is a call to *_Connect for each send, we should probably figure out a better way to do this, /* FIXME: There is a call to *_Connect for each send, we should probably figure out a better way to do this,
possibly consult the stack for "connection" state */ possibly consult the stack for "connection" state */
// TODO: flags // TODO: flags
int err = 0; int err = -1;
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
if ((err = picostack->pico_Connect(vs, addr, addrlen)) < 0) { // implicit if ((err = picostack->pico_Connect(vs, addr, addrlen)) < 0) { // implicit
@@ -545,6 +637,9 @@ namespace ZeroTier {
errno = ENOBUFS; // TODO: translate pico err to something more useful errno = ENOBUFS; // TODO: translate pico err to something more useful
return err; return err;
} }
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
@@ -555,6 +650,9 @@ namespace ZeroTier {
if ((err = lwipstack->lwip_Write(vs, (void*)buf, len)) < 0) { if ((err = lwipstack->lwip_Write(vs, (void*)buf, len)) < 0) {
return err; return err;
} }
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return err; return err;
@@ -562,21 +660,29 @@ namespace ZeroTier {
// Remove VritualSocket from VirtualTap, and instruct network stacks to dismantle their // Remove VritualSocket from VirtualTap, and instruct network stacks to dismantle their
// respective protocol control structures // respective protocol control structures
int VirtualTap::Close(VirtualSocket *vs) { int VirtualTap::Close(VirtualSocket *vs)
{
int err = 0; int err = 0;
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid VirtualSocket"); DEBUG_ERROR("invalid VirtualSocket");
handle_general_failure();
return -1; return -1;
} }
removeVirtualSocket(vs); removeVirtualSocket(vs);
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
err = picostack->pico_Close(vs); err = picostack->pico_Close(vs);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
err = lwipstack->lwip_Close(vs); err = lwipstack->lwip_Close(vs);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
if (vs->sock) { if (vs->sock) {
@@ -592,11 +698,17 @@ namespace ZeroTier {
#if defined(STACK_PICO) #if defined(STACK_PICO)
if (picostack) { if (picostack) {
err = picostack->pico_Shutdown(vs, how); err = picostack->pico_Shutdown(vs, how);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
if (lwipstack) { if (lwipstack) {
err = lwipstack->lwip_Shutdown(vs, how); err = lwipstack->lwip_Shutdown(vs, how);
} else {
handle_general_failure();
return -1;
} }
#endif #endif
return err; return err;
@@ -660,7 +772,6 @@ namespace ZeroTier {
} }
} }
} }
// TODO: Clean up VirtualSocket objects // TODO: Clean up VirtualSocket objects
last_housekeeping_ts = std::time(nullptr); last_housekeeping_ts = std::time(nullptr);
} }

View File

@@ -161,7 +161,7 @@ void zts_simple_start(const char *path, const char *nwid)
void zts_stop() { void zts_stop() {
if (ZeroTier::zt1Service) { if (ZeroTier::zt1Service) {
ZeroTier::zt1Service->terminate(); ZeroTier::zt1Service->terminate();
dismantleTaps(); disableTaps();
} }
} }
@@ -215,7 +215,8 @@ void zts_leave_soft(const char * filepath, const char * nwid) {
void zts_get_homepath(char *homePath, int len) { void zts_get_homepath(char *homePath, int len) {
if (ZeroTier::homeDir.length()) { if (ZeroTier::homeDir.length()) {
memset(homePath, 0, len); memset(homePath, 0, len);
memcpy(homePath, ZeroTier::homeDir.c_str(), len < ZeroTier::homeDir.length() ? len : ZeroTier::homeDir.length()); int buf_len = len < ZeroTier::homeDir.length() ? len : ZeroTier::homeDir.length();
memcpy(homePath, ZeroTier::homeDir.c_str(), buf_len);
} }
} }
@@ -414,7 +415,7 @@ int zts_socket(ZT_SOCKET_SIG) {
vs->socket_family = socket_family; vs->socket_family = socket_family;
vs->socket_type = socket_type; vs->socket_type = socket_type;
vs->protocol = protocol; vs->protocol = protocol;
add_unassigned_virtual_socket(vs->app_fd, vs); add_unassigned_virt_socket(vs->app_fd, vs);
return vs->app_fd; return vs->app_fd;
} }
#if defined(STACK_PICO) #if defined(STACK_PICO)
@@ -425,7 +426,7 @@ int zts_socket(ZT_SOCKET_SIG) {
vs->socket_family = socket_family; vs->socket_family = socket_family;
vs->socket_type = socket_type; vs->socket_type = socket_type;
vs->picosock = p; vs->picosock = p;
add_unassigned_virtual_socket(vs->app_fd, vs); add_unassigned_virt_socket(vs->app_fd, vs);
err = vs->app_fd; // return one end of the socketpair err = vs->app_fd; // return one end of the socketpair
} }
else { else {
@@ -443,7 +444,7 @@ int zts_socket(ZT_SOCKET_SIG) {
vs->socket_family = socket_family; vs->socket_family = socket_family;
vs->socket_type = socket_type; vs->socket_type = socket_type;
vs->pcb = pcb; vs->pcb = pcb;
add_unassigned_virtual_socket(vs->app_fd, vs); add_unassigned_virt_socket(vs->app_fd, vs);
// return one end of the socketpair for the app to use // return one end of the socketpair for the app to use
err = vs->app_fd; err = vs->app_fd;
} }
@@ -523,7 +524,7 @@ int zts_connect(ZT_CONNECT_SIG) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid socket, unable to locate VirtualSocket for fd=%d", fd); DEBUG_ERROR("invalid socket, unable to locate VirtualSocket for fd=%d", fd);
errno = EBADF; errno = EBADF;
@@ -570,8 +571,8 @@ int zts_connect(ZT_CONNECT_SIG) {
vs->sock = tap->_phy.wrapSocket(vs->sdk_fd, vs); vs->sock = tap->_phy.wrapSocket(vs->sdk_fd, vs);
// TODO: Consolidate these calls // TODO: Consolidate these calls
del_unassigned_virtual_socket(fd); del_unassigned_virt_socket(fd);
add_assigned_virtual_socket(tap, vs, fd); add_assigned_virt_socket(tap, vs, fd);
// save peer addr, for calls like getpeername // save peer addr, for calls like getpeername
memcpy(&(vs->peer_addr), addr, sizeof(vs->peer_addr)); memcpy(&(vs->peer_addr), addr, sizeof(vs->peer_addr));
@@ -652,7 +653,7 @@ int zts_bind(ZT_BIND_SIG) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("no VirtualSocket for fd=%d", fd); DEBUG_ERROR("no VirtualSocket for fd=%d", fd);
errno = ENOTSOCK; errno = ENOTSOCK;
@@ -704,8 +705,8 @@ int zts_bind(ZT_BIND_SIG) {
err = tap->Bind(vs, addr, addrlen); err = tap->Bind(vs, addr, addrlen);
if (err == 0) { // success if (err == 0) { // success
vs->tap = tap; vs->tap = tap;
del_unassigned_virtual_socket(fd); del_unassigned_virt_socket(fd);
add_assigned_virtual_socket(tap, vs, fd); add_assigned_virt_socket(tap, vs, fd);
} }
return err; return err;
} }
@@ -827,7 +828,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
} }
} }
if (accepted_vs) { if (accepted_vs) {
add_assigned_virtual_socket(tap, accepted_vs, accepted_vs->app_fd); add_assigned_virt_socket(tap, accepted_vs, accepted_vs->app_fd);
err = accepted_vs->app_fd; err = accepted_vs->app_fd;
} }
} }
@@ -908,43 +909,42 @@ int zts_accept4(ZT_ACCEPT4_SIG)
this error may also be returned if optlen is not in a this error may also be returned if optlen is not in a
valid part of the process address space. valid part of the process address space.
[ ] [EDOM] The argument value is out of bounds. [ ] [EDOM] The argument value is out of bounds.
int fd, int level, int optname, const void *optval, socklen_t optlen
*/ */
int zts_setsockopt(ZT_SETSOCKOPT_SIG) int zts_setsockopt(ZT_SETSOCKOPT_SIG)
{ {
// TODO: Move stack-specific logic into stack driver section DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname);
//DEBUG_INFO("fd=%d", fd);
int err = errno = 0; int err = errno = 0;
if (fd < 0 || fd >= ZT_MAX_SOCKETS) { if (fd < 0 || fd >= ZT_MAX_SOCKETS) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
#if defined(STACK_PICO) ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid fd=%d", fd); DEBUG_ERROR("invalid fd=%d", fd);
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
struct pico_socket *p = vs->picosock; #if defined(STACK_PICO)
if (p) { if (ZeroTier::picostack) {
// Disable Nagle's algorithm err = ZeroTier::picostack->pico_setsockopt(vs, level, optname, optval, optlen);
int value = 1; } else {
if ((err = pico_socket_setoption(p, PICO_TCP_NODELAY, &value)) < 0) { handle_general_failure();
if (err == PICO_ERR_EINVAL) { // TODO: errno?
DEBUG_ERROR("error while disabling Nagle's algorithm"); err = -1;
errno = ENOPROTOOPT;
return -1;
}
}
} }
err = setsockopt(fd, level, optname, optval, optlen);
return err;
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
// TODO if (ZeroTier::lwipstack) {
err = ZeroTier::lwipstack->lwip_setsockopt(vs, level, optname, optval, optlen);
} else {
handle_general_failure();
// TODO: errno?
err = -1;
}
#endif #endif
return 0; return err;
} }
/* /*
@@ -960,12 +960,36 @@ int zts_setsockopt(ZT_SETSOCKOPT_SIG)
*/ */
int zts_getsockopt(ZT_GETSOCKOPT_SIG) int zts_getsockopt(ZT_GETSOCKOPT_SIG)
{ {
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname);
int err = errno = 0; int err = errno = 0;
if (fd < 0 || fd >= ZT_MAX_SOCKETS) { if (fd < 0 || fd >= ZT_MAX_SOCKETS) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
err = getsockopt(fd, level, optname, optval, optlen); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid fd=%d", fd);
errno = EBADF;
return -1;
}
#if defined(STACK_PICO)
if (ZeroTier::picostack) {
err = ZeroTier::picostack->pico_getsockopt(vs, level, optname, optval, optlen);
} else {
handle_general_failure();
// TODO: errno?
err = -1;
}
#endif
#if defined(STACK_LWIP)
if (ZeroTier::lwipstack) {
err = ZeroTier::lwipstack->lwip_getsockopt(vs, level, optname, optval, optlen);
} else {
handle_general_failure();
// TODO: errno?
err = -1;
}
#endif
return err; return err;
} }
@@ -1008,7 +1032,7 @@ int zts_getpeername(ZT_GETPEERNAME_SIG)
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
errno = ENOTCONN; errno = ENOTCONN;
return -1; return -1;
@@ -1083,14 +1107,14 @@ int zts_close(ZT_CLOSE_SIG)
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("no vs found for fd=%d", fd); DEBUG_ERROR("no vs found for fd=%d", fd);
handle_general_failure(); handle_general_failure();
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
del_virtual_socket(fd); del_virt_socket(fd);
if (vs->tap) { if (vs->tap) {
vs->tap->Close(vs); vs->tap->Close(vs);
} }
@@ -1231,7 +1255,7 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("no vs found for fd=%x", fd); DEBUG_ERROR("no vs found for fd=%x", fd);
handle_general_failure(); handle_general_failure();
@@ -1356,7 +1380,7 @@ ssize_t zts_send(ZT_SEND_SIG)
errno = EMSGSIZE; errno = EMSGSIZE;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd); DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF; errno = EBADF;
@@ -1468,7 +1492,7 @@ ssize_t zts_recv(ZT_RECV_SIG)
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd); DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF; errno = EBADF;
@@ -1671,7 +1695,7 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd); ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd); DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF; errno = EBADF;
@@ -1855,7 +1879,8 @@ namespace ZeroTier {
return rxbytes; return rxbytes;
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1write(JNIEnv *env, jobject thisObj,
jint fd, jarray buf, jint len)
{ {
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0); jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
char * bufp = (char *)malloc(sizeof(char)*len); char * bufp = (char *)malloc(sizeof(char)*len);
@@ -1865,7 +1890,8 @@ namespace ZeroTier {
return written_bytes; return written_bytes;
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1read(JNIEnv *env, jobject thisObj,
jint fd, jarray buf, jint len)
{ {
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0); jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
int read_bytes = read(fd, body, len); int read_bytes = read(fd, body, len);
@@ -1874,19 +1900,23 @@ namespace ZeroTier {
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1setsockopt( JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1setsockopt(
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) { JNIEnv *env, jobject thisObj,
jint fd, jint level, jint optname, jint optval, jint optlen) {
return zts_setsockopt(fd, level, optname, (const void*)optval, optlen); return zts_setsockopt(fd, level, optname, (const void*)optval, optlen);
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockopt(JNIEnv *env, jobject thisObj,
jint fd, jint level, jint optname, jint optval, jint optlen) {
return zts_getsockopt(fd, level, optname, (void*)optval, (socklen_t *)optlen); return zts_getsockopt(fd, level, optname, (void*)optval, (socklen_t *)optlen);
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1socket(JNIEnv *env, jobject thisObj,
jint family, jint type, jint protocol) {
return zts_socket(family, type, protocol); return zts_socket(family, type, protocol);
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1connect(JNIEnv *env, jobject thisObj,
jint fd, jstring addrstr, jint port) {
struct sockaddr_in addr; struct sockaddr_in addr;
const char *str = (*env).GetStringUTFChars( addrstr, 0); const char *str = (*env).GetStringUTFChars( addrstr, 0);
addr.sin_addr.s_addr = inet_addr(str); addr.sin_addr.s_addr = inet_addr(str);
@@ -1896,7 +1926,8 @@ namespace ZeroTier {
return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr)); return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr));
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1bind(JNIEnv *env, jobject thisObj,
jint fd, jstring addrstr, jint port) {
struct sockaddr_in addr; struct sockaddr_in addr;
const char *str = (*env).GetStringUTFChars( addrstr, 0); const char *str = (*env).GetStringUTFChars( addrstr, 0);
DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port); DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port);
@@ -1908,7 +1939,8 @@ namespace ZeroTier {
} }
#if defined(__linux__) #if defined(__linux__)
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept4(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port, jint flags) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept4(JNIEnv *env, jobject thisObj,
jint fd, jstring addrstr, jint port, jint flags) {
struct sockaddr_in addr; struct sockaddr_in addr;
char *str; char *str;
// = env->GetStringUTFChars(addrstr, NULL); // = env->GetStringUTFChars(addrstr, NULL);
@@ -1920,7 +1952,8 @@ namespace ZeroTier {
} }
#endif #endif
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept(JNIEnv *env, jobject thisObj,
jint fd, jstring addrstr, jint port) {
struct sockaddr_in addr; struct sockaddr_in addr;
// TODO: Send addr info back to Javaland // TODO: Send addr info back to Javaland
addr.sin_addr.s_addr = inet_addr(""); addr.sin_addr.s_addr = inet_addr("");
@@ -1929,15 +1962,18 @@ namespace ZeroTier {
return zts_accept(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr)); return zts_accept(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr));
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1listen(JNIEnv *env, jobject thisObj,
jint fd, int backlog) {
return zts_listen(fd, backlog); return zts_listen(fd, backlog);
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1close(JNIEnv *env, jobject thisObj, jint fd) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1close(JNIEnv *env, jobject thisObj,
jint fd) {
return zts_close(fd); return zts_close(fd);
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockname(JNIEnv *env, jobject thisObj,
jint fd, jobject ztaddr) {
struct sockaddr_in addr; struct sockaddr_in addr;
int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr)); int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
jfieldID fid; jfieldID fid;
@@ -1949,7 +1985,8 @@ namespace ZeroTier {
return err; return err;
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getpeername(JNIEnv *env, jobject thisObj,
jint fd, jobject ztaddr) {
struct sockaddr_in addr; struct sockaddr_in addr;
int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr)); int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
jfieldID fid; jfieldID fid;
@@ -1961,7 +1998,8 @@ namespace ZeroTier {
return err; return err;
} }
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1fcntl(JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags) { JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1fcntl(JNIEnv *env, jobject thisObj,
jint fd, jint cmd, jint flags) {
return zts_fcntl(fd,cmd,flags); return zts_fcntl(fd,cmd,flags);
} }
} }
@@ -1973,6 +2011,7 @@ namespace ZeroTier {
bool can_provision_new_socket(int socket_type) bool can_provision_new_socket(int socket_type)
{ {
int can = false;
#if defined(STACK_PICO) #if defined(STACK_PICO)
return !(pico_ntimers()+1 > PICO_MAX_TIMERS); return !(pico_ntimers()+1 > PICO_MAX_TIMERS);
#endif #endif
@@ -1986,15 +2025,16 @@ bool can_provision_new_socket(int socket_type)
if (socket_type == SOCK_RAW) { if (socket_type == SOCK_RAW) {
return !(ZeroTier::lwIP::lwip_num_current_raw_pcbs()+1 > MEMP_NUM_RAW_PCB); return !(ZeroTier::lwIP::lwip_num_current_raw_pcbs()+1 > MEMP_NUM_RAW_PCB);
} }
return true; can = true;
#endif #endif
#if defined(NO_STACK) #if defined(NO_STACK)
// always true since there's no network stack timer/memory limitation // always true since there's no network stack timer/memory limitation
return true; can = true;
#endif #endif
return can;
} }
int zts_nsockets() int zts_num_active_virt_sockets()
{ {
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
int num = ZeroTier::unmap.size() + ZeroTier::fdmap.size(); int num = ZeroTier::unmap.size() + ZeroTier::fdmap.size();
@@ -2002,18 +2042,32 @@ int zts_nsockets()
return num; return num;
} }
int zts_maxsockets() int zts_maxsockets(int socket_type)
{ {
int max = 0;
#if defined(STACK_PICO) #if defined(STACK_PICO)
// TODO: This is only an approximation // TODO: This is only an approximation
return PICO_MAX_TIMERS - 10; // TODO: distinquish by type
max = PICO_MAX_TIMERS - 10;
#endif #endif
#if defined(STACK_LWIP) #if defined(STACK_LWIP)
return 32; if (socket_type == SOCK_STREAM) {
max = MEMP_NUM_TCP_PCB;
}
if (socket_type == SOCK_DGRAM) {
max = MEMP_NUM_UDP_PCB;
}
#endif #endif
#if defined(NO_STACK) #if defined(NO_STACK)
return 1024; // arbitrary // arbitrary
#if defined(__linux__)
max = RLIMIT_NOFILE;
#endif #endif
#if defined(__APPLE__)
max = 1024;
#endif
#endif
return max;
} }
/****************************************************************************/ /****************************************************************************/
@@ -2124,7 +2178,7 @@ ZeroTier::VirtualTap *getAnyTap()
/* VirtualSocket / VirtualTap helper functions - DON'T CALL THESE DIRECTLY */ /* VirtualSocket / VirtualTap helper functions - DON'T CALL THESE DIRECTLY */
/****************************************************************************/ /****************************************************************************/
ZeroTier::VirtualSocket *get_virtual_socket(int fd) ZeroTier::VirtualSocket *get_virt_socket(int fd)
{ {
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
// try to locate in unmapped set // try to locate in unmapped set
@@ -2143,7 +2197,7 @@ ZeroTier::VirtualSocket *get_virtual_socket(int fd)
return vs; return vs;
} }
int del_virtual_socket(int fd) int del_virt_socket(int fd)
{ {
int err = 0; int err = 0;
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
@@ -2166,7 +2220,7 @@ int del_virtual_socket(int fd)
return err; return err;
} }
int add_unassigned_virtual_socket(int fd, ZeroTier::VirtualSocket *vs) int add_unassigned_virt_socket(int fd, ZeroTier::VirtualSocket *vs)
{ {
int err = 0; int err = 0;
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
@@ -2189,7 +2243,7 @@ int add_unassigned_virtual_socket(int fd, ZeroTier::VirtualSocket *vs)
return err; return err;
} }
int del_unassigned_virtual_socket(int fd) int del_unassigned_virt_socket(int fd)
{ {
int err = 0; int err = 0;
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
@@ -2208,12 +2262,13 @@ int del_unassigned_virtual_socket(int fd)
return err; return err;
} }
int add_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd) int add_assigned_virt_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd)
{ {
int err = 0; int err = 0;
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
try { try {
std::map<int, std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>*>::iterator fd_iter = ZeroTier::fdmap.find(fd); std::map<int, std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>*>::iterator fd_iter;
fd_iter = ZeroTier::fdmap.find(fd);
if (fd_iter == ZeroTier::fdmap.end()) { if (fd_iter == ZeroTier::fdmap.end()) {
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(vs, tap); ZeroTier::fdmap[fd] = new std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>(vs, tap);
} }
@@ -2231,12 +2286,13 @@ int add_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSock
return err; return err;
} }
int del_assigned_virtual_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd) int del_assigned_virt_socket(ZeroTier::VirtualTap *tap, ZeroTier::VirtualSocket *vs, int fd)
{ {
int err = 0; int err = 0;
ZeroTier::_multiplexer_lock.lock(); ZeroTier::_multiplexer_lock.lock();
try { try {
std::map<int, std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>*>::iterator fd_iter = ZeroTier::fdmap.find(fd); std::map<int, std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>*>::iterator fd_iter;
fd_iter = ZeroTier::fdmap.find(fd);
if (fd_iter != ZeroTier::fdmap.end()) { if (fd_iter != ZeroTier::fdmap.end()) {
ZeroTier::fdmap.erase(fd_iter); ZeroTier::fdmap.erase(fd_iter);
} }
@@ -2258,15 +2314,13 @@ std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *get_assigned_virtual
return p; return p;
} }
void dismantleTaps() void disableTaps()
{ {
ZeroTier::_vtaps_lock.lock(); ZeroTier::_vtaps_lock.lock();
for(int i=0; i<ZeroTier::vtaps.size(); i++) { for(int i=0; i<ZeroTier::vtaps.size(); i++) {
DEBUG_ERROR("ZeroTier::vtapsf[i]=%p", ZeroTier::vtaps[i]); DEBUG_EXTRA("vt=%p", ZeroTier::vtaps[i]);
delete (ZeroTier::VirtualTap*)ZeroTier::vtaps[i]; ((ZeroTier::VirtualTap*)ZeroTier::vtaps[i])->_enabled = false;
ZeroTier::vtaps[i] = NULL;
} }
ZeroTier::vtaps.clear();
ZeroTier::_vtaps_lock.unlock(); ZeroTier::_vtaps_lock.unlock();
} }

View File

@@ -88,7 +88,7 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p)
int proto = ZeroTier::Utils::ntoh((uint16_t)ethhdr->type); int proto = ZeroTier::Utils::ntoh((uint16_t)ethhdr->type);
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len); tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len);
if (ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { if (ZT_MSG_TRANSFER == true) {
char flagbuf[32]; char flagbuf[32];
memset(&flagbuf, 0, 32); memset(&flagbuf, 0, 32);
char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN];
@@ -333,7 +333,11 @@ namespace ZeroTier
dataptr += q->len; dataptr += q->len;
} }
} }
if (ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { else {
DEBUG_ERROR("dropped packet: no pbufs available");
return;
}
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32]; char flagbuf[32];
memset(&flagbuf, 0, 32); memset(&flagbuf, 0, 32);
char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN];
@@ -344,10 +348,6 @@ namespace ZeroTier
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s %s", len, macBuf, nodeBuf, tap->nodeId().c_str(),
ZeroTier::Utils::ntoh(ethhdr.type), beautify_eth_proto_nums(ZeroTier::Utils::ntoh(ethhdr.type)), flagbuf); ZeroTier::Utils::ntoh(ethhdr.type), beautify_eth_proto_nums(ZeroTier::Utils::ntoh(ethhdr.type)), flagbuf);
} }
else {
DEBUG_ERROR("dropped packet: no pbufs available");
return;
}
{ {
#if defined(LIBZT_IPV4) #if defined(LIBZT_IPV4)
if (tap->lwipdev.input(p, &(tap->lwipdev)) != ERR_OK) { if (tap->lwipdev.input(p, &(tap->lwipdev)) != ERR_OK) {
@@ -658,12 +658,12 @@ namespace ZeroTier
if (vs->pcb) { if (vs->pcb) {
struct tcp_pcb* tpcb = (struct tcp_pcb*)vs->pcb; struct tcp_pcb* tpcb = (struct tcp_pcb*)vs->pcb;
if (tpcb->state == CLOSED) { if (tpcb->state == CLOSED) {
DEBUG_ERROR("pcb is in CLOSED state"); DEBUG_EXTRA("pcb is in CLOSED state");
// calling tcp_close() here would be redundant // calling tcp_close() here would be redundant
return 0; return 0;
} }
if (tpcb->state == CLOSE_WAIT) { if (tpcb->state == CLOSE_WAIT) {
DEBUG_ERROR("pcb is in CLOSE_WAIT state"); DEBUG_EXTRA("pcb is in CLOSE_WAIT state");
// calling tcp_close() here would be redundant // calling tcp_close() here would be redundant
} }
if (tpcb->state > TIME_WAIT) { if (tpcb->state > TIME_WAIT) {
@@ -922,7 +922,7 @@ namespace ZeroTier
err_t lwIP::lwip_cb_connected(void *arg, struct tcp_pcb *PCB, err_t err) err_t lwIP::lwip_cb_connected(void *arg, struct tcp_pcb *PCB, err_t err)
{ {
DEBUG_ATTN("pcb=%p", PCB); DEBUG_EXTRA("pcb=%p", PCB);
VirtualSocket *vs = (VirtualSocket *)arg; VirtualSocket *vs = (VirtualSocket *)arg;
if (vs == NULL) { if (vs == NULL) {
DEBUG_ERROR("invalid virtual socket"); DEBUG_ERROR("invalid virtual socket");
@@ -994,6 +994,690 @@ namespace ZeroTier
return ERR_OK; return ERR_OK;
} }
int lwIP::lwip_setsockopt(VirtualSocket *vs, int level, int optname, const void *optval, socklen_t optlen)
{
int err = -1;
errno = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid vs");
return -1;
} else {
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", vs->app_fd, level, optname);
}
if (level == SOL_SOCKET)
{
/* Turns on recording of debugging information. This option enables or disables debugging in the underlying
protocol modules. This option takes an int value. This is a Boolean option.*/
if (optname == SO_DEBUG)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Specifies that the rules used in validating addresses supplied to bind() should allow reuse of local
addresses, if this is supported by the protocol. This option takes an int value. This is a Boolean option.*/
if (optname == SO_REUSEADDR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Keeps connections active by enabling the periodic transmission of messages, if this is supported by the
protocol. This option takes an int value. */
if (optname == SO_KEEPALIVE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Requests that outgoing messages bypass the standard routing facilities. */
if (optname == SO_DONTROUTE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Lingers on a close() if data is present. */
if (optname == SO_LINGER)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Permits sending of broadcast messages, if this is supported by the protocol. This option takes an int
value. This is a Boolean option. */
if (optname == SO_BROADCAST)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Leaves received out-of-band data (data marked urgent) inline. This option takes an int value. This is a
Boolean option. */
if (optname == SO_OOBINLINE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets send buffer size. This option takes an int value. */
if (optname == SO_SNDBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets receive buffer size. This option takes an int value. */
if (optname == SO_RCVBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_STYLE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_TYPE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Get error status and clear */
if (optname == SO_ERROR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_IP)
{
if (optname == IP_ADD_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BIND_ADDRESS_NO_PORT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_FREEBIND) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_HDRINCL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MSFILTER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU_DISCOVER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_ALL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_IF) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_LOOP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_NODEFRAG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_OPTIONS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_PKTINFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVORIGDSTADDR) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RETOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ROUTER_ALERT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TRANSPARENT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_UNBLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
// TODO
return -1;
}
if (level == IPPROTO_TCP)
{
struct tcp_pcb *pcb = (struct tcp_pcb*)(vs->pcb);
if (pcb == NULL) {
handle_general_failure();
return -1;
}
/* If set, don't send out partial frames. */
if (optname == TCP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Allow a listener to be awakened only when data arrives on the socket. */
if (optname == TCP_DEFER_ACCEPT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Used to collect information about this socket. The kernel returns a struct tcp_info as defined in the
file /usr/include/linux/tcp.h.*/
if (optname == TCP_INFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum number of keepalive probes TCP should send before dropping the connection.*/
if (optname == TCP_KEEPCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes,
if the socket option SO_KEEPALIVE has been set on this socket. */
if (optname == TCP_KEEPIDLE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) between individual keepalive probes.*/
if (optname == TCP_KEEPINTVL) {
// TODO
return -1;
}
/* The lifetime of orphaned FIN_WAIT2 state sockets. */
if (optname == TCP_LINGER2) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum segment size for outgoing TCP packets. */
if (optname == TCP_MAXSEG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* If set, disable the Nagle algorithm. */
if (optname == TCP_NODELAY) {
pcb->flags |= TF_NODELAY;
return 0;
}
/* Enable quickack mode if set or disable quickack mode if cleared. */
if (optname == TCP_QUICKACK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Set the number of SYN retransmits that TCP should send before aborting the attempt to connect. It
cannot exceed 255. */
if (optname == TCP_SYNCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Bound the size of the advertised window to this value. The kernel imposes a minimum size of
SOCK_MIN_RCVBUF/2. */
if (optname == TCP_WINDOW_CLAMP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_UDP)
{
/*If this option is enabled, then all data output on this socket is accumulated into a single
datagram that is transmitted when the option is disabled. */
if (optname == UDP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
return err;
}
int lwIP::lwip_getsockopt(VirtualSocket *vs, int level, int optname, void *optval, socklen_t *optlen)
{
int err = -1, optval_tmp = 0;
errno = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid vs");
return -1;
} else {
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", vs->app_fd, level, optname);
}
if (level == SOL_SOCKET)
{
/* Turns on recording of debugging information. This option enables or disables debugging in the underlying
protocol modules. This option takes an int value. This is a Boolean option.*/
if (optname == SO_DEBUG)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Specifies that the rules used in validating addresses supplied to bind() should allow reuse of local
addresses, if this is supported by the protocol. This option takes an int value. This is a Boolean option.*/
if (optname == SO_REUSEADDR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Keeps connections active by enabling the periodic transmission of messages, if this is supported by the
protocol. This option takes an int value. */
if (optname == SO_KEEPALIVE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Requests that outgoing messages bypass the standard routing facilities. */
if (optname == SO_DONTROUTE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Lingers on a close() if data is present. */
if (optname == SO_LINGER)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Permits sending of broadcast messages, if this is supported by the protocol. This option takes an int
value. This is a Boolean option. */
if (optname == SO_BROADCAST)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Leaves received out-of-band data (data marked urgent) inline. This option takes an int value. This is a
Boolean option. */
if (optname == SO_OOBINLINE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets send buffer size. This option takes an int value. */
if (optname == SO_SNDBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets receive buffer size. This option takes an int value. */
if (optname == SO_RCVBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_STYLE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_TYPE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Get error status and clear */
if (optname == SO_ERROR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_IP)
{
if (optname == IP_ADD_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BIND_ADDRESS_NO_PORT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_FREEBIND) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_HDRINCL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MSFILTER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU_DISCOVER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_ALL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_IF) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_LOOP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_NODEFRAG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_OPTIONS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_PKTINFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVORIGDSTADDR) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RETOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ROUTER_ALERT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TRANSPARENT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_UNBLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
// TODO
return -1;
}
if (level == IPPROTO_TCP)
{
struct tcp_pcb *pcb = (struct tcp_pcb*)(vs->pcb);
if (pcb == NULL) {
handle_general_failure();
return -1;
}
/* If set, don't send out partial frames. */
if (optname == TCP_CORK) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* Allow a listener to be awakened only when data arrives on the socket. */
if (optname == TCP_DEFER_ACCEPT) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* Used to collect information about this socket. */
if (optname == TCP_INFO) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* The maximum number of keepalive probes TCP should send before dropping the connection.*/
if (optname == TCP_KEEPCNT) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes,
if the socket option SO_KEEPALIVE has been set on this socket. */
if (optname == TCP_KEEPIDLE) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* The time (in seconds) between individual keepalive probes.*/
if (optname == TCP_KEEPINTVL) {
// TODO
err = -1;
}
/* The lifetime of orphaned FIN_WAIT2 state sockets. */
if (optname == TCP_LINGER2) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* The maximum segment size for outgoing TCP packets. */
if (optname == TCP_MAXSEG) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* If set, disable the Nagle algorithm. */
if (optname == TCP_NODELAY) {
optval_tmp = pcb->flags & TF_NODELAY;
memcpy(optval, &optval_tmp, *optlen);
err = 0;
}
/* Enable quickack mode if set or disable quickack mode if cleared. */
if (optname == TCP_QUICKACK) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* Set the number of SYN retransmits that TCP should send before aborting the attempt to connect. It
cannot exceed 255. */
if (optname == TCP_SYNCNT) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
/* Bound the size of the advertised window to this value. The kernel imposes a minimum size of
SOCK_MIN_RCVBUF/2. */
if (optname == TCP_WINDOW_CLAMP) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
}
if (level == IPPROTO_UDP)
{
/* If this option is enabled, then all data output on this socket is accumulated into a single
datagram that is transmitted when the option is disabled. */
if (optname == UDP_CORK) {
// TODO
errno = ENOPROTOOPT;
err = -1;
}
}
return err;
}
void lwIP::lwip_cb_err(void *arg, err_t err) void lwIP::lwip_cb_err(void *arg, err_t err)
{ {
VirtualSocket *vs = (VirtualSocket *)arg; VirtualSocket *vs = (VirtualSocket *)arg;

View File

@@ -287,6 +287,16 @@ namespace ZeroTier {
*/ */
int lwip_Shutdown(VirtualSocket *vs, int how); int lwip_Shutdown(VirtualSocket *vs, int how);
/*
* Sets a property of a socket
*/
static int lwip_setsockopt(VirtualSocket *vs, int level, int optname, const void *optval, socklen_t optlen);
/*
* Gets a property of a socket
*/
static int lwip_getsockopt(VirtualSocket *vs, int level, int optname, void *optval, socklen_t *optlen);
// --- Callbacks from network stack --- // --- Callbacks from network stack ---
//static void netif_status_callback(struct netif *nif); //static void netif_status_callback(struct netif *nif);

View File

@@ -564,7 +564,7 @@ namespace ZeroTier {
MAC dest_mac; MAC dest_mac;
src_mac.setTo(ethhdr->saddr, 6); src_mac.setTo(ethhdr->saddr, 6);
dest_mac.setTo(ethhdr->daddr, 6); dest_mac.setTo(ethhdr->daddr, 6);
if (ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { if (ZT_MSG_TRANSFER == true) {
char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN];
mac2str(macBuf, ZT_MAC_ADDRSTRLEN, ethhdr->daddr); mac2str(macBuf, ZT_MAC_ADDRSTRLEN, ethhdr->daddr);
ZeroTier::MAC mac; ZeroTier::MAC mac;
@@ -641,7 +641,7 @@ namespace ZeroTier {
ethhdr.proto = Utils::hton((uint16_t)etherType); ethhdr.proto = Utils::hton((uint16_t)etherType);
int32_t msg_len = len + sizeof(int32_t) + sizeof(struct pico_eth_hdr); int32_t msg_len = len + sizeof(int32_t) + sizeof(struct pico_eth_hdr);
if (ZT_DEBUG_LEVEL >= ZT_MSG_TRANSFER) { if (ZT_MSG_TRANSFER == true) {
char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN]; char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN];
mac2str(macBuf, sizeof(macBuf), ethhdr.saddr); mac2str(macBuf, sizeof(macBuf), ethhdr.saddr);
ZeroTier::MAC mac; ZeroTier::MAC mac;
@@ -716,8 +716,11 @@ namespace ZeroTier {
// get frame len // get frame len
memcpy(&len, tap->pico_frame_rxbuf, sizeof(int32_t)); memcpy(&len, tap->pico_frame_rxbuf, sizeof(int32_t));
if (len > sizeof(int32_t)) { // meaning, since we package the len in the msg, we don't want to recv a 0-(sizeof(int32_t)) sized frame if (len > sizeof(int32_t)) { // meaning, since we package the len in the msg, we don't want to recv a 0-(sizeof(int32_t)) sized frame
DEBUG_ERROR("tap->pico_frame_rxbuf + sizeof(int32_t)=%p, len=%d", tap->pico_frame_rxbuf + sizeof(int32_t), len-(sizeof(int32_t)));
memcpy(frame, tap->pico_frame_rxbuf + sizeof(int32_t), len-(sizeof(int32_t)) ); // get frame data memcpy(frame, tap->pico_frame_rxbuf + sizeof(int32_t), len-(sizeof(int32_t)) ); // get frame data
DEBUG_ERROR("tap->pico_frame_rxbuf=%p, tap->pico_frame_rxbuf + len=%p, MAX_PICO_FRAME_RX_BUF_SZ-len=%d", tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len);
memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer
DEBUG_ERROR("dev=%p, frame=%p, len=%d", dev, frame, (len-sizeof(int32_t)));
if ((err = pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(int32_t)))) < 0) { if ((err = pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(int32_t)))) < 0) {
if (picostack) { if (picostack) {
DEBUG_ERROR("pico_stack_recv(), err=%d, pico_err=%d, %s", err, pico_err, picostack->beautify_pico_error(pico_err)); DEBUG_ERROR("pico_stack_recv(), err=%d, pico_err=%d, %s", err, pico_err, picostack->beautify_pico_error(pico_err));
@@ -745,44 +748,43 @@ namespace ZeroTier {
else { else {
int protocol_version = 0; int protocol_version = 0;
struct pico_socket *psock; struct pico_socket *psock;
if (socket_family == AF_INET) if (socket_family == AF_INET) {
protocol_version = PICO_PROTO_IPV4; protocol_version = PICO_PROTO_IPV4;
if (socket_family == AF_INET6) }
if (socket_family == AF_INET6) {
protocol_version = PICO_PROTO_IPV6; protocol_version = PICO_PROTO_IPV6;
}
if (socket_type == SOCK_DGRAM) { if (socket_type == SOCK_DGRAM) {
psock = pico_socket_open( psock = pico_socket_open(protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_ev);
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_ev);
if (psock) { if (psock) {
// configure size of UDP SND/RCV buffers // configure size of UDP SND/RCV buffers
// TODO // TODO
} }
} }
if (socket_type == SOCK_STREAM) { if (socket_type == SOCK_STREAM) {
psock = pico_socket_open( psock = pico_socket_open(protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_ev);
protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_ev);
if (psock) { if (psock) {
// configure size of TCP SND/RCV buffers // configure size of TCP SND/RCV buffers
int tx_buf_sz = ZT_STACK_TCP_SOCKET_TX_SZ; int tx_buf_sz = ZT_STACK_TCP_SOCKET_TX_SZ;
int rx_buf_sz = ZT_STACK_TCP_SOCKET_RX_SZ; int rx_buf_sz = ZT_STACK_TCP_SOCKET_RX_SZ;
int t_err = 0; int t_err = 0;
if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_SNDBUF, &tx_buf_sz)) < 0) {
// int value = 1;
// pico_socket_setoption(psock, PICO_TCP_NODELAY, &value);
if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_SNDBUF, &tx_buf_sz)) < 0)
DEBUG_ERROR("unable to set SNDBUF size, err=%d, pico_err=%d, %s", DEBUG_ERROR("unable to set SNDBUF size, err=%d, pico_err=%d, %s",
t_err, pico_err, beautify_pico_error(pico_err)); t_err, pico_err, beautify_pico_error(pico_err));
if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_RCVBUF, &rx_buf_sz)) < 0) }
if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_RCVBUF, &rx_buf_sz)) < 0) {
DEBUG_ERROR("unable to set RCVBUF size, err=%d, pico_err=%d, %s", DEBUG_ERROR("unable to set RCVBUF size, err=%d, pico_err=%d, %s",
t_err, pico_err, beautify_pico_error(pico_err)); t_err, pico_err, beautify_pico_error(pico_err));
}
/*
if (ZT_SOCK_BEHAVIOR_LINGER) { if (ZT_SOCK_BEHAVIOR_LINGER) {
int linger_time_ms = ZT_SOCK_BEHAVIOR_LINGER_TIME; int linger_time_ms = ZT_SOCK_BEHAVIOR_LINGER_TIME;
if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0) if ((t_err = pico_socket_setoption(psock, PICO_SOCKET_OPT_LINGER, &linger_time_ms)) < 0) {
DEBUG_ERROR("unable to set LINGER, err=%d, pico_err=%d, %s", DEBUG_ERROR("unable to set LINGER, err=%d, pico_err=%d, %s",
t_err, pico_err, beautify_pico_error(pico_err)); t_err, pico_err, beautify_pico_error(pico_err));
}
} }
*/
} }
} }
*p = psock; *p = psock;
@@ -1024,6 +1026,727 @@ namespace ZeroTier {
return err; return err;
} }
int picoTCP::pico_setsockopt(VirtualSocket *vs, int level, int optname, const void *optval, socklen_t optlen)
{
int err = -1;
errno = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid vs");
return -1;
} else {
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", vs->app_fd, level, optname);
}
if (level == SOL_SOCKET)
{
/* Turns on recording of debugging information. This option enables or disables debugging in the underlying
protocol modules. This option takes an int value. This is a Boolean option.*/
if (optname == SO_DEBUG)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Specifies that the rules used in validating addresses supplied to bind() should allow reuse of local
addresses, if this is supported by the protocol. This option takes an int value. This is a Boolean option.*/
if (optname == SO_REUSEADDR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Keeps connections active by enabling the periodic transmission of messages, if this is supported by the
protocol. This option takes an int value. */
if (optname == SO_KEEPALIVE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Requests that outgoing messages bypass the standard routing facilities. */
if (optname == SO_DONTROUTE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Lingers on a close() if data is present. */
if (optname == SO_LINGER)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Permits sending of broadcast messages, if this is supported by the protocol. This option takes an int
value. This is a Boolean option. */
if (optname == SO_BROADCAST)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Leaves received out-of-band data (data marked urgent) inline. This option takes an int value. This is a
Boolean option. */
if (optname == SO_OOBINLINE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets send buffer size. This option takes an int value. */
if (optname == SO_SNDBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets receive buffer size. This option takes an int value. */
if (optname == SO_RCVBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_STYLE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_TYPE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Get error status and clear */
if (optname == SO_ERROR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_IP)
{
if (optname == IP_ADD_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BIND_ADDRESS_NO_PORT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_FREEBIND) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_HDRINCL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MSFILTER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU_DISCOVER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_ALL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_IF) {
/*
if ((err = pico_socket_getoption(p, PICO_TCP_NODELAY, &optval_tmp)) < 0) {
if (err == PICO_ERR_EINVAL) {
DEBUG_ERROR("error while disabling Nagle's algorithm");
errno = ENOPROTOOPT;
err = -1;
}
}
memcpy(optval, &optval_tmp, *optlen);
*/
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_LOOP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_NODEFRAG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_OPTIONS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_PKTINFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVORIGDSTADDR) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RETOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ROUTER_ALERT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TRANSPARENT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_UNBLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
// TODO
return -1;
}
if (level == IPPROTO_TCP)
{
struct pico_socket *p = vs->picosock;
if (p == NULL) {
handle_general_failure();
return -1;
}
/* If set, don't send out partial frames. */
if (optname == TCP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Allow a listener to be awakened only when data arrives on the socket. */
if (optname == TCP_DEFER_ACCEPT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Used to collect information about this socket. The kernel returns a struct tcp_info as defined in the
file /usr/include/linux/tcp.h.*/
if (optname == TCP_INFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum number of keepalive probes TCP should send before dropping the connection.*/
if (optname == TCP_KEEPCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes,
if the socket option SO_KEEPALIVE has been set on this socket. */
if (optname == TCP_KEEPIDLE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) between individual keepalive probes.*/
if (optname == TCP_KEEPINTVL) {
// TODO
return -1;
}
/* The lifetime of orphaned FIN_WAIT2 state sockets. */
if (optname == TCP_LINGER2) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum segment size for outgoing TCP packets. */
if (optname == TCP_MAXSEG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* If set, disable the Nagle algorithm. */
if (optname == TCP_NODELAY) {
int no_delay = *((const int*)optval);
if ((err = pico_socket_setoption(p, PICO_TCP_NODELAY, &no_delay) < 0)) {
if (err == PICO_ERR_EINVAL) {
DEBUG_ERROR("error while disabling Nagle's algorithm");
errno = EINVAL;
err = -1;
}
}
return err;
}
/* Enable quickack mode if set or disable quickack mode if cleared. */
if (optname == TCP_QUICKACK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Set the number of SYN retransmits that TCP should send before aborting the attempt to connect. It
cannot exceed 255. */
if (optname == TCP_SYNCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Bound the size of the advertised window to this value. The kernel imposes a minimum size of
SOCK_MIN_RCVBUF/2. */
if (optname == TCP_WINDOW_CLAMP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_UDP)
{
/*If this option is enabled, then all data output on this socket is accumulated into a single
datagram that is transmitted when the option is disabled. */
if (optname == UDP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
return err;
}
int picoTCP::pico_getsockopt(VirtualSocket *vs, int level, int optname, void *optval, socklen_t *optlen)
{
int err = -1, optval_tmp = 0;
errno = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid vs");
return -1;
} else {
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", vs->app_fd, level, optname);
}
if (level == SOL_SOCKET)
{
/* Turns on recording of debugging information. This option enables or disables debugging in the underlying
protocol modules. This option takes an int value. This is a Boolean option.*/
if (optname == SO_DEBUG)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Specifies that the rules used in validating addresses supplied to bind() should allow reuse of local
addresses, if this is supported by the protocol. This option takes an int value. This is a Boolean option.*/
if (optname == SO_REUSEADDR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Keeps connections active by enabling the periodic transmission of messages, if this is supported by the
protocol. This option takes an int value. */
if (optname == SO_KEEPALIVE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Requests that outgoing messages bypass the standard routing facilities. */
if (optname == SO_DONTROUTE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Lingers on a close() if data is present. */
if (optname == SO_LINGER)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Permits sending of broadcast messages, if this is supported by the protocol. This option takes an int
value. This is a Boolean option. */
if (optname == SO_BROADCAST)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Leaves received out-of-band data (data marked urgent) inline. This option takes an int value. This is a
Boolean option. */
if (optname == SO_OOBINLINE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets send buffer size. This option takes an int value. */
if (optname == SO_SNDBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Sets receive buffer size. This option takes an int value. */
if (optname == SO_RCVBUF)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_STYLE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* */
if (optname == SO_TYPE)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Get error status and clear */
if (optname == SO_ERROR)
{
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_IP)
{
if (optname == IP_ADD_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BIND_ADDRESS_NO_PORT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_BLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_DROP_SOURCE_MEMBERSHIP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_FREEBIND) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_HDRINCL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MSFILTER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MTU_DISCOVER) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_ALL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_IF) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_LOOP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_MULTICAST_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_NODEFRAG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_OPTIONS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_PKTINFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVORIGDSTADDR) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RECVTTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_RETOPTS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_ROUTER_ALERT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TOS) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TRANSPARENT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_TTL) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
if (optname == IP_UNBLOCK_SOURCE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
// TODO
return -1;
}
if (level == IPPROTO_TCP)
{
struct pico_socket *p = vs->picosock;
if (p == NULL) {
handle_general_failure();
return -1;
}
/* If set, don't send out partial frames. */
if (optname == TCP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Allow a listener to be awakened only when data arrives on the socket. */
if (optname == TCP_DEFER_ACCEPT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Used to collect information about this socket. */
if (optname == TCP_INFO) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum number of keepalive probes TCP should send before dropping the connection.*/
if (optname == TCP_KEEPCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes,
if the socket option SO_KEEPALIVE has been set on this socket. */
if (optname == TCP_KEEPIDLE) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The time (in seconds) between individual keepalive probes.*/
if (optname == TCP_KEEPINTVL) {
// TODO
return -1;
}
/* The lifetime of orphaned FIN_WAIT2 state sockets. */
if (optname == TCP_LINGER2) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* The maximum segment size for outgoing TCP packets. */
if (optname == TCP_MAXSEG) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* If set, disable the Nagle algorithm. */
if (optname == TCP_NODELAY) {
/*
TODO:
PICO TCP NODELAY - Nagle algorithm, value casted to (int *) (0 = disabled, 1 = enabled)
• PICO SOCKET OPT RCVBUF - Read current receive buffer size for the socket
• PICO SOCKET OPT SNDBUF - Read current receive buffer size for the socket
• PICO IP MULTICAST IF - (Not supported) Link multicast datagrams are sent from
• PICO IP MULTICAST TTL - TTL (0-255) of multicast datagrams
• PICO IP MULTICAST LOOP - Loop back a copy of an outgoing multicast datagram, as long
as it is a member of the multicast group, or not
*/
if ((err = pico_socket_getoption(p, PICO_TCP_NODELAY, &optval_tmp)) < 0) {
if (err == PICO_ERR_EINVAL) {
DEBUG_ERROR("error while disabling Nagle's algorithm");
errno = ENOPROTOOPT;
err = -1;
}
}
memcpy(optval, &optval_tmp, *optlen);
return err;
}
/* Enable quickack mode if set or disable quickack mode if cleared. */
if (optname == TCP_QUICKACK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Set the number of SYN retransmits that TCP should send before aborting the attempt to connect. It
cannot exceed 255. */
if (optname == TCP_SYNCNT) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
/* Bound the size of the advertised window to this value. The kernel imposes a minimum size of
SOCK_MIN_RCVBUF/2. */
if (optname == TCP_WINDOW_CLAMP) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
if (level == IPPROTO_UDP)
{
/*If this option is enabled, then all data output on this socket is accumulated into a single
datagram that is transmitted when the option is disabled. */
if (optname == UDP_CORK) {
// TODO
errno = ENOPROTOOPT;
return -1;
}
}
return err;
}
int picoTCP::map_pico_err_to_errno(int err) int picoTCP::map_pico_err_to_errno(int err)
{ {
if (err == PICO_ERR_NOERR) { errno = 0; return 0; } // if (err == PICO_ERR_NOERR) { errno = 0; return 0; } //

View File

@@ -150,7 +150,8 @@ namespace ZeroTier
/* /*
* Packets from the ZeroTier virtual wire enter the stack here * Packets from the ZeroTier virtual wire enter the stack here
*/ */
void pico_eth_rx(VirtualTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len); void pico_eth_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 "VirtualSocket object" * Creates a stack-specific "socket" or "VirtualSocket object"
@@ -180,7 +181,7 @@ namespace ZeroTier
/* /*
* Read from RX buffer to application - Called from VirtualTap * Read from RX buffer to application - Called from VirtualTap
*/ */
int pico_Read(VirtualTap *tap, ZeroTier::PhySocket *sock,VirtualSocket *vs,bool stack_invoked); int pico_Read(VirtualTap *tap, ZeroTier::PhySocket *sock, VirtualSocket *vs, bool stack_invoked);
/* /*
* Write to userspace network stack - Called from VirtualTap * Write to userspace network stack - Called from VirtualTap
@@ -197,6 +198,16 @@ namespace ZeroTier
*/ */
int pico_Shutdown(VirtualSocket *vs, int how); int pico_Shutdown(VirtualSocket *vs, int how);
/*
* Sets a property of a socket
*/
static int pico_setsockopt(VirtualSocket *vs, int level, int optname, const void *optval, socklen_t optlen);
/*
* Gets a property of a socket
*/
static int pico_getsockopt(VirtualSocket *vs, int level, int optname, void *optval, socklen_t *optlen);
/* /*
* Converts a pico_err to its most closely-related errno, and sets errno * Converts a pico_err to its most closely-related errno, and sets errno
*/ */