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
// 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 */
/****************************************************************************/
@@ -574,12 +610,12 @@ bool can_provision_new_socket(int socket_type);
* haven't passed that limit. Someday if multiple stacks are used simultaneously
* 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
*/
int zts_maxsockets();
int zts_maxsockets(int socket_type);
int pico_ntimers();
@@ -596,31 +632,31 @@ ZeroTier::VirtualTap *getAnyTap();
/*
* 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
*/
int del_virtual_socket(int fd);
int del_virt_socket(int fd);
/*
* 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
*/
int del_unassigned_virtual_socket(int fd);
int del_unassigned_virt_socket(int fd);
/*
* 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
*/
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)
@@ -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);
/*
* Destroys all virtual tap devices
* Disable all virtual tap devices
*/
void dismantleTaps();
void disableTaps();
/*
* Get device ID (from file)

View File

@@ -61,8 +61,6 @@ class VirtualTap;
extern std::vector<void*> vtaps;
// static bool picodev_initialized;
namespace ZeroTier {
int VirtualTap::devno = 0;
@@ -135,12 +133,18 @@ namespace ZeroTier {
if (picostack) {
picostack->pico_register_address(this, ip);
return true;
} else {
handle_general_failure();
return false;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
lwipstack->lwip_init_interface(this, ip);
return true;
} else {
handle_general_failure();
return false;
}
#endif
return false;
@@ -148,12 +152,13 @@ namespace ZeroTier {
bool VirtualTap::addIp(const InetAddress &ip)
{
int err = false;
#if defined(NO_STACK)
char ipbuf[INET6_ADDRSTRLEN];
DEBUG_INFO("addIp (%s)", ip.toString(ipbuf));
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
return true;
err = true;
#endif
#if defined(STACK_PICO) || defined(STACK_LWIP)
char ipbuf[INET6_ADDRSTRLEN];
@@ -165,16 +170,18 @@ namespace ZeroTier {
}
return true;
}
return false;
err = false;
#endif
return err;
}
bool VirtualTap::removeIp(const InetAddress &ip)
{
Mutex::Lock _l(_ips_m);
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (i == _ips.end())
if (i == _ips.end()) {
return false;
}
_ips.erase(i);
if (ip.isV4()) {
// FIXME: De-register from network stacks
@@ -197,11 +204,15 @@ namespace ZeroTier {
#if defined(STACK_PICO)
if (picostack) {
picostack->pico_eth_rx(this,from,to,etherType,data,len);
} else {
handle_general_failure();
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
lwipstack->lwip_eth_rx(this,from,to,etherType,data,len);
} else {
handle_general_failure();
}
#endif
}
@@ -257,9 +268,7 @@ namespace ZeroTier {
void VirtualTap::setMtu(unsigned int mtu)
{
if (_mtu != mtu) {
_mtu = mtu;
}
_mtu = mtu;
}
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)
picostack->pico_loop(this);
}
} else {
handle_general_failure();
}
#endif
#if defined(STACK_LWIP)
@@ -283,33 +294,37 @@ namespace ZeroTier {
#endif
}
void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr)
void VirtualTap::phyOnUnixClose(PhySocket *sock, void **uptr)
{
if (sock) {
VirtualSocket *vs = (VirtualSocket*)uptr;
if (vs) {
Close(vs);
}
} else {
handle_general_failure();
}
}
void VirtualTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
{
//DEBUG_ATTN("sock->fd=%d", _phy.getDescriptor(sock));
VirtualSocket *vs = (VirtualSocket*)*uptr;
if (vs == NULL) {
handle_general_failure();
return;
}
if (len > 0) {
Write(vs, data, len);
}
return;
}
void VirtualTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked)
{
if (sock)
if (sock) {
Read(sock,uptr,stack_invoked);
} else {
handle_general_failure();
}
}
// Adds a route to the virtual tap
@@ -321,11 +336,18 @@ namespace ZeroTier {
#if defined(STACK_PICO)
if (picostack) {
return picostack->pico_route_add(this, addr, nm, gw, 0);
} else {
handle_general_failure();
return false;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
// TODO
return true;
} else {
handle_general_failure();
return false;
}
#endif
return false;
@@ -340,11 +362,18 @@ namespace ZeroTier {
#if defined(STACK_PICO)
if (picostack) {
return picostack->pico_route_del(this, addr, nm, 0);
} else {
handle_general_failure();
return false;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
// TODO
return true;
} else {
handle_general_failure();
return false;
}
#endif
return false;
@@ -362,7 +391,6 @@ namespace ZeroTier {
for(int i=0; i<_VirtualSockets.size(); i++) {
if (vs == _VirtualSockets[i]) {
_VirtualSockets.erase(_VirtualSockets.begin() + i);
//DEBUG_EXTRA("Removed vs=%p from vt=%p", vs, this);
break;
}
}
@@ -375,22 +403,46 @@ namespace ZeroTier {
int VirtualTap::add_DNS_Nameserver(struct sockaddr *addr)
{
int err = -1;
#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
#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
return err;
}
int VirtualTap::del_DNS_Nameserver(struct sockaddr *addr)
{
int err = -1;
#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
#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
return err;
}
/****************************************************************************/
@@ -398,26 +450,35 @@ namespace ZeroTier {
/****************************************************************************/
// 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)
return -1;
return err;
#endif
#if defined(STACK_PICO)
if (picostack) {
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
#if defined(STACK_LWIP)
if (lwipstack) {
return lwipstack->lwip_Connect(vs, addr, addrlen);
err = lwipstack->lwip_Connect(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
}
#endif
return -1;
return err;
}
// 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)
return -1;
#endif
@@ -425,85 +486,111 @@ namespace ZeroTier {
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Bind(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Bind(this, vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
}
#endif
return -1;
}
// 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)
return -1;
return err;
#endif
#if defined(STACK_PICO)
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Listen(vs, backlog);
}
else {
return ZT_ERR_GENERAL_FAILURE;
} else {
handle_general_failure();
return err;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Listen(vs, backlog);
}
else {
return ZT_ERR_GENERAL_FAILURE;
err = lwipstack->lwip_Listen(vs, backlog);
} else {
handle_general_failure();
return err;
}
#endif
return err;
}
// Accept a VirtualSocket
VirtualSocket* VirtualTap::Accept(VirtualSocket *vs) {
VirtualSocket* VirtualTap::Accept(VirtualSocket *vs)
{
VirtualSocket *new_vs = NULL;
#if defined(NO_STACK)
return NULL;
new_vs = NULL;
#endif
#if defined(STACK_PICO)
// TODO: separation of church and state
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Accept(vs);
}
else {
new_vs = picostack->pico_Accept(vs);
} else {
handle_general_failure();
return NULL;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
Mutex::Lock _l(_tcpconns_m);
return lwipstack->lwip_Accept(vs);
}
else {
new_vs = lwipstack->lwip_Accept(vs);
} else {
handle_general_failure();
return NULL;
}
#endif
return new_vs;
}
// 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 (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
#if defined(STACK_LWIP)
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
return -1;
return err;
}
// 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
if (vs->socket_type == SOCK_RAW) {
struct ether_header *eh = (struct ether_header *) data;
@@ -516,15 +603,21 @@ namespace ZeroTier {
}
#if defined(STACK_PICO)
if (picostack) {
return picostack->pico_Write(vs, data, len);
err = picostack->pico_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
return lwipstack->lwip_Write(vs, data, len);
err = lwipstack->lwip_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
}
#endif
return -1;
return err;
}
// 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,
possibly consult the stack for "connection" state */
// TODO: flags
int err = 0;
int err = -1;
#if defined(STACK_PICO)
if (picostack) {
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
return err;
}
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
@@ -555,6 +650,9 @@ namespace ZeroTier {
if ((err = lwipstack->lwip_Write(vs, (void*)buf, len)) < 0) {
return err;
}
} else {
handle_general_failure();
return -1;
}
#endif
return err;
@@ -562,21 +660,29 @@ namespace ZeroTier {
// Remove VritualSocket from VirtualTap, and instruct network stacks to dismantle their
// respective protocol control structures
int VirtualTap::Close(VirtualSocket *vs) {
int VirtualTap::Close(VirtualSocket *vs)
{
int err = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid VirtualSocket");
handle_general_failure();
return -1;
}
removeVirtualSocket(vs);
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_Close(vs);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Close(vs);
} else {
handle_general_failure();
return -1;
}
#endif
if (vs->sock) {
@@ -592,11 +698,17 @@ namespace ZeroTier {
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_Shutdown(vs, how);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Shutdown(vs, how);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
@@ -660,7 +772,6 @@ namespace ZeroTier {
}
}
}
// TODO: Clean up VirtualSocket objects
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() {
if (ZeroTier::zt1Service) {
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) {
if (ZeroTier::homeDir.length()) {
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_type = socket_type;
vs->protocol = protocol;
add_unassigned_virtual_socket(vs->app_fd, vs);
add_unassigned_virt_socket(vs->app_fd, vs);
return vs->app_fd;
}
#if defined(STACK_PICO)
@@ -425,7 +426,7 @@ int zts_socket(ZT_SOCKET_SIG) {
vs->socket_family = socket_family;
vs->socket_type = socket_type;
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
}
else {
@@ -443,7 +444,7 @@ int zts_socket(ZT_SOCKET_SIG) {
vs->socket_family = socket_family;
vs->socket_type = socket_type;
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
err = vs->app_fd;
}
@@ -523,7 +524,7 @@ int zts_connect(ZT_CONNECT_SIG) {
errno = EBADF;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid socket, unable to locate VirtualSocket for fd=%d", fd);
errno = EBADF;
@@ -570,8 +571,8 @@ int zts_connect(ZT_CONNECT_SIG) {
vs->sock = tap->_phy.wrapSocket(vs->sdk_fd, vs);
// TODO: Consolidate these calls
del_unassigned_virtual_socket(fd);
add_assigned_virtual_socket(tap, vs, fd);
del_unassigned_virt_socket(fd);
add_assigned_virt_socket(tap, vs, fd);
// save peer addr, for calls like getpeername
memcpy(&(vs->peer_addr), addr, sizeof(vs->peer_addr));
@@ -652,7 +653,7 @@ int zts_bind(ZT_BIND_SIG) {
errno = EBADF;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("no VirtualSocket for fd=%d", fd);
errno = ENOTSOCK;
@@ -704,8 +705,8 @@ int zts_bind(ZT_BIND_SIG) {
err = tap->Bind(vs, addr, addrlen);
if (err == 0) { // success
vs->tap = tap;
del_unassigned_virtual_socket(fd);
add_assigned_virtual_socket(tap, vs, fd);
del_unassigned_virt_socket(fd);
add_assigned_virt_socket(tap, vs, fd);
}
return err;
}
@@ -827,7 +828,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
}
}
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;
}
}
@@ -908,43 +909,42 @@ int zts_accept4(ZT_ACCEPT4_SIG)
this error may also be returned if optlen is not in a
valid part of the process address space.
[ ] [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)
{
// TODO: Move stack-specific logic into stack driver section
//DEBUG_INFO("fd=%d", fd);
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname);
int err = errno = 0;
if (fd < 0 || fd >= ZT_MAX_SOCKETS) {
errno = EBADF;
return -1;
}
#if defined(STACK_PICO)
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid fd=%d", fd);
errno = EBADF;
return -1;
}
struct pico_socket *p = vs->picosock;
if (p) {
// Disable Nagle's algorithm
int value = 1;
if ((err = pico_socket_setoption(p, PICO_TCP_NODELAY, &value)) < 0) {
if (err == PICO_ERR_EINVAL) {
DEBUG_ERROR("error while disabling Nagle's algorithm");
errno = ENOPROTOOPT;
return -1;
}
}
#if defined(STACK_PICO)
if (ZeroTier::picostack) {
err = ZeroTier::picostack->pico_setsockopt(vs, level, optname, optval, optlen);
} else {
handle_general_failure();
// TODO: errno?
err = -1;
}
err = setsockopt(fd, level, optname, optval, optlen);
return err;
#endif
#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
return 0;
return err;
}
/*
@@ -960,12 +960,36 @@ int zts_setsockopt(ZT_SETSOCKOPT_SIG)
*/
int zts_getsockopt(ZT_GETSOCKOPT_SIG)
{
DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname);
int err = errno = 0;
if (fd < 0 || fd >= ZT_MAX_SOCKETS) {
errno = EBADF;
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;
}
@@ -1008,7 +1032,7 @@ int zts_getpeername(ZT_GETPEERNAME_SIG)
errno = EBADF;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
errno = ENOTCONN;
return -1;
@@ -1083,14 +1107,14 @@ int zts_close(ZT_CLOSE_SIG)
errno = EBADF;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("no vs found for fd=%d", fd);
handle_general_failure();
errno = EBADF;
return -1;
}
del_virtual_socket(fd);
del_virt_socket(fd);
if (vs->tap) {
vs->tap->Close(vs);
}
@@ -1231,7 +1255,7 @@ ssize_t zts_sendto(ZT_SENDTO_SIG)
errno = EINVAL;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("no vs found for fd=%x", fd);
handle_general_failure();
@@ -1356,7 +1380,7 @@ ssize_t zts_send(ZT_SEND_SIG)
errno = EMSGSIZE;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF;
@@ -1468,7 +1492,7 @@ ssize_t zts_recv(ZT_RECV_SIG)
errno = EBADF;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF;
@@ -1671,7 +1695,7 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
errno = EINVAL;
return -1;
}
ZeroTier::VirtualSocket *vs = get_virtual_socket(fd);
ZeroTier::VirtualSocket *vs = get_virt_socket(fd);
if (vs == NULL) {
DEBUG_ERROR("invalid vs for fd=%d", fd);
errno = EBADF;
@@ -1855,7 +1879,8 @@ namespace ZeroTier {
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);
char * bufp = (char *)malloc(sizeof(char)*len);
@@ -1865,7 +1890,8 @@ namespace ZeroTier {
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);
int read_bytes = read(fd, body, len);
@@ -1874,19 +1900,23 @@ namespace ZeroTier {
}
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);
}
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);
}
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);
}
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;
const char *str = (*env).GetStringUTFChars( addrstr, 0);
addr.sin_addr.s_addr = inet_addr(str);
@@ -1896,7 +1926,8 @@ namespace ZeroTier {
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;
const char *str = (*env).GetStringUTFChars( addrstr, 0);
DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port);
@@ -1908,7 +1939,8 @@ namespace ZeroTier {
}
#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;
char *str;
// = env->GetStringUTFChars(addrstr, NULL);
@@ -1920,7 +1952,8 @@ namespace ZeroTier {
}
#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;
// TODO: Send addr info back to Javaland
addr.sin_addr.s_addr = inet_addr("");
@@ -1929,15 +1962,18 @@ namespace ZeroTier {
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);
}
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);
}
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;
int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
jfieldID fid;
@@ -1949,7 +1985,8 @@ namespace ZeroTier {
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;
int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
jfieldID fid;
@@ -1961,7 +1998,8 @@ namespace ZeroTier {
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);
}
}
@@ -1973,6 +2011,7 @@ namespace ZeroTier {
bool can_provision_new_socket(int socket_type)
{
int can = false;
#if defined(STACK_PICO)
return !(pico_ntimers()+1 > PICO_MAX_TIMERS);
#endif
@@ -1986,15 +2025,16 @@ bool can_provision_new_socket(int socket_type)
if (socket_type == SOCK_RAW) {
return !(ZeroTier::lwIP::lwip_num_current_raw_pcbs()+1 > MEMP_NUM_RAW_PCB);
}
return true;
can = true;
#endif
#if defined(NO_STACK)
// always true since there's no network stack timer/memory limitation
return true;
can = true;
#endif
return can;
}
int zts_nsockets()
int zts_num_active_virt_sockets()
{
ZeroTier::_multiplexer_lock.lock();
int num = ZeroTier::unmap.size() + ZeroTier::fdmap.size();
@@ -2002,18 +2042,32 @@ int zts_nsockets()
return num;
}
int zts_maxsockets()
int zts_maxsockets(int socket_type)
{
int max = 0;
#if defined(STACK_PICO)
// TODO: This is only an approximation
return PICO_MAX_TIMERS - 10;
// TODO: distinquish by type
max = PICO_MAX_TIMERS - 10;
#endif
#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
#if defined(NO_STACK)
return 1024; // arbitrary
// arbitrary
#if defined(__linux__)
max = RLIMIT_NOFILE;
#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 */
/****************************************************************************/
ZeroTier::VirtualSocket *get_virtual_socket(int fd)
ZeroTier::VirtualSocket *get_virt_socket(int fd)
{
ZeroTier::_multiplexer_lock.lock();
// try to locate in unmapped set
@@ -2143,7 +2197,7 @@ ZeroTier::VirtualSocket *get_virtual_socket(int fd)
return vs;
}
int del_virtual_socket(int fd)
int del_virt_socket(int fd)
{
int err = 0;
ZeroTier::_multiplexer_lock.lock();
@@ -2166,7 +2220,7 @@ int del_virtual_socket(int fd)
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;
ZeroTier::_multiplexer_lock.lock();
@@ -2189,7 +2243,7 @@ int add_unassigned_virtual_socket(int fd, ZeroTier::VirtualSocket *vs)
return err;
}
int del_unassigned_virtual_socket(int fd)
int del_unassigned_virt_socket(int fd)
{
int err = 0;
ZeroTier::_multiplexer_lock.lock();
@@ -2208,12 +2262,13 @@ int del_unassigned_virtual_socket(int fd)
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;
ZeroTier::_multiplexer_lock.lock();
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()) {
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;
}
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;
ZeroTier::_multiplexer_lock.lock();
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()) {
ZeroTier::fdmap.erase(fd_iter);
}
@@ -2258,15 +2314,13 @@ std::pair<ZeroTier::VirtualSocket*, ZeroTier::VirtualTap*> *get_assigned_virtual
return p;
}
void dismantleTaps()
void disableTaps()
{
ZeroTier::_vtaps_lock.lock();
for(int i=0; i<ZeroTier::vtaps.size(); i++) {
DEBUG_ERROR("ZeroTier::vtapsf[i]=%p", ZeroTier::vtaps[i]);
delete (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
ZeroTier::vtaps[i] = NULL;
DEBUG_EXTRA("vt=%p", ZeroTier::vtaps[i]);
((ZeroTier::VirtualTap*)ZeroTier::vtaps[i])->_enabled = false;
}
ZeroTier::vtaps.clear();
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);
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];
memset(&flagbuf, 0, 32);
char macBuf[ZT_MAC_ADDRSTRLEN], nodeBuf[ZT_ID_LEN];
@@ -333,7 +333,11 @@ namespace ZeroTier
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];
memset(&flagbuf, 0, 32);
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(),
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 (tap->lwipdev.input(p, &(tap->lwipdev)) != ERR_OK) {
@@ -658,12 +658,12 @@ namespace ZeroTier
if (vs->pcb) {
struct tcp_pcb* tpcb = (struct tcp_pcb*)vs->pcb;
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
return 0;
}
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
}
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)
{
DEBUG_ATTN("pcb=%p", PCB);
DEBUG_EXTRA("pcb=%p", PCB);
VirtualSocket *vs = (VirtualSocket *)arg;
if (vs == NULL) {
DEBUG_ERROR("invalid virtual socket");
@@ -994,6 +994,690 @@ namespace ZeroTier
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)
{
VirtualSocket *vs = (VirtualSocket *)arg;

View File

@@ -287,6 +287,16 @@ namespace ZeroTier {
*/
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 ---
//static void netif_status_callback(struct netif *nif);

View File

@@ -564,7 +564,7 @@ namespace ZeroTier {
MAC dest_mac;
src_mac.setTo(ethhdr->saddr, 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];
mac2str(macBuf, ZT_MAC_ADDRSTRLEN, ethhdr->daddr);
ZeroTier::MAC mac;
@@ -641,7 +641,7 @@ namespace ZeroTier {
ethhdr.proto = Utils::hton((uint16_t)etherType);
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];
mac2str(macBuf, sizeof(macBuf), ethhdr.saddr);
ZeroTier::MAC mac;
@@ -716,8 +716,11 @@ namespace ZeroTier {
// get frame len
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
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
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
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 (picostack) {
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 {
int protocol_version = 0;
struct pico_socket *psock;
if (socket_family == AF_INET)
if (socket_family == AF_INET) {
protocol_version = PICO_PROTO_IPV4;
if (socket_family == AF_INET6)
}
if (socket_family == AF_INET6) {
protocol_version = PICO_PROTO_IPV6;
}
if (socket_type == SOCK_DGRAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_ev);
psock = pico_socket_open(protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_ev);
if (psock) {
// configure size of UDP SND/RCV buffers
// TODO
}
}
if (socket_type == SOCK_STREAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_ev);
psock = pico_socket_open(protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_ev);
if (psock) {
// configure size of TCP SND/RCV buffers
int tx_buf_sz = ZT_STACK_TCP_SOCKET_TX_SZ;
int rx_buf_sz = ZT_STACK_TCP_SOCKET_RX_SZ;
int t_err = 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)
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",
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",
t_err, pico_err, beautify_pico_error(pico_err));
}
/*
if (ZT_SOCK_BEHAVIOR_LINGER) {
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",
t_err, pico_err, beautify_pico_error(pico_err));
}
}
*/
}
}
*p = psock;
@@ -1024,6 +1026,727 @@ namespace ZeroTier {
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)
{
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
*/
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"
@@ -180,7 +181,7 @@ namespace ZeroTier
/*
* 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
@@ -197,6 +198,16 @@ namespace ZeroTier
*/
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
*/