BSD-license-compatible, and NO_STACK build variants

This commit is contained in:
Joseph Henry
2017-07-25 23:40:24 -07:00
parent bb60904899
commit 4e36fe28d5
279 changed files with 113515 additions and 228 deletions

View File

@@ -24,6 +24,8 @@
* of your own application.
*/
// General connection object used by SocketTap and network stack drivers
#ifndef ZT_CONNECTION_HPP
#define ZT_CONNECTION_HPP
@@ -31,7 +33,9 @@
#include <sys/socket.h>
// picoTCP
#include "pico_socket.h"
#if defined(STACK_PICO)
#include "pico_socket.h"
#endif
// ZT
#include "Phy.hpp"
@@ -42,10 +46,9 @@
#include "RingBuffer.hpp"
namespace ZeroTier {
class SocketTap;
/*
* Connection object
*/
struct Connection
{
int tot = 0;
@@ -54,20 +57,25 @@ namespace ZeroTier {
Mutex _tx_m, _rx_m;
PhySocket *sock;
struct pico_socket *picosock;
PhySocket *sock;
#if defined(STACK_PICO)
struct pico_socket *picosock;
#endif
#if defined(STACK_LWIP)
void *pcb;
#endif
// TODO: For getsockname, etc
struct sockaddr_storage *local_addr; // Address we've bound to locally
struct sockaddr_storage *peer_addr; // Address of connection call to remote host
int socket_family, socket_type;
int app_fd; // provided to app for I/O
int sdk_fd; // provided to SDK for I/O
int app_fd; // used by app for I/O
int sdk_fd; // used by lib for I/O
std::queue<Connection*> _AcceptedConnections;
SocketTap *tap; // Reference to SocketTap
SocketTap *tap;
int state; // See libzt.h for (ZT_SOCK_STATE_*)
// timestamp for closure event

View File

@@ -35,7 +35,14 @@
// SDK
#include "SocketTap.hpp"
#include "libzt.h"
#include "picoTCP.hpp"
// stack drivers
#if defined(STACK_PICO)
#include "picoTCP.hpp"
#endif
#if defined(STACK_LWIP)
#include "lwIP.hpp"
#endif
// ZT
#include "Utils.hpp"
@@ -98,26 +105,22 @@ namespace ZeroTier {
bool SocketTap::registerIpWithStack(const InetAddress &ip)
{
if(picostack) {
if(ip.isV4())
{
#if defined(SDK_IPV4)
//DEBUG_INFO("addr = %s", ip.toString().c_str());
picostack->pico_init_interface(this, ip);
_ips.push_back(ip);
#endif
}
if(ip.isV6())
{
#if defined(SDK_IPV6)
//DEBUG_INFO("addr = %s", ip.toString().c_str());
picostack->pico_init_interface(this, ip);
_ips.push_back(ip);
#endif
}
#if defined(STACK_PICO)
if(picostack){
picostack->pico_init_interface(this, ip);
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
return true;
}
#endif
#if defined(STACK_LWIP)
if(lwipstack){
lwipstack->lwip_init_interface(this, ip);
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
return true;
}
#endif
return false;
}
@@ -158,9 +161,14 @@ namespace ZeroTier {
void SocketTap::put(const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
// RX packet
#if defined(STACK_PICO)
if(picostack)
picostack->pico_rx(this, from,to,etherType,data,len);
picostack->pico_rx(this,from,to,etherType,data,len);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
lwipstack->lwip_rx(this,from,to,etherType,data,len);
#endif
}
std::string SocketTap::deviceName() const
@@ -206,8 +214,14 @@ namespace ZeroTier {
void SocketTap::threadMain()
throw()
{
#if defined(STACK_PICO)
if(picostack)
picostack->pico_loop(this);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
lwipstack->lwip_loop(this);
#endif
}
void SocketTap::phyOnUnixClose(PhySocket *sock,void **uptr)
@@ -235,7 +249,6 @@ namespace ZeroTier {
void SocketTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool stack_invoked)
{
DEBUG_INFO();
//exit(0);
if(sock)
Read(sock,uptr,stack_invoked);
}
@@ -246,45 +259,68 @@ namespace ZeroTier {
int SocketTap::Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) {
Mutex::Lock _l(_tcpconns_m);
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Connect(conn, fd, addr, addrlen);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Connect(conn, fd, addr, addrlen);
#endif
return ZT_ERR_GENERAL_FAILURE;
}
int SocketTap::Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) {
Mutex::Lock _l(_tcpconns_m);
#if defined(STACK_PICO)
if(picostack)
return picostack->pico_Bind(conn, fd, addr, addrlen);
#endif
#if defined(STACK_LWIP)
if(lwipstack)
return lwipstack->lwip_Bind(this, conn, fd, addr, addrlen);
#endif
return ZT_ERR_GENERAL_FAILURE;
}
int SocketTap::Listen(Connection *conn, int fd, int backlog) {
#if defined(STACK_PICO)
Mutex::Lock _l(_tcpconns_m);
if(picostack)
return picostack->pico_Listen(conn, fd, backlog);
return ZT_ERR_GENERAL_FAILURE;
#endif
return ZT_ERR_GENERAL_FAILURE;
}
Connection* SocketTap::Accept(Connection *conn) {
#if defined(STACK_PICO)
Mutex::Lock _l(_tcpconns_m);
if(picostack)
return picostack->pico_Accept(conn);
return NULL;
#endif
return NULL;
}
void SocketTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) {
#if defined(STACK_PICO)
DEBUG_INFO();
if(picostack)
picostack->pico_Read(this, sock, (Connection*)uptr, stack_invoked);
#endif
}
void SocketTap::Write(Connection *conn, void *data, ssize_t len) {
#if defined(STACK_PICO)
//DEBUG_INFO();
if(picostack)
picostack->pico_Write(conn, data, len);
#endif
}
void SocketTap::Close(Connection *conn) {
#if defined(STACK_PICO)
if(!conn) {
DEBUG_ERROR("invalid connection");
return;
@@ -321,10 +357,12 @@ namespace ZeroTier {
break;
}
}
#endif
}
void SocketTap::Housekeeping()
{
#if defined(STACK_PICO)
Mutex::Lock _l(_tcpconns_m);
std::time_t current_ts = std::time(nullptr);
if(current_ts > last_housekeeping_ts + ZT_HOUSEKEEPING_INTERVAL) {
@@ -338,6 +376,7 @@ namespace ZeroTier {
}
last_housekeeping_ts = std::time(nullptr);
}
#endif
}
/****************************************************************************/

View File

@@ -44,9 +44,10 @@
#include "Phy.hpp"
#include "libzt.h"
#include "picoTCP.hpp"
#include "Connection.hpp"
#if defined(STACK_PICO)
#include "picoTCP.hpp"
#include "pico_protocol.h"
#include "pico_stack.h"
#include "pico_ipv4.h"
@@ -55,6 +56,10 @@
#include "pico_protocol.h"
#include "pico_device.h"
#include "pico_ipv6.h"
#endif
#if defined(STACK_LWIP)
#include "lwIP.hpp"
#endif
namespace ZeroTier {
@@ -154,9 +159,30 @@ namespace ZeroTier {
/* Vars */
/****************************************************************************/
#if defined(STACK_PICO)
/*
* Whether our picoTCP device has been initialized
*/
bool picodev_initialized = false;
struct pico_device *picodev;
struct pico_device *picodev6;
/****************************************************************************/
/* Guarded RX Frame Buffer for picoTCP */
/****************************************************************************/
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
int pico_frame_rxbuf_tot;
Mutex _pico_frame_rxbuf_m;
#endif
#if defined(STACK_LWIP)
netif lwipdev;
netif lwipdev6;
#endif
std::vector<InetAddress> ips() const;
std::vector<InetAddress> _ips;
@@ -185,19 +211,6 @@ namespace ZeroTier {
*/
std::time_t last_housekeeping_ts;
/*
* Whether our picoTCP device has been initialized
*/
bool picodev_initialized = false;
/****************************************************************************/
/* Guarded RX Frame Buffer for picoTCP */
/****************************************************************************/
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
int pico_frame_rxbuf_tot;
Mutex _pico_frame_rxbuf_m;
/****************************************************************************/
/* In these, we will call the stack's corresponding functions, this is */
/* where one would put logic to select between different stacks */

View File

@@ -24,12 +24,35 @@
* of your own application.
*/
#ifndef SDK_UTILITIES_HPP
#define SDK_UTILITIES_HPP
#ifndef UTILITIES_HPP
#define UTILITIES_HPP
/*
* Print a stacktrace
*/
// void zt_dump_stacktrace(int sig);
#if defined(STACK_LWIP) && defined(LIBZT_IPV4)
#include "lwip/ip_addr.h"
#include <netinet/in.h>
#define ip4_addr1b(ipaddr) (((u8_t*)(ipaddr))[0])
#define ip4_addr2b(ipaddr) (((u8_t*)(ipaddr))[1])
#define ip4_addr3b(ipaddr) (((u8_t*)(ipaddr))[2])
#define ip4_addr4b(ipaddr) (((u8_t*)(ipaddr))[3])
inline ip_addr_t convert_ip(struct sockaddr_in * addr)
{
ip_addr_t conn_addr;
struct sockaddr_in *ipv4 = addr;
short a = ip4_addr1b(&(ipv4->sin_addr));
short b = ip4_addr2b(&(ipv4->sin_addr));
short c = ip4_addr3b(&(ipv4->sin_addr));
short d = ip4_addr4b(&(ipv4->sin_addr));
IP4_ADDR(&conn_addr, a,b,c,d);
return conn_addr;
}
#endif
#endif

View File

@@ -43,7 +43,12 @@ for applications to use. See also: include/libzt.h */
#include <poll.h>
// stack
#include "pico_stack.h"
#if defined(STACK_PICO)
#include "pico_stack.h"
#endif
#if defined(STACK_LWIP)
#include "lwIP.hpp"
#endif
// ZT
#include "OneService.hpp"
@@ -69,7 +74,12 @@ namespace ZeroTier {
/*
* Global reference to stack
*/
#if defined(STACK_PICO)
picoTCP *picostack = NULL;
#endif
#if defined(STACK_LWIP)
lwIP *lwipstack = NULL;
#endif
/*
* "sockets" that have been created but not bound to a SocketTap interface yet
@@ -93,13 +103,16 @@ void zts_start(const char *path)
{
if(zt1Service)
return;
#if defined(STACK_PICO)
if(ZeroTier::picostack)
return;
ZeroTier::picostack = new ZeroTier::picoTCP();
pico_stack_init();
//DEBUG_INFO("path=%s", path);
#endif
#if defined(STACK_LWIP)
ZeroTier::lwipstack = new ZeroTier::lwIP();
lwip_init();
#endif
if(path)
ZeroTier::homeDir = path;
pthread_t service_thread;
@@ -354,7 +367,6 @@ int zts_socket(ZT_SOCKET_SIG) {
errno = EINVAL;
return -1;
}
//DEBUG_INFO();
int err = 0;
if(!zt1Service) {
DEBUG_ERROR("cannot create socket, no service running. call zts_start() first.");
@@ -366,66 +378,44 @@ int zts_socket(ZT_SOCKET_SIG) {
errno = EPROTONOSUPPORT; // seemingly closest match
return -1;
}
ZeroTier::_multiplexer_lock.lock();
if(pico_ntimers() >= PICO_MAX_TIMERS) {
DEBUG_ERROR("cannot provision additional socket due to limitation of PICO_MAX_TIMERS. current = %d", pico_ntimers());
errno = EMFILE;
#if defined(STACK_PICO)
struct pico_socket *p;
err = ZeroTier::picostack->pico_Socket(&p, socket_family, socket_type, protocol);
if(p) {
ZeroTier::Connection *conn = new ZeroTier::Connection();
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->picosock = p;
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create pico_socket");
err = -1;
}
else
{
#endif
#if defined(STACK_LWIP)
// TODO: check for max lwIP timers/sockets
ZeroTier::Connection *conn = new ZeroTier::Connection();
void *pcb;
err = ZeroTier::lwipstack->lwip_Socket(&pcb, socket_family, socket_type, protocol);
if(pcb) {
ZeroTier::Connection *conn = new ZeroTier::Connection();
int protocol_version = 0;
struct pico_socket *psock;
if(socket_family == AF_INET)
protocol_version = PICO_PROTO_IPV4;
if(socket_family == AF_INET6)
protocol_version = PICO_PROTO_IPV6;
if(socket_type == SOCK_DGRAM) {
psock = pico_socket_open(
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
if(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_activity);
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)
DEBUG_ERROR("unable to set SNDBUF size, err = %d, pico_err = %d", t_err, pico_err);
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", t_err, 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)
DEBUG_ERROR("unable to set LINGER, err = %d, pico_err = %d", t_err, pico_err);
}
}
}
if(psock) {
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->picosock = psock;
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
}
else {
//DEBUG_ERROR("failed to create pico_socket");
err = -1;
}
conn->socket_family = socket_family;
conn->socket_type = socket_type;
conn->pcb = pcb;
ZeroTier::unmap[conn->app_fd] = conn;
err = conn->app_fd; // return one end of the socketpair
}
else {
DEBUG_ERROR("failed to create lwip pcb");
err = -1;
}
#endif
ZeroTier::_multiplexer_lock.unlock();
return err;
}
@@ -485,6 +475,7 @@ Linux:
*/
int zts_connect(ZT_CONNECT_SIG) {
#if defined(STACK_PICO)
//DEBUG_INFO("fd = %d", fd);
int err = 0;
if(fd < 0) {
@@ -604,6 +595,8 @@ int zts_connect(ZT_CONNECT_SIG) {
}
}
return err;
#endif
return 0;
}
/*
@@ -636,13 +629,11 @@ int zts_bind(ZT_BIND_SIG) {
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
ZeroTier::SocketTap *tap;
if(conn) {
char ipstr[INET6_ADDRSTRLEN]; //, nm_str[INET6_ADDRSTRLEN];
if(conn) {
char ipstr[INET6_ADDRSTRLEN];
memset(ipstr, 0, INET6_ADDRSTRLEN);
ZeroTier::InetAddress iaddr;
int port = 0;
if(conn->socket_family == AF_INET) {
inet_ntop(AF_INET,
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
@@ -662,16 +653,28 @@ int zts_bind(ZT_BIND_SIG) {
errno = EADDRNOTAVAIL;
err = -1;
}
#if defined(STACK_PICO)
else {
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
err = tap->Bind(conn, fd, addr, addrlen); // Semantically: tap->stack->connect
err = tap->Bind(conn, fd, addr, addrlen);
conn->tap = tap;
if(err == 0) { // success
ZeroTier::unmap.erase(fd);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
}
}
#endif
#if defined(STACK_LWIP)
else {
tap->_Connections.push_back(conn);
err = tap->Bind(conn, fd, addr, addrlen);
if(err == 0) { // success
ZeroTier::unmap.erase(fd);
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
}
}
#endif
}
else {
DEBUG_ERROR("unable to locate connection");
@@ -701,6 +704,7 @@ Linux:
[ ] [EOPNOTSUPP] The socket is not of a type that supports the listen() operation.
*/
int zts_listen(ZT_LISTEN_SIG) {
#if defined(STACK_PICO)
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
@@ -733,6 +737,8 @@ int zts_listen(ZT_LISTEN_SIG) {
ZeroTier::_multiplexer_lock.unlock();
}
return err;
#endif
return 0;
}
/*
@@ -750,6 +756,7 @@ Darwin:
[ ] [ENFILE] The system file table is full.
*/
int zts_accept(ZT_ACCEPT_SIG) {
#if defined(STACK_PICO)
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
@@ -809,6 +816,8 @@ int zts_accept(ZT_ACCEPT_SIG) {
ZeroTier::_multiplexer_lock.unlock();
}
return err;
#endif
return 0;
}
@@ -860,6 +869,7 @@ EPERM Firewall rules forbid connection.
*/
int zts_setsockopt(ZT_SETSOCKOPT_SIG)
{
#if defined(STACK_PICO)
DEBUG_INFO("fd = %d", fd);
int err = 0;
if(fd < 0) {
@@ -883,6 +893,8 @@ int zts_setsockopt(ZT_SETSOCKOPT_SIG)
}
err = setsockopt(fd, level, optname, optval, optlen);
return err;
#endif
return 0;
}
/*
@@ -964,6 +976,7 @@ Linux / Darwin:
int zts_close(ZT_CLOSE_SIG)
{
#if defined(STACK_PICO)
DEBUG_EXTRA("fd = %d", fd);
int err = 0;
if(fd < 0) {
@@ -1063,6 +1076,8 @@ int zts_close(ZT_CLOSE_SIG)
}
}
return err;
#endif
return 0;
}
int zts_poll(ZT_POLL_SIG)
@@ -1161,6 +1176,7 @@ int zts_write(ZT_WRITE_SIG) {
int zts_shutdown(ZT_SHUTDOWN_SIG)
{
#if defined(STACK_PICO)
DEBUG_INFO("fd = %d", fd);
int err = 0, mode = 0;
@@ -1237,6 +1253,8 @@ int zts_shutdown(ZT_SHUTDOWN_SIG)
}
}
return err;
#endif
return 0;
}
/****************************************************************************/
@@ -1311,7 +1329,7 @@ namespace ZeroTier {
jstring _str = (*env).NewStringUTF(address_string);
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
return addresses;
}
}
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv6_1address(
JNIEnv *env, jobject thisObj, jstring nwid)
@@ -1325,7 +1343,7 @@ namespace ZeroTier {
jstring _str = (*env).NewStringUTF(address_string);
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
return addresses;
}
}
// Returns the device is in integer form
JNIEXPORT jint Java_zerotier_ZeroTier_ztjni_1get_1device_1id()
@@ -1501,45 +1519,47 @@ namespace ZeroTier {
/* SDK Socket API Helper functions --- DON'T CALL THESE DIRECTLY */
/****************************************************************************/
int zts_get_pico_socket(int fd, struct pico_socket *s)
{
int err = 0;
if(!zt1Service) {
DEBUG_ERROR("cannot shutdown socket. service not started. call zts_start(path) first");
errno = EBADF;
err = -1;
}
else
#if defined(STACK_PICO)
int zts_get_pico_socket(int fd, struct pico_socket *s)
{
ZeroTier::_multiplexer_lock.lock();
// First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
// Since we found an unassigned connection, we don't need to consult the stack or tap
// during closure - it isn't yet stitched into the clockwork
if(conn)
{
s = conn->picosock;
return 1; // unassigned
int err = 0;
if(!zt1Service) {
DEBUG_ERROR("cannot shutdown socket. service not started. call zts_start(path) first");
errno = EBADF;
err = -1;
}
else // assigned
else
{
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
if(!p)
ZeroTier::_multiplexer_lock.lock();
// First, look for for unassigned connections
ZeroTier::Connection *conn = ZeroTier::unmap[fd];
// Since we found an unassigned connection, we don't need to consult the stack or tap
// during closure - it isn't yet stitched into the clockwork
if(conn)
{
DEBUG_ERROR("unable to locate connection pair.");
errno = EBADF;
err = -1;
s = conn->picosock;
return 1; // unassigned
}
else // found everything, begin closure
else // assigned
{
s = p->first->picosock;
return 0;
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
if(!p)
{
DEBUG_ERROR("unable to locate connection pair.");
errno = EBADF;
err = -1;
}
else // found everything, begin closure
{
s = p->first->picosock;
return 0;
}
}
ZeroTier::_multiplexer_lock.unlock();
}
ZeroTier::_multiplexer_lock.unlock();
return err;
}
return err;
}
#endif
int zts_nsockets()
{
@@ -1551,8 +1571,11 @@ int zts_nsockets()
int zts_maxsockets()
{
#if defined(STACK_PICO)
// TODO: This is only an approximation
return PICO_MAX_TIMERS - 10;
#endif
return 32;
}
// Starts a ZeroTier service in the background
@@ -1618,7 +1641,7 @@ void *zts_start_service(void *thread_id) {
ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.public").c_str());
}
}
}
continue; // restart!
}
break; // terminate loop -- normally we don't keep restarting

393
src/lwIP.cpp Normal file
View File

@@ -0,0 +1,393 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
// lwIP network stack driver
#include "libzt.h"
#include "SocketTap.hpp"
#include "Utilities.hpp"
#include "lwIP.hpp"
#include "netif/ethernet.h"
#include "lwip/etharp.h"
err_t tapif_init(struct netif *netif)
{
DEBUG_INFO();
return ERR_OK;
}
err_t low_level_output(struct netif *netif, struct pbuf *p)
{
DEBUG_INFO();
struct pbuf *q;
char buf[ZT_MAX_MTU+32];
char *bufptr;
int totalLength = 0;
ZeroTier::SocketTap *tap = (ZeroTier::SocketTap*)netif->state;
bufptr = buf;
// Copy data from each pbuf, one at a time
for(q = p; q != NULL; q = q->next) {
memcpy(bufptr, q->payload, q->len);
bufptr += q->len;
totalLength += q->len;
}
// Split ethernet header and feed into handler
struct eth_hdr *ethhdr;
ethhdr = (struct eth_hdr *)buf;
ZeroTier::MAC src_mac;
ZeroTier::MAC dest_mac;
src_mac.setTo(ethhdr->src.addr, 6);
dest_mac.setTo(ethhdr->dest.addr, 6);
tap->_handler(tap->_arg,NULL,tap->_nwid,src_mac,dest_mac,
ZeroTier::Utils::ntoh((uint16_t)ethhdr->type),0,buf + sizeof(struct eth_hdr),totalLength - sizeof(struct eth_hdr));
return ERR_OK;
}
namespace ZeroTier
{
void lwIP::lwip_init_interface(SocketTap *tap, const InetAddress &ip)
{
DEBUG_INFO();
Mutex::Lock _l(tap->_ips_m);
if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) {
tap->_ips.push_back(ip);
std::sort(tap->_ips.begin(),tap->_ips.end());
#if defined(LIBZT_IPV4)
if (ip.isV4()) {
// Set IP
static ip_addr_t ipaddr, netmask, gw;
IP4_ADDR(&gw,127,0,0,1);
ipaddr.addr = *((u32_t *)ip.rawIpData());
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
netif_add(&(tap->lwipdev),&ipaddr, &netmask, &gw, NULL, tapif_init, ethernet_input);
tap->lwipdev.state = tap;
tap->lwipdev.output = etharp_output;
tap->_mac.copyTo(tap->lwipdev.hwaddr, 6);
tap->lwipdev.mtu = tap->_mtu;
tap->lwipdev.name[0] = 'l';
tap->lwipdev.name[1] = '4';
tap->lwipdev.linkoutput = low_level_output;
tap->lwipdev.hwaddr_len = 6;
tap->lwipdev.flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
netif_set_default(&(tap->lwipdev));
netif_set_up(&(tap->lwipdev));
DEBUG_INFO("addr=%s, netmask=%s", ip.toString().c_str(), ip.netmask().toString().c_str());
}
#endif
#if defined(LIBZT_IPV6)
if(ip.isV6()) {
DEBUG_INFO("local_addr=%s", ip.toString().c_str());
static ip6_addr_t addr6;
struct sockaddr_in6 in6;
memcpy(in6.sin6_addr.s6_addr,ip.rawIpData(),16);
in6_to_ip6((ip6_addr *)&addr6, &in6);
tap->lwipdev6.mtu = tap->_mtu;
tap->lwipdev6.name[0] = 'l';
tap->lwipdev6.name[1] = '6';
tap->lwipdev6.hwaddr_len = 6;
tap->lwipdev6.linkoutput = low_level_output;
tap->lwipdev6.ip6_autoconfig_enabled = 1;
tap->_mac.copyTo(tap->lwipdev6.hwaddr, tap->lwipdev6.hwaddr_len);
netif_create_ip6_linklocal_address(&(tap->lwipdev6), 1);
netif_add(&(tap->lwipdev6), NULL, tapif_init, ethernet_input);
netif_set_default(&(tap->lwipdev6));
netif_set_up(&(tap->lwipdev6));
netif_ip6_addr_set_state(&(tap->lwipdev6), 1, IP6_ADDR_TENTATIVE);
ip6_addr_copy(ip_2_ip6(tap->lwipdev6.ip6_addr[1]), addr6);
tap->lwipdev6.output_ip6 = ethip6_output;
tap->lwipdev6.state = tap;
tap->lwipdev6.flags = NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
DEBUG_INFO("addr=%s, netmask=%s", ip.toString().c_str(), ip.netmask().toString().c_str());
}
#endif
}
}
void lwIP::lwip_loop(SocketTap *tap)
{
DEBUG_INFO();
uint64_t prev_tcp_time = 0, prev_status_time = 0, prev_discovery_time = 0;
while(tap->_run)
{
uint64_t now = OSUtils::now();
uint64_t since_tcp = now - prev_tcp_time;
uint64_t since_discovery = now - prev_discovery_time;
uint64_t since_status = now - prev_status_time;
uint64_t tcp_remaining = LWIP_TCP_TIMER_INTERVAL;
uint64_t discovery_remaining = 5000;
#if defined(LIBZT_IPV6)
#define DISCOVERY_INTERVAL 1000
#elif defined(LIBZT_IPV4)
#define DISCOVERY_INTERVAL ARP_TMR_INTERVAL
#endif
// Main TCP/ETHARP timer section
if (since_tcp >= LWIP_TCP_TIMER_INTERVAL) {
prev_tcp_time = now;
tcp_tmr();
}
else {
tcp_remaining = LWIP_TCP_TIMER_INTERVAL - since_tcp;
}
if (since_discovery >= DISCOVERY_INTERVAL) {
prev_discovery_time = now;
#if defined(LIBZT_IPV4)
etharp_tmr();
#endif
#if defined(LIBZT_IPV6)
nd6_tmr();
#endif
} else {
discovery_remaining = DISCOVERY_INTERVAL - since_discovery;
}
tap->_phy.poll((unsigned long)std::min(tcp_remaining,discovery_remaining));
}
}
void lwIP::lwip_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
DEBUG_INFO();
struct pbuf *p,*q;
if (!tap->_enabled)
return;
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
ethhdr.type = ZeroTier::Utils::hton((uint16_t)etherType);
p = pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_POOL);
if (p != NULL) {
const char *dataptr = reinterpret_cast<const char *>(data);
// First pbuf gets ethernet header at start
q = p;
if (q->len < sizeof(ethhdr)) {
DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header");
return;
}
memcpy(q->payload,&ethhdr,sizeof(ethhdr));
memcpy((char*)q->payload + sizeof(ethhdr),dataptr,q->len - sizeof(ethhdr));
dataptr += q->len - sizeof(ethhdr);
// Remaining pbufs (if any) get rest of data
while ((q = q->next)) {
memcpy(q->payload,dataptr,q->len);
dataptr += q->len;
}
}
else {
DEBUG_ERROR("dropped packet: no pbufs available");
return;
}
{
#if defined(LIBZT_IPV6)
if(tap->lwipdev6.input(p, &(tap->lwipdev6)) != ERR_OK) {
DEBUG_ERROR("error while feeding frame into stack lwipdev6");
}
#endif
#if defined(LIBZT_IPV4)
if(tap->lwipdev.input(p, &(tap->lwipdev)) != ERR_OK) {
DEBUG_ERROR("error while feeding frame into stack lwipdev");
}
#endif
}
}
int lwIP::lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol)
{
// TODO: check lwIP timers, and max sockets
DEBUG_INFO();
if(socket_type == SOCK_STREAM) {
struct tcp_pcb *new_tcp_PCB = tcp_new();
*pcb = new_tcp_PCB;
return ERR_OK;
}
if(socket_type == SOCK_DGRAM) {
struct udp_pcb *new_udp_PCB = udp_new();
*pcb = new_udp_PCB;
return ERR_OK;
}
if(socket_type == SOCK_RAW) {
DEBUG_ERROR("SOCK_RAW, not currently supported.");
return -1;
}
return -1;
}
int lwIP::lwip_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{
DEBUG_INFO();
}
int lwIP::lwip_Bind(SocketTap *tap, Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{
DEBUG_INFO();
ip_addr_t ba;
char addrstr[INET6_ADDRSTRLEN];
int port = 0, err = 0;
#if defined(LIBZT_IPV4)
DEBUG_ERROR("A");
struct sockaddr_in *in4;
if(addr->sa_family == AF_INET) {
DEBUG_ERROR("A");
in4 = (struct sockaddr_in *)addr;
DEBUG_ERROR("A");
inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN);
DEBUG_ERROR("A");
DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in4->sin_port));
}
ba = convert_ip(in4);
port = lwip_ntohs(in4->sin_port);
DEBUG_INFO("port=%d", port);
DEBUG_INFO("port=%d", lwip_ntohs(port));
#endif
#if defined(LIBZT_IPV6)
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&addr;
in6_to_ip6((ip6_addr *)&ba, in6);
if(addr->sa_family == AF_INET6) {
struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr;
inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN);
DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(connaddr6->sin6_port));
}
#endif
if(conn->socket_type == SOCK_DGRAM) {
err = udp_bind((struct udp_pcb*)conn->pcb, (const ip_addr_t *)&ba, port);
if(err == ERR_USE) {
err = -1;
errno = EADDRINUSE; // port in use
}
else {
// set the recv callback
udp_recv((struct udp_pcb*)conn->pcb, nc_udp_recved, new ConnectionPair(tap, conn));
err = ERR_OK;
errno = ERR_OK; // success
}
}
else if (conn->socket_type == SOCK_STREAM) {
err = tcp_bind((struct tcp_pcb*)conn->pcb, (const ip_addr_t *)&ba, port);
if(err != ERR_OK) {
DEBUG_ERROR("err=%d", err);
if(err == ERR_USE){
err = -1;
errno = EADDRINUSE;
}
if(err == ERR_MEM){
err = -1;
errno = ENOMEM;
}
if(err == ERR_BUF){
err = -1;
errno = ENOMEM;
}
}
else {
err = ERR_OK;
errno = ERR_OK; // success
}
}
return err;
}
int lwIP::lwip_Listen(SocketTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc)
{
DEBUG_INFO();
// to be implemented
}
int lwIP::lwip_Read(SocketTap *tap, PhySocket *sock, void **uptr, bool lwip_invoked)
{
DEBUG_EXTRA();
// to be implemented
}
int lwIP::lwip_Write(SocketTap *tap, Connection *conn)
{
DEBUG_EXTRA("conn=%p", (void*)&conn);
// to be implemented
}
int lwIP::lwip_Close(SocketTap *tap, PhySocket *sock, Connection *conn)
{
DEBUG_INFO();
// to be implemented
}
/****************************************************************************/
/* Callbacks from lwIP stack */
/****************************************************************************/
err_t lwIP::nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err)
{
DEBUG_INFO();
// to be implemented
return ERR_OK;
}
err_t lwIP::nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err)
{
DEBUG_INFO();
// to be implemented
return -1;
}
void lwIP::nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port)
{
DEBUG_INFO();
// to be implemented
}
err_t lwIP::nc_sent(void* arg, struct tcp_pcb *PCB, u16_t len)
{
DEBUG_EXTRA("pcb=%p", (void*)&PCB);
// to be implemented
return ERR_OK;
}
err_t lwIP::nc_connected(void *arg, struct tcp_pcb *PCB, err_t err)
{
DEBUG_ATTN("pcb=%p", (void*)&PCB);
// to be implemented
return ERR_OK;
}
err_t lwIP::nc_poll(void* arg, struct tcp_pcb *PCB)
{
DEBUG_INFO();
// to be implemented
return ERR_OK;
}
void lwIP::nc_err(void *arg, err_t err)
{
DEBUG_INFO();
// to be implemented
}
}

204
src/lwIP.hpp Normal file
View File

@@ -0,0 +1,204 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
// lwIP network stack driver
#ifndef ZT_LWIP_HPP
#define ZT_LWIP_HPP
#include <stdio.h>
#include <dlfcn.h>
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/init.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/priv/tcp_priv.h"
#include "Mutex.hpp"
#include "OSUtils.hpp"
#include "libzt.h"
#include "SocketTap.hpp"
struct tcp_pcb;
struct netif;
#if defined(LIBZT_IPV4)
#define LWIP_NETIF_ADD_SIG struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input
#define LWIP_ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr
#endif
#if defined(LIBZT_IPV6)
#define LWIP_NETIF_ADD_SIG struct netif *netif, void *state, netif_init_fn init, netif_input_fn input
#define LWIP_ETHIP6_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr
#define LWIP_ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ipaddr
#define LWIP_NETIF_IP6_ADDR_SET_STATE_SIG struct netif* netif, s8_t addr_idx, u8_t state
#define LWIP_NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG struct netif *netif, u8_t from_mac_48bit
#endif
#define LWIP_PBUF_FREE_SIG struct pbuf *p
#define LWIP_PBUF_ALLOC_SIG pbuf_layer layer, u16_t length, pbuf_type type
#define LWIP_HTONS_SIG u16_t x
#define LWIP_NTOHS_SIG u16_t x
#define LWIP_UDP_NEW_SIG void
#define LWIP_UDP_CONNECT_SIG struct udp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port
#define LWIP_UDP_SEND_SIG struct udp_pcb * pcb, struct pbuf * p
#define LWIP_UDP_SENDTO_SIG struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port
#define LWIP_UDP_RECV_SIG struct udp_pcb * pcb, void (* recv)(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port), void * recv_arg
#define LWIP_UDP_RECVED_SIG struct udp_pcb * pcb, u16_t len
#define LWIP_UDP_BIND_SIG struct udp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port
#define LWIP_UDP_REMOVE_SIG struct udp_pcb *pcb
#define LWIP_TCP_WRITE_SIG struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags
#define LWIP_TCP_SENT_SIG struct tcp_pcb * pcb, err_t (* sent)(void * arg, struct tcp_pcb * tpcb, u16_t len)
#define LWIP_TCP_NEW_SIG void
#define LWIP_TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
#define LWIP_TCP_RECVED_SIG struct tcp_pcb * pcb, u16_t len
//#define LWIP_TCP_SNDBUF_SIG struct tcp_pcb * pcb
#define LWIP_TCP_CONNECT_SIG struct tcp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port, err_t (* connected)(void * arg, struct tcp_pcb * tpcb, err_t err)
#define LWIP_TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
#define LWIP_TCP_ERR_SIG struct tcp_pcb * pcb, void (* err)(void * arg, err_t err)
#define LWIP_TCP_POLL_SIG struct tcp_pcb * pcb, err_t (* poll)(void * arg, struct tcp_pcb * tpcb), u8_t interval
#define LWIP_TCP_ARG_SIG struct tcp_pcb * pcb, void * arg
#define LWIP_TCP_CLOSE_SIG struct tcp_pcb * pcb
#define LWIP_TCP_ABORT_SIG struct tcp_pcb * pcb
#define LWIP_TCP_OUTPUT_SIG struct tcp_pcb * pcb
#define LWIP_TCP_ACCEPT_SIG struct tcp_pcb * pcb, err_t (* accept)(void * arg, struct tcp_pcb * newpcb, err_t err)
#define LWIP_TCP_LISTEN_SIG struct tcp_pcb * pcb
#define LWIP_TCP_LISTEN_WITH_BACKLOG_SIG struct tcp_pcb * pcb, u8_t backlog
#define LWIP_TCP_BIND_SIG struct tcp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port
#define LWIP_TCP_INPUT_SIG struct pbuf *p, struct netif *inp
#define LWIP_ETHERNET_INPUT_SIG struct pbuf *p, struct netif *netif
#define LWIP_IP_INPUT_SIG struct pbuf *p, struct netif *inp
#define LWIP_NETIF_SET_DEFAULT_SIG struct netif *netif
#define LWIP_NETIF_SET_UP_SIG struct netif *netif
#define LWIP_NETIF_POLL_SIG struct netif *netif
#if defined(LIBZT_IPV4)
extern "C" err_t etharp_output(LWIP_ETHARP_OUTPUT_SIG);
#endif
#if defined(LIBZT_IPV6)
extern "C" void nd6_tmr(void);
extern "C" void netif_ip6_addr_set_state(LWIP_NETIF_IP6_ADDR_SET_STATE_SIG);
extern "C" void netif_create_ip6_linklocal_address(LWIP_NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG);
extern "C" err_t _ethip6_output(LWIP_ETHIP6_OUTPUT_SIG);
#endif
extern "C" void lwip_init();
extern "C" err_t ethernet_input(LWIP_ETHERNET_INPUT_SIG);
extern "C" void netif_poll(LWIP_NETIF_POLL_SIG);
//extern "C" err_t etharp_output(LWIP_ETHARP_OUTPUT_SIG);
//extern "C" err_t ethernet_input(LWIP_ETHERNET_INPUT_SIG);
extern "C" void netif_set_up(LWIP_NETIF_SET_UP_SIG);
extern "C" void netif_set_default(LWIP_NETIF_SET_DEFAULT_SIG);
//extern "C" struct netif *netif_add(LWIP_NETIF_ADD_SIG);
extern "C" err_t tapif_init(struct netif *netif);
extern "C" err_t low_level_output(struct netif *netif, struct pbuf *p);
extern "C" err_t tcp_write(LWIP_TCP_WRITE_SIG);
extern "C" void tcp_sent(LWIP_TCP_SENT_SIG);
extern "C" struct tcp_pcb *tcp_new(LWIP_TCP_NEW_SIG);
//u16_t tcp_sndbuf(struct tcp_pcb * pcb);
extern "C" err_t tcp_connect(LWIP_TCP_CONNECT_SIG);
extern "C" struct udp_pcb *udp_new(LWIP_UDP_NEW_SIG);
extern "C" err_t udp_connect(LWIP_UDP_CONNECT_SIG);
extern "C" err_t udp_send(LWIP_UDP_SEND_SIG);
extern "C" err_t udp_sendto(LWIP_UDP_SENDTO_SIG);
//extern "C" void udp_recv(LWIP_UDP_RECV_SIG);
extern "C" void udp_recved(LWIP_UDP_RECVED_SIG);
extern "C" err_t udp_bind(LWIP_UDP_BIND_SIG);
extern "C" void udp_remove(LWIP_UDP_REMOVE_SIG);
extern "C" void tcp_recv(LWIP_TCP_RECV_SIG);
extern "C" void tcp_recved(LWIP_TCP_RECVED_SIG);
extern "C" void tcp_err(LWIP_TCP_ERR_SIG);
extern "C" void tcp_poll(LWIP_TCP_POLL_SIG);
extern "C" void tcp_arg(LWIP_TCP_ARG_SIG);
extern "C" err_t tcp_close(LWIP_TCP_CLOSE_SIG);
extern "C" void tcp_abort(LWIP_TCP_ABORT_SIG);
extern "C" err_t tcp_output(LWIP_TCP_OUTPUT_SIG);
extern "C" void tcp_accept(LWIP_TCP_ACCEPT_SIG);
//extern "C" struct tcp_pcb *tcp_listen(LWIP_TCP_LISTEN_SIG);
extern "C" struct tcp_pcb *tcp_listen_with_backlog(LWIP_TCP_LISTEN_WITH_BACKLOG_SIG);
extern "C" err_t tcp_bind(LWIP_TCP_BIND_SIG);
extern "C" void etharp_tmr(void);
extern "C" void tcp_tmr(void);
extern "C" u8_t pbuf_free(LWIP_PBUF_FREE_SIG);
extern "C" struct pbuf *pbuf_alloc(LWIP_PBUF_ALLOC_SIG);
extern "C" u16_t lwip_htons(LWIP_HTONS_SIG);
extern "C" u16_t lwip_ntohs(LWIP_NTOHS_SIG);
extern "C" void tcp_input(LWIP_TCP_INPUT_SIG);
extern "C" err_t ip_input(LWIP_IP_INPUT_SIG);
namespace ZeroTier {
class SocketTap;
struct Connection;
class lwIP
{
public:
/*
* Set up an interface in the network stack for the SocketTap
*/
void lwip_init_interface(SocketTap *tap, const InetAddress &ip);
/*
* Main stack loop
*/
void lwip_loop(SocketTap *tap);
/*
* Packets from the ZeroTier virtual wire enter the stack here
*/
void lwip_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
int lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol);
int lwip_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Bind(SocketTap *tap, Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen);
int lwip_Listen(SocketTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc);
int lwip_Read(SocketTap *tap, PhySocket *sock, void **uptr, bool lwip_invoked);
int lwip_Write(SocketTap *tap, Connection *conn);
int lwip_Close(SocketTap *tap, PhySocket *sock, Connection *conn);
static err_t nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err);
static err_t nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err);
static void nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port);
static void nc_err(void *arg, err_t err);
static err_t nc_poll(void* arg, struct tcp_pcb *PCB);
static err_t nc_sent(void *arg, struct tcp_pcb *PCB, u16_t len);
static err_t nc_connected(void *arg, struct tcp_pcb *PCB, err_t err);
};
}
#endif

View File

@@ -502,6 +502,58 @@ namespace ZeroTier {
}
return loop_score;
}
int picoTCP::pico_Socket(struct pico_socket **p, int socket_family, int socket_type, int protocol)
{
int err = 0;
if(pico_ntimers() >= PICO_MAX_TIMERS) {
DEBUG_ERROR("cannot create additional socket, see PICO_MAX_TIMERS. current = %d", pico_ntimers());
errno = EMFILE;
err = -1;
}
else
{
int protocol_version = 0;
struct pico_socket *psock;
if(socket_family == AF_INET)
protocol_version = PICO_PROTO_IPV4;
if(socket_family == AF_INET6)
protocol_version = PICO_PROTO_IPV6;
if(socket_type == SOCK_DGRAM) {
DEBUG_ERROR("SOCK_DGRAM");
psock = pico_socket_open(
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
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_activity);
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)
DEBUG_ERROR("unable to set SNDBUF size, err = %d, pico_err = %d", t_err, pico_err);
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", t_err, 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)
DEBUG_ERROR("unable to set LINGER, err = %d, pico_err = %d", t_err, pico_err);
}
}
}
*p = psock;
}
return err;
}
int picoTCP::pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen)
{

View File

@@ -121,7 +121,12 @@ namespace ZeroTier
* Packets from the ZeroTier virtual wire enter the stack here
*/
void pico_rx(SocketTap *tap, const ZeroTier::MAC &from,const ZeroTier::MAC &to,unsigned int etherType,const void *data,unsigned int len);
/*
* Creates a stack-specific "socket" or "connection object"
*/
int pico_Socket(struct pico_socket **p, int socket_family, int socket_type, int protocol);
/*
* Connect to remote host via userspace network stack interface - Called from SocketTap
*/