diff --git a/include/libzt.h b/include/libzt.h index 4cec3f1..2274b0d 100644 --- a/include/libzt.h +++ b/include/libzt.h @@ -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 *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) diff --git a/src/VirtualTap.cpp b/src/VirtualTap.cpp index 827f659..bc00a77 100644 --- a/src/VirtualTap.cpp +++ b/src/VirtualTap.cpp @@ -61,8 +61,6 @@ class VirtualTap; extern std::vector 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::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); } diff --git a/src/libzt.cpp b/src/libzt.cpp index bb30906..7d2cfbe 100644 --- a/src/libzt.cpp +++ b/src/libzt.cpp @@ -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*>::iterator fd_iter = ZeroTier::fdmap.find(fd); + std::map*>::iterator fd_iter; + fd_iter = ZeroTier::fdmap.find(fd); if (fd_iter == ZeroTier::fdmap.end()) { ZeroTier::fdmap[fd] = new std::pair(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*>::iterator fd_iter = ZeroTier::fdmap.find(fd); + std::map*>::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 *get_assigned_virtual return p; } -void dismantleTaps() +void disableTaps() { ZeroTier::_vtaps_lock.lock(); for(int i=0; i_enabled = false; } - ZeroTier::vtaps.clear(); ZeroTier::_vtaps_lock.unlock(); } diff --git a/src/lwIP.cpp b/src/lwIP.cpp index 8ee75bd..8f2290c 100644 --- a/src/lwIP.cpp +++ b/src/lwIP.cpp @@ -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; diff --git a/src/lwIP.hpp b/src/lwIP.hpp index 0a17e82..703d2ff 100644 --- a/src/lwIP.hpp +++ b/src/lwIP.hpp @@ -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); diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp index e0379dc..afa2b6b 100644 --- a/src/picoTCP.cpp +++ b/src/picoTCP.cpp @@ -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; } // diff --git a/src/picoTCP.hpp b/src/picoTCP.hpp index c080196..00b6c23 100644 --- a/src/picoTCP.hpp +++ b/src/picoTCP.hpp @@ -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 */