Introduction of sequential-API build variant, better thread safety (lwIP only)

This commit is contained in:
Joseph Henry
2017-09-27 02:29:04 -07:00
parent e4620e4c85
commit 5f1e9fe795
176 changed files with 16494 additions and 20406 deletions

68
src/Platform.cpp Normal file
View File

@@ -0,0 +1,68 @@
/*
* 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.
*/
/**
* @file
*
* Platform-specific implementations of common functions
*/
#include "Platform.h"
#include <stdint.h>
#include <pthread.h>
#ifdef __linux__
#include <sys/syscall.h>
#include <unistd.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
void handle_general_failure() {
#ifdef ZT_EXIT_ON_GENERAL_FAIL
DEBUG_ERROR("exiting (ZT_EXIT_ON_GENERAL_FAIL==1)");
exit(-1);
#endif
}
inline unsigned int gettid()
{
#ifdef _WIN32
return GetCurrentThreadId();
#elif defined(__linux__)
return static_cast<unsigned int>(syscall(__NR_gettid));
#elif defined(__APPLE__)
uint64_t tid64;
pthread_threadid_np(0, &tid64);
return static_cast<unsigned int>(tid64);
#endif
}
#ifdef __cplusplus
}
#endif

View File

@@ -24,6 +24,12 @@
* of your own application.
*/
/**
* @file
*
* Ring buffer implementation for network stack drivers
*/
#ifndef ZT_RINGBUFFER_HPP
#define ZT_RINGBUFFER_HPP

View File

@@ -24,6 +24,12 @@
* of your own application.
*/
/**
* @file
*
* Misc utilities
*/
#include "InetAddress.hpp"
#include "Debug.hpp"
@@ -82,26 +88,6 @@ char *beautify_eth_proto_nums(int proto)
return (char*)"UNKNOWN";
}
/*
ZeroTier::InetAddress *ztipv6_mask(ZeroTier::InetAddress *addr, unsigned int bits)
{
ZeroTier::InetAddress r(addr);
switch(r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= ZeroTier::Utils::hton((uint32_t)(0xffffffff << (32 - bits)));
break;
case AF_INET6: {
uint64_t nm[2];
memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
nm[0] &= ZeroTier::Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= ZeroTier::Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
}
return &r;
}
*/
bool ipv6_in_subnet(ZeroTier::InetAddress *subnet, ZeroTier::InetAddress *addr)
{
ZeroTier::InetAddress r(addr);
@@ -134,7 +120,6 @@ bool ipv6_in_subnet(ZeroTier::InetAddress *subnet, ZeroTier::InetAddress *addr)
return !strcmp(r.toIpString(b0), b.toIpString(b1));
}
void sockaddr2inet(int socket_family, const struct sockaddr *addr, ZeroTier::InetAddress *inet)
{
char ipstr[INET6_ADDRSTRLEN];
@@ -158,3 +143,24 @@ void mac2str(char *macbuf, int len, unsigned char* addr)
snprintf(macbuf, len, "%02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
/**
* Convert from standard IPV6 address structure to an lwIP native structure
*/
/*
inline void in6_to_ip6(ip6_addr_t *ba, struct sockaddr_in6 *in6)
{
uint8_t *ip = &(in6->sin6_addr).s6_addr[0];
IP6_ADDR2(ba,
(((ip[ 0] & 0xffff) << 8) | ((ip[ 1]) & 0xffff)),
(((ip[ 2] & 0xffff) << 8) | ((ip[ 3]) & 0xffff)),
(((ip[ 4] & 0xffff) << 8) | ((ip[ 5]) & 0xffff)),
(((ip[ 6] & 0xffff) << 8) | ((ip[ 7]) & 0xffff)),
(((ip[ 8] & 0xffff) << 8) | ((ip[ 9]) & 0xffff)),
(((ip[10] & 0xffff) << 8) | ((ip[11]) & 0xffff)),
(((ip[12] & 0xffff) << 8) | ((ip[13]) & 0xffff)),
(((ip[14] & 0xffff) << 8) | ((ip[15]) & 0xffff))
);
}
*/

View File

@@ -1,100 +0,0 @@
/*
* 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.
*/
#ifndef UTILITIES_HPP
#define UTILITIES_HPP
/**
* Returns masked address for subnet comparisons
*/
//ZeroTier::InetAddress *ztipv6_mask(ZeroTier::InetAddress *addr, unsigned int bits);
bool ipv6_in_subnet(ZeroTier::InetAddress *subnet, ZeroTier::InetAddress *addr);
/**
* Convert protocol numbers to human-readable strings
*/
char *beautify_eth_proto_nums(int proto);
/**
* Convert a struct sockaddr to a ZeroTier::InetAddress
*/
void sockaddr2inet(int socket_family, const struct sockaddr *addr, ZeroTier::InetAddress *inet);
/**
* Convert a raw MAC address byte array into a human-readable string
*/
void mac2str(char *macbuf, int len, unsigned char* addr);
#if defined(STACK_LWIP) && defined(LIBZT_IPV6)
#define IP6_ADDR2(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = ZeroTier::Utils::hton((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
(ipaddr)->addr[1] = ZeroTier::Utils::hton(((c & 0xffff) << 16) | (d & 0xffff)); \
(ipaddr)->addr[2] = ZeroTier::Utils::hton(((e & 0xffff) << 16) | (f & 0xffff)); \
(ipaddr)->addr[3] = ZeroTier::Utils::hton(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
/**
* Convert from standard IPV6 address structure to an lwIP native structure
*/
inline void in6_to_ip6(ip6_addr_t *ba, struct sockaddr_in6 *in6)
{
uint8_t *ip = &(in6->sin6_addr).s6_addr[0];
IP6_ADDR2(ba,
(((ip[ 0] & 0xffff) << 8) | ((ip[ 1]) & 0xffff)),
(((ip[ 2] & 0xffff) << 8) | ((ip[ 3]) & 0xffff)),
(((ip[ 4] & 0xffff) << 8) | ((ip[ 5]) & 0xffff)),
(((ip[ 6] & 0xffff) << 8) | ((ip[ 7]) & 0xffff)),
(((ip[ 8] & 0xffff) << 8) | ((ip[ 9]) & 0xffff)),
(((ip[10] & 0xffff) << 8) | ((ip[11]) & 0xffff)),
(((ip[12] & 0xffff) << 8) | ((ip[13]) & 0xffff)),
(((ip[14] & 0xffff) << 8) | ((ip[15]) & 0xffff))
);
}
#endif
#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 // STACK_LWIP && LIBZT_IPV4
#endif // UTILITIES_HPP

View File

@@ -24,14 +24,28 @@
* of your own application.
*/
/**
* @file
*
*
*/
/*
#include "VirtualSocket.h"
#include "VirtualTap.hpp"
This file is only meant for those who wish to replace the currently supported network stacks (lwIP and picoTCP) with
one of their own choosing. If you're looking for information on how to integrate libzt with your application, you
should instead go view the (examples) folder. Now let us get started.
TODO
#ifdef __cplusplus
extern "C" {
#endif
struct VirtualBindingPair
{
VirtualTap *tap;
VirtualSocket *vs;
VirtualBindingPair(VirtualTap *_tap, VirtualSocket *_vs) : tap(_tap), vs(_vs) {}
};
#ifdef __cplusplus
}
#endif
*/

119
src/VirtualSocket.cpp Normal file
View File

@@ -0,0 +1,119 @@
/*
* 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.
*/
/**
* @file
*
* Platform-agnostic implementation of a socket-like object
*/
#ifndef ZT_VIRTUALSOCKET_HPP
#define ZT_VIRTUALSOCKET_HPP
#include <ctime>
#include <sys/socket.h>
#include "VirtualSocket.h"
#include "VirtualBindingPair.h"
#include "RingBuffer.hpp"
#define VS_STATE_INACTIVE 0x000000u // Default value for newly created VirtualSocket
#define VS_STATE_ACTIVE 0x000001u // VirtualSocket is RX'ing or TX'ing without issue
#define VS_STATE_SHOULD_SHUTDOWN 0x000002u // Application, stack driver, or stack marked this VirtualSocket for death
#define VS_STATE_SHUTDOWN 0x000004u // VirtualSocket and underlying protocol control structures will not RX/TX
#define VS_STATE_CLOSED 0x000008u // VirtualSocket and underlying protocol control structures are closed
#define VS_STATE_UNHANDLED_CONNECTED 0x000010u // stack callback has received a connection but we haven't dealt with it
#define VS_STATE_CONNECTED 0x000020u // stack driver has akwnowledged new connection
#define VS_STATE_LISTENING 0x000040u // virtual socket is listening for incoming connections
#define VS_OPT_TCP_NODELAY 0x000000u // Nagle's algorithm
#define VS_OPT_SO_LINGER 0x000001u // VirtualSocket waits for data transmission before closure
/*
#define VS_RESERVED 0x000002u //
#define VS_RESERVED 0x000004u //
#define VS_RESERVED 0x000008u //
#define VS_RESERVED 0x000010u //
#define VS_RESERVED 0x000020u //
#define VS_RESERVED 0x000040u //
*/
#define VS_OPT_FD_NONBLOCKING 0x000080u // Whether the VirtualSocket exhibits non-blocking behaviour
/*
#define VS_RESERVED 0x000100u //
#define VS_RESERVED 0x000200u //
#define VS_RESERVED 0x000400u //
#define VS_RESERVED 0x000800u //
#define VS_RESERVED 0x001000u //
#define VS_RESERVED 0x002000u //
#define VS_RESERVED 0x004000u //
#define VS_RESERVED 0x008000u //
#define VS_RESERVED 0x010000u //
#define VS_RESERVED 0x020000u //
#define VS_RESERVED 0x040000u //
#define VS_RESERVED 0x080000u //
#define VS_RESERVED 0x100000u //
#define VS_RESERVED 0x200000u //
#define VS_RESERVED 0x400000u //
#define VS_RESERVED 0x800000u //
*/
#define vs_is_nonblocking(vs) (((vs)->optflags & VS_OPT_FD_NONBLOCKING) != 0)
namespace ZeroTier {
class VirtualTap;
class VirtualSocket
{
private:
int _state = VS_STATE_INACTIVE;
public:
/**
* Sets the VirtualSocket's state value
*/
void apply_state(int state) {
_state &= state;
}
/**
* Sets the VirtualSocket's state value
*/
void set_state(int state) {
_state = state;
}
/**
* Gets the VirtualSocket's state value
*/
int get_state() {
return _state;
}
VirtualSocket() {
}
~VirtualSocket() {
}
};
}
#endif

View File

@@ -1,236 +0,0 @@
/*
* 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.
*/
// General connection object used by VirtualTap and network stack drivers
#ifndef ZT_CONNECTION_HPP
#define ZT_CONNECTION_HPP
#include <ctime>
#include <sys/socket.h>
#if defined(STACK_PICO)
#include "pico_socket.h"
#endif
#if defined(STACK_LWIP)
#include "lwip/tcp.h"
#endif
#include "Phy.hpp"
#include "libzt.h"
#include "VirtualTap.hpp"
#include "RingBuffer.hpp"
#define VS_STATE_INACTIVE 0x000000u // Default value for newly created VirtualSocket
#define VS_STATE_ACTIVE 0x000001u // VirtualSocket is RX'ing or TX'ing without issue
#define VS_STATE_SHOULD_SHUTDOWN 0x000002u // Application, stack driver, or stack marked this VirtualSocket for death
#define VS_STATE_SHUTDOWN 0x000004u // VirtualSocket and underlying protocol control structures will not RX/TX
#define VS_STATE_CLOSED 0x000008u // VirtualSocket and underlying protocol control structures are closed
#define VS_STATE_UNHANDLED_CONNECTED 0x000010u // stack callback has received a connection but we haven't dealt with it
#define VS_STATE_CONNECTED 0x000020u // stack driver has akwnowledged new connection
#define VS_STATE_LISTENING 0x000040u // virtual socket is listening for incoming connections
#define VS_OPT_TCP_NODELAY 0x000000u // Nagle's algorithm
#define VS_OPT_SO_LINGER 0x000001u // VirtualSocket waits for data transmission before closure
/*
#define VS_RESERVED 0x000002u //
#define VS_RESERVED 0x000004u //
#define VS_RESERVED 0x000008u //
#define VS_RESERVED 0x000010u //
#define VS_RESERVED 0x000020u //
#define VS_RESERVED 0x000040u //
*/
#define VS_OPT_FD_NONBLOCKING 0x000080u // Whether the VirtualSocket exhibits non-blocking behaviour
/*
#define VS_RESERVED 0x000100u //
#define VS_RESERVED 0x000200u //
#define VS_RESERVED 0x000400u //
#define VS_RESERVED 0x000800u //
#define VS_RESERVED 0x001000u //
#define VS_RESERVED 0x002000u //
#define VS_RESERVED 0x004000u //
#define VS_RESERVED 0x008000u //
#define VS_RESERVED 0x010000u //
#define VS_RESERVED 0x020000u //
#define VS_RESERVED 0x040000u //
#define VS_RESERVED 0x080000u //
#define VS_RESERVED 0x100000u //
#define VS_RESERVED 0x200000u //
#define VS_RESERVED 0x400000u //
#define VS_RESERVED 0x800000u //
*/
#define vs_is_nonblocking(vs) (((vs)->optflags & VS_OPT_FD_NONBLOCKING) != 0)
namespace ZeroTier {
class VirtualTap;
/**
* An abstraction of a socket that operates between the application-exposed platform-sockets
* and the network stack's representation of a protocol control structure. This object is used by
* the POSIX socket emulation layer and stack drivers.
*/
class VirtualSocket
{
private:
int _state = VS_STATE_INACTIVE;
public:
RingBuffer<unsigned char> *TXbuf;
RingBuffer<unsigned char> *RXbuf;
Mutex _tx_m, _rx_m, _op_m;
PhySocket *sock = NULL;
/**
* Sets the VirtualSocket's state value
*/
void apply_state(int state) {
// states may be set by application or by stack callbacks, thus this must be guarded
_op_m.lock();
_state &= state;
#if defined (STACK_PICO)
DEBUG_EXTRA("APPLY STATE=%d (state=%d, vs=%p, ps=%p)", _state, state, this, picosock);
#endif
#if defined (STACK_LWIP)
DEBUG_EXTRA("APPLY STATE=%d (state=%d, vs=%p, pcb=%p)", _state, state, this, pcb);
#endif
_op_m.unlock();
}
/**
* Sets the VirtualSocket's state value
*/
void set_state(int state) {
// states may be set by application or by stack callbacks, thus this must be guarded
_op_m.lock();
_state = state;
#if defined (STACK_PICO)
DEBUG_EXTRA("SET STATE=%d (state=%d, vs=%p, ps=%p)", _state, state, this, picosock);
#endif
#if defined (STACK_LWIP)
DEBUG_EXTRA("SET STATE=%d (state=%d, vs=%p, pcb=%p)", _state, state, this, pcb);
#endif
_op_m.unlock();
}
/**
* Gets the VirtualSocket's state value
*/
int get_state() {
#if defined (STACK_PICO)
DEBUG_EXTRA("GET STATE=%d (vs=%p, ps=%p)", _state, this, picosock);
#endif
#if defined (STACK_LWIP)
DEBUG_EXTRA("GET STATE=%d (vs=%p, pcb=%p)", _state, this, pcb);
#endif
return _state;
}
#if defined(STACK_PICO)
struct pico_socket *picosock = NULL;
#endif
#if defined(STACK_LWIP)
int32_t optflags = 0;
int linger;
void *pcb = NULL; // Protocol Control Block
/*
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
for the data to be copied into. If this flag is not given, no new memory
should be allocated and the data should only be referenced by pointer. This
also means that the memory behind dataptr must not change until the data is
ACKed by the remote host
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted,
the PSH flag is set in the last segment created by this call to tcp_write.
If this flag is given, the PSH flag is not set.
*/
// copy as default, processed via pointer reference if set to 0. See notes in lwip_cb_sent() and lwip_Write()
int8_t copymode = TCP_WRITE_FLAG_COPY;
#endif
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 = 0;
int socket_type = 0;
int protocol = 0;
int app_fd = 0; // used by app for I/O
int sdk_fd = 0; // used by lib for I/O
std::queue<VirtualSocket*> _AcceptedConnections;
VirtualTap *tap = NULL;
VirtualSocket() {
DEBUG_EXTRA("this=%p",this);
memset(&local_addr, 0, sizeof(sockaddr_storage));
memset(&peer_addr, 0, sizeof(sockaddr_storage));
// ringbuffer used for incoming and outgoing traffic between app, stack, stack drivers, and ZT
TXbuf = new RingBuffer<unsigned char>(ZT_TCP_TX_BUF_SZ);
RXbuf = new RingBuffer<unsigned char>(ZT_TCP_RX_BUF_SZ);
// socketpair, I/O channel between app and stack drivers
ZT_PHY_SOCKFD_TYPE fdpair[2];
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdpair) < 0) {
if (errno < 0) {
DEBUG_ERROR("unable to create socketpair, errno=%d", errno);
return;
}
}
sdk_fd = fdpair[0];
app_fd = fdpair[1];
// set to non-blocking since these are used as the primary I/O channel
if (fcntl(sdk_fd, F_SETFL, O_NONBLOCK) < 0) {
DEBUG_ERROR("error while setting virtual socket to NONBLOCKING. exiting", errno);
exit(0);
}
}
~VirtualSocket() {
DEBUG_EXTRA("this=%p",this);
close(app_fd);
close(sdk_fd);
delete TXbuf;
delete RXbuf;
TXbuf = RXbuf = NULL;
#if defined(STACK_PICO)
picosock->priv = NULL;
picosock = NULL;
#endif
#if defined(STACK_LWIP)
pcb = NULL;
#endif
}
};
/**
* A helper object for passing VirtualTap(s) and VirtualSocket(s) through the stack
*/
struct VirtualBindingPair
{
VirtualTap *tap;
VirtualSocket *vs;
VirtualBindingPair(VirtualTap *_tap, VirtualSocket *_vs) : tap(_tap), vs(_vs) {}
};
}
#endif

View File

@@ -24,22 +24,24 @@
* of your own application.
*/
#include <netinet/in.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
/**
* @file
*
* Virtual Ethernet tap device
*/
#include <errno.h>
#include <utility>
#include <sys/poll.h>
#include <stdint.h>
#include <utility>
#include "Phy.hpp"
#include "VirtualTap.hpp"
#include <utility>
#include <stdint.h>
#include <cstring>
#include "libzt.h"
#if defined(STACK_PICO)
#include "picoTCP.hpp"
#endif
#if defined(STACK_LWIP)
#include "lwIP.hpp"
#endif
@@ -51,15 +53,13 @@
#include <netinet/ether.h>
#endif
#include "OneService.hpp"
#include "ZT1Service.h"
#include "Utils.hpp"
#include "OSUtils.hpp"
#include "Mutex.hpp"
#include "Constants.hpp"
#include "Phy.hpp"
class VirtualTap;
extern std::vector<void*> vtaps;
#include "InetAddress.hpp"
#include "OneService.hpp"
namespace ZeroTier {
@@ -92,7 +92,7 @@ namespace ZeroTier {
_unixListenSocket((PhySocket *)0),
_phy(this,false,true)
{
vtaps.push_back((void*)this);
ZeroTier::vtaps.push_back((void*)this);
// set virtual tap interface name (full)
memset(vtap_full_name, 0, sizeof(vtap_full_name));
@@ -129,40 +129,19 @@ namespace ZeroTier {
bool VirtualTap::registerIpWithStack(const InetAddress &ip)
{
#if defined(STACK_PICO)
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;
DEBUG_EXTRA();
lwip_driver_init();
lwip_init_interface((void*)this, this->_mac, ip);
return true;
}
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());
err = true;
#endif
#if defined(STACK_PICO) || defined(STACK_LWIP)
char ipbuf[INET6_ADDRSTRLEN];
DEBUG_INFO("addIp (%s)", ip.toString(ipbuf));
DEBUG_EXTRA("addIp (%s)", ip.toString(ipbuf));
Mutex::Lock _l(_ips_m);
if (registerIpWithStack(ip)) {
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) {
_ips.push_back(ip);
@@ -170,18 +149,17 @@ namespace ZeroTier {
}
return true;
}
err = false;
#endif
return err;
}
bool VirtualTap::removeIp(const InetAddress &ip)
{
DEBUG_EXTRA();
Mutex::Lock _l(_ips_m);
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (i == _ips.end()) {
return false;
}
//if (i == _ips.end()) {
// return false;
//}
_ips.erase(i);
if (ip.isV4()) {
// FIXME: De-register from network stacks
@@ -201,20 +179,7 @@ namespace ZeroTier {
void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
#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
lwip_eth_rx(this, from, to, etherType, data, len);
}
std::string VirtualTap::deviceName() const
@@ -224,7 +189,6 @@ namespace ZeroTier {
std::string VirtualTap::nodeId() const
{
// TODO: This is inefficient and awkward, should be replaced with something more elegant
if (zt1ServiceRef) {
char id[ZT_ID_LEN];
memset(id, 0, sizeof(id));
@@ -238,8 +202,7 @@ namespace ZeroTier {
void VirtualTap::setFriendlyName(const char *friendlyName)
{
DEBUG_INFO("%s", friendlyName);
// Someday
DEBUG_EXTRA("%s", friendlyName);
}
void VirtualTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
@@ -274,189 +237,64 @@ namespace ZeroTier {
void VirtualTap::threadMain()
throw()
{
#if defined(STACK_PICO)
if (picostack) {
picostack->pico_init_interface(this);
if (should_start_stack) {
// Add link to ipv4_link_add
//ZeroTier::InetAddress localhost;
//localhost.fromString("127.0.0.1");
//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();
DEBUG_EXTRA();
while (true) {
_phy.poll(ZT_PHY_POLL_INTERVAL);
Housekeeping();
}
#endif
#if defined(STACK_LWIP)
if (lwipstack)
lwipstack->lwip_loop(this);
#endif
}
void VirtualTap::phyOnUnixClose(PhySocket *sock, void **uptr)
{
DEBUG_EXTRA();
/*
int err = 0;
if (sock) {
VirtualSocket *vs = (VirtualSocket*)uptr;
if (vs) {
if (vs->get_state() != VS_STATE_CLOSED && vs->get_state() != VS_STATE_LISTENING) {
DEBUG_EXTRA("vs=%p, vs->get_state()=%d, vs->picosock->state=%d", vs, vs->get_state(), vs->picosock->state);
// doesn't make sense to shut down a listening socket, just close it
if ((err = vs->tap->Shutdown(vs, SHUT_RDWR)) < 0) {
DEBUG_ERROR("error while shutting down socket");
handle_general_failure();
return;
}
}
//picostack->pico_Close(vs);
}
} else {
handle_general_failure();
}
*/
}
void VirtualTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
{
DEBUG_EXTRA();
VirtualSocket *vs = (VirtualSocket*)*uptr;
if (vs == NULL) {
handle_general_failure();
return;
}
if (len > 0) {
Write(vs, data, len);
}
}
void VirtualTap::phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked)
{
if (sock) {
Read(sock,uptr,stack_invoked);
} else {
handle_general_failure();
}
DEBUG_EXTRA();
}
// Adds a route to the virtual tap
bool VirtualTap::routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw)
{
#if defined(NO_STACK)
return false;
#endif
#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
DEBUG_EXTRA();
return false;
}
// Deletes a route from the virtual tap
bool VirtualTap::routeDelete(const InetAddress &addr, const InetAddress &nm)
{
#if defined(NO_STACK)
return false;
#endif
#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
DEBUG_EXTRA();
return false;
}
void VirtualTap::addVirtualSocket(VirtualSocket *vs)
void VirtualTap::addVirtualSocket()
{
Mutex::Lock _l(_tcpconns_m);
_VirtualSockets.push_back(vs);
DEBUG_EXTRA();
}
void VirtualTap::removeVirtualSocket(VirtualSocket *vs)
void VirtualTap::removeVirtualSocket()
{
Mutex::Lock _l(_tcpconns_m);
for (int i=0; i<_VirtualSockets.size(); i++) {
if (vs == _VirtualSockets[i]) {
_VirtualSockets.erase(_VirtualSockets.begin() + i);
break;
}
}
DEBUG_EXTRA();
}
/****************************************************************************/
/* DNS */
/****************************************************************************/
int VirtualTap::add_DNS_Nameserver(struct sockaddr *addr)
{
int err = -1;
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_add_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_add_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
int VirtualTap::del_DNS_Nameserver(struct sockaddr *addr)
{
int err = -1;
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_del_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_del_dns_nameserver(addr);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
/****************************************************************************/
@@ -464,281 +302,66 @@ namespace ZeroTier {
/****************************************************************************/
// Connect
int VirtualTap::Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
int VirtualTap::Connect(const struct sockaddr *addr, socklen_t addrlen)
{
int err = -1;
#if defined(NO_STACK)
return err;
#endif
#if defined(STACK_PICO)
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
err = picostack->pico_Connect(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Connect(vs, addr, addrlen);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
// Bind VirtualSocket to a network stack's interface
int VirtualTap::Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
int VirtualTap::Bind(const struct sockaddr *addr, socklen_t addrlen)
{
#if defined(NO_STACK)
return -1;
#endif
#if defined(STACK_PICO)
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_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
DEBUG_EXTRA();
return -1;
}
// Listen for an incoming VirtualSocket
int VirtualTap::Listen(VirtualSocket *vs, int backlog)
int VirtualTap::Listen(int backlog)
{
int err = -1;
#if defined(NO_STACK)
return err;
#endif
#if defined(STACK_PICO)
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
return picostack->pico_Listen(vs, backlog);
} else {
handle_general_failure();
return err;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
Mutex::Lock _l(_tcpconns_m);
err = lwipstack->lwip_Listen(vs, backlog);
} else {
handle_general_failure();
return err;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
// Accept a VirtualSocket
VirtualSocket* VirtualTap::Accept(VirtualSocket *vs)
void VirtualTap::Accept()
{
VirtualSocket *new_vs = NULL;
#if defined(NO_STACK)
new_vs = NULL;
#endif
#if defined(STACK_PICO)
// TODO: separation of church and state
if (picostack) {
Mutex::Lock _l(_tcpconns_m);
new_vs = picostack->pico_Accept(vs);
} else {
handle_general_failure();
return NULL;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
Mutex::Lock _l(_tcpconns_m);
new_vs = lwipstack->lwip_Accept(vs);
} else {
handle_general_failure();
return NULL;
}
#endif
return new_vs;
DEBUG_EXTRA();
}
// Read from stack/buffers into the app's socket
int VirtualTap::Read(PhySocket *sock,void **uptr,bool stack_invoked)
{
int err = -1;
#if defined(NO_STACK)
#endif
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_Read(this, sock, (VirtualSocket*)uptr, stack_invoked);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Read((VirtualSocket*)*(_phy.getuptr(sock)), stack_invoked);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
// 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(void *data, ssize_t len)
{
DEBUG_EXTRA("vs=%p, fd=%d, data=%p, len=%d", vs, vs->app_fd, data, 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;
MAC src_mac;
MAC dest_mac;
src_mac.setTo(eh->ether_shost, 6);
dest_mac.setTo(eh->ether_dhost, 6);
_handler(_arg,NULL,_nwid,src_mac,dest_mac, Utils::ntoh((uint16_t)eh->ether_type),0, ((char*)data) + sizeof(struct ether_header),len - sizeof(struct ether_header));
return len;
}
#if defined(STACK_PICO)
if (picostack) {
err = picostack->pico_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Write(vs, data, len);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA("data=%p, len=%d", data, len);
return -1;
}
// Send data to a specified host
int VirtualTap::SendTo(VirtualSocket *vs, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen)
int VirtualTap::SendTo(const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen)
{
/* 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 = -1;
#if defined(STACK_PICO)
if (picostack) {
if ((err = picostack->pico_Connect(vs, addr, addrlen)) < 0) { // implicit
errno = ENOTCONN;
return err;
}
if ((err = picostack->pico_Write(vs, (void*)buf, len)) < 0) {
errno = ENOBUFS; // TODO: translate pico err to something more useful
return err;
}
} else {
handle_general_failure();
return -1;
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
if ((err = lwipstack->lwip_Connect(vs, addr, addrlen)) < 0) { // implicit
return err;
}
if ((err = lwipstack->lwip_Write(vs, (void*)buf, len)) < 0) {
return err;
}
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
// Remove VritualSocket from VirtualTap, and instruct network stacks to dismantle their
// respective protocol control structures
int VirtualTap::Close(VirtualSocket *vs)
int VirtualTap::Close()
{
int err = 0;
if (vs == NULL) {
DEBUG_ERROR("invalid VirtualSocket");
handle_general_failure();
return -1;
}
if (vs->sock) {
DEBUG_EXTRA("calling _phy.close()");
_phy.close(vs->sock, true);
}
removeVirtualSocket(vs);
#if defined(STACK_PICO)
if (vs->get_state() != VS_STATE_CLOSED && vs->get_state() != VS_STATE_LISTENING) {
DEBUG_EXTRA("vs=%p, vs->get_state()=%d, vs->picosock->state=%d", vs, vs->get_state(), vs->picosock->state);
// doesn't make sense to shut down a listening socket, just close it
if ((err = vs->tap->Shutdown(vs, SHUT_RDWR)) < 0) {
DEBUG_ERROR("error while shutting down socket");
handle_general_failure();
return - 1;
}
}
picostack->pico_Close(vs);
removeVirtualSocket(vs);
if (vs->socket_type == SOCK_STREAM) {
while (!(vs->picosock->state & PICO_SOCKET_STATE_CLOSED)) {
nanosleep((const struct timespec[]) {{0, (ZT_ACCEPT_RECHECK_DELAY * 1000000)}}, NULL);
DEBUG_EXTRA("virtual lingering on socket, ps=%p, buf remaining=%d",vs->picosock, vs->TXbuf->count());
}
}
#endif
#if defined(STACK_LWIP)
if (lwipstack) {
err = lwipstack->lwip_Close(vs);
} else {
handle_general_failure();
return -1;
}
#endif
return err;
DEBUG_EXTRA();
return -1;
}
// Shuts down some aspect of a connection (Read/Write)
int VirtualTap::Shutdown(VirtualSocket *vs, int how)
int VirtualTap::Shutdown(int how)
{
int err = 0;
#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;
DEBUG_EXTRA();
return -1;
}
void VirtualTap::Housekeeping()
@@ -746,7 +369,7 @@ namespace ZeroTier {
Mutex::Lock _l(_tcpconns_m);
std::time_t current_ts = std::time(nullptr);
if (current_ts > last_housekeeping_ts + ZT_HOUSEKEEPING_INTERVAL) {
// DEBUG_EXTRA();
DEBUG_EXTRA();
// update managed routes (add/del from network stacks)
ZeroTier::OneService *service = ((ZeroTier::OneService *)zt1ServiceRef);
if (service) {
@@ -800,7 +423,6 @@ namespace ZeroTier {
}
}
}
// TODO: Clean up VirtualSocket objects
last_housekeeping_ts = std::time(nullptr);
}
@@ -819,5 +441,4 @@ namespace ZeroTier {
void VirtualTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
void VirtualTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
} // namespace ZeroTier
} // namespace ZeroTier

View File

@@ -24,45 +24,23 @@
* of your own application.
*/
/**
* @file
*
* Virtual Ethernet tap device
*/
#ifndef ZT_VIRTUALTAP_HPP
#define ZT_VIRTUALTAP_HPP
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <queue>
#include <utility>
#include <stdexcept>
#include <stdint.h>
#include <errno.h>
#include <ctime>
#include "Constants.hpp"
#include "MulticastGroup.hpp"
#include "Mutex.hpp"
#include "MulticastGroup.hpp"
#include "InetAddress.hpp"
#include "Thread.hpp"
#include "Phy.hpp"
#include "libzt.h"
#include "VirtualSocket.hpp"
#if defined(STACK_PICO)
#include "picoTCP.hpp"
#include "pico_protocol.h"
#include "pico_stack.h"
#include "pico_ipv4.h"
#include "pico_icmp4.h"
#include "pico_dev_tap.h"
#include "pico_protocol.h"
#include "pico_device.h"
#include "pico_ipv6.h"
#endif
#if defined(STACK_LWIP)
#include "lwip/netif.h"
struct netif;
#endif
namespace ZeroTier {
/**
@@ -175,12 +153,12 @@ namespace ZeroTier {
/**
* Assign a VirtualSocket to the VirtualTap
*/
void addVirtualSocket(VirtualSocket *vs);
void addVirtualSocket();
/**
* Remove a VirtualSocket from the VirtualTap
*/
void removeVirtualSocket(VirtualSocket *vs);
void removeVirtualSocket();
/****************************************************************************/
/* DNS */
@@ -200,22 +178,6 @@ namespace ZeroTier {
/* Vars */
/****************************************************************************/
#if defined(STACK_PICO)
bool should_start_stack = false;
struct pico_device *picodev = NULL;
/****************************************************************************/
/* Guarded RX Frame Buffer for picoTCP */
/****************************************************************************/
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
int pico_frame_rxbuf_tot = 0;
Mutex _pico_frame_rxbuf_m;
#endif
#if defined(STACK_LWIP)
netif lwipdev;
netif lwipdev6;
#endif
std::vector<std::pair<ZeroTier::InetAddress, ZeroTier::InetAddress>> routes;
void *zt1ServiceRef = NULL;
@@ -238,7 +200,7 @@ namespace ZeroTier {
PhySocket *_unixListenSocket;
Phy<VirtualTap *> _phy;
std::vector<VirtualSocket*> _VirtualSockets;
//std::vector<VirtualSocket*> _VirtualSockets;
Thread _thread;
std::string _dev; // path to Unix domain socket
@@ -261,22 +223,22 @@ namespace ZeroTier {
/**
* Connect to a remote host via the userspace stack interface associated with this VirtualTap
*/
int Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
int Connect( const struct sockaddr *addr, socklen_t addrlen);
/**
* Bind to the userspace stack interface associated with this VirtualTap
*/
int Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
int Bind(const struct sockaddr *addr, socklen_t addrlen);
/**
* Listen for a VirtualSocket
*/
int Listen(VirtualSocket *vs, int backlog);
int Listen(int backlog);
/**
* Accepts an incoming VirtualSocket
*/
VirtualSocket* Accept(VirtualSocket *vs);
void Accept();
/**
* Move data from RX buffer to application's "socket"
@@ -286,22 +248,22 @@ namespace ZeroTier {
/**
* Move data from application's "socket" into network stack
*/
int Write(VirtualSocket *vs, void *data, ssize_t len);
int Write(void *data, ssize_t len);
/**
* Send data to specified host
*/
int SendTo(VirtualSocket *vs, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
int SendTo(const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
/**
* Closes a VirtualSocket
*/
int Close(VirtualSocket *vs);
int Close();
/**
* Shuts down some aspect of a VirtualSocket
*/
int Shutdown(VirtualSocket *vs, int how);
int Shutdown(int how);
/**
* Disposes of previously-closed VirtualSockets

508
src/ZT1Service.cpp Normal file
View File

@@ -0,0 +1,508 @@
/*
* 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.
*/
/**
* @file
*
* ZeroTier One service control wrapper
*/
#include "ZT1Service.h"
#include "Debug.hpp"
#include "Phy.hpp"
#include "OneService.hpp"
#include "Utilities.h"
#include "OSUtils.hpp"
#ifdef __cplusplus
extern "C" {
#endif
namespace ZeroTier {
std::vector<void*> vtaps;
static ZeroTier::OneService *zt1Service;
std::string homeDir; // Platform-specific dir we *must* use internally
std::string netDir; // Where network .conf files are to be written
ZeroTier::Mutex _vtaps_lock;
ZeroTier::Mutex _multiplexer_lock;
}
/****************************************************************************/
/* ZeroTier Core helper functions for libzt - DON'T CALL THESE DIRECTLY */
/****************************************************************************/
std::vector<ZT_VirtualNetworkRoute> *zts_get_network_routes(char *nwid)
{
uint64_t nwid_int = strtoull(nwid, NULL, 16);
return ZeroTier::zt1Service->getRoutes(nwid_int);
}
ZeroTier::VirtualTap *getTapByNWID(uint64_t nwid)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::VirtualTap *s, *tap = nullptr;
for (int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if (s->_nwid == nwid) { tap = s; }
}
ZeroTier::_vtaps_lock.unlock();
return tap;
}
ZeroTier::VirtualTap *getTapByAddr(ZeroTier::InetAddress *addr)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::VirtualTap *s, *tap = nullptr;
//char ipbuf[64], ipbuf2[64], ipbuf3[64];
for (int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
// check address schemes
for (int j=0; j<s->_ips.size(); j++) {
if ((s->_ips[j].isV4() && addr->isV4()) || (s->_ips[j].isV6() && addr->isV6())) {
//DEBUG_EXTRA("looking at tap %s, <addr=%s> --- for <%s>", s->_dev.c_str(), s->_ips[j].toString(ipbuf), addr->toIpString(ipbuf2));
if (s->_ips[j].isEqualPrefix(addr)
|| s->_ips[j].ipsEqual(addr)
|| s->_ips[j].containsAddress(addr)
|| (addr->isV6() && ipv6_in_subnet(&s->_ips[j], addr))
)
{
//DEBUG_EXTRA("selected tap %s, <addr=%s>", s->_dev.c_str(), s->_ips[j].toString(ipbuf));
ZeroTier::_vtaps_lock.unlock();
return s;
}
}
}
// check managed routes
if (tap == NULL) {
std::vector<ZT_VirtualNetworkRoute> *managed_routes = ZeroTier::zt1Service->getRoutes(s->_nwid);
ZeroTier::InetAddress target, nm, via;
for (int i=0; i<managed_routes->size(); i++) {
target = managed_routes->at(i).target;
nm = target.netmask();
via = managed_routes->at(i).via;
if (target.containsAddress(addr)) {
//DEBUG_EXTRA("chose tap with route <target=%s, nm=%s, via=%s>", target.toString(ipbuf), nm.toString(ipbuf2), via.toString(ipbuf3));
ZeroTier::_vtaps_lock.unlock();
return s;
}
}
}
}
ZeroTier::_vtaps_lock.unlock();
return tap;
}
ZeroTier::VirtualTap *getTapByName(char *ifname)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::VirtualTap *s, *tap = nullptr;
for (int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if (strcmp(s->_dev.c_str(), ifname) == false) {
tap = s;
}
}
ZeroTier::_vtaps_lock.unlock();
return tap;
}
ZeroTier::VirtualTap *getTapByIndex(int index)
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::VirtualTap *s, *tap = nullptr;
for (int i=0; i<ZeroTier::vtaps.size(); i++) {
s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
if (s->ifindex == index) {
tap = s;
}
}
ZeroTier::_vtaps_lock.unlock();
return tap;
}
ZeroTier::VirtualTap *getAnyTap()
{
ZeroTier::_vtaps_lock.lock();
ZeroTier::VirtualTap *vtap = NULL;
if (ZeroTier::vtaps.size()) {
vtap = (ZeroTier::VirtualTap *)ZeroTier::vtaps[0];
}
ZeroTier::_vtaps_lock.unlock();
return vtap;
}
int zts_get_device_id_from_file(const char *filepath, char *devID) {
std::string fname("identity.public");
std::string fpath(filepath);
if (ZeroTier::OSUtils::fileExists((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),false)) {
std::string oldid;
ZeroTier::OSUtils::readFile((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),oldid);
memcpy(devID, oldid.c_str(), 10); // first 10 bytes of file
return 0;
}
return -1;
}
// Starts a ZeroTier service in the background
void *zts_start_service(void *thread_id)
{
DEBUG_INFO("homeDir=%s", ZeroTier::homeDir.c_str());
// Where network .conf files will be stored
ZeroTier::netDir = ZeroTier::homeDir + "/networks.d";
ZeroTier::zt1Service = (ZeroTier::OneService *)0;
// Construct path for network config and supporting service files
if (ZeroTier::homeDir.length()) {
std::vector<std::string> hpsp(ZeroTier::OSUtils::split(ZeroTier::homeDir.c_str(), ZT_PATH_SEPARATOR_S,"",""));
std::string ptmp;
if (ZeroTier::homeDir[0] == ZT_PATH_SEPARATOR) {
ptmp.push_back(ZT_PATH_SEPARATOR);
}
for (std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
if (ptmp.length() > 0) {
ptmp.push_back(ZT_PATH_SEPARATOR);
}
ptmp.append(*pi);
if ((*pi != ".")&&(*pi != "..")) {
if (ZeroTier::OSUtils::mkdir(ptmp) == false) {
DEBUG_ERROR("home path does not exist, and could not create");
handle_general_failure();
perror("error\n");
}
}
}
}
else {
DEBUG_ERROR("homeDir is empty, could not construct path");
handle_general_failure();
return NULL;
}
// Generate random port for new service instance
unsigned int randp = 0;
ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
// TODO: Better port random range selection
int servicePort = 9000 + (randp % 1000);
for (;;) {
ZeroTier::zt1Service = ZeroTier::OneService::newInstance(ZeroTier::homeDir.c_str(),servicePort);
switch(ZeroTier::zt1Service->run()) {
case ZeroTier::OneService::ONE_STILL_RUNNING:
case ZeroTier::OneService::ONE_NORMAL_TERMINATION:
break;
case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR:
DEBUG_ERROR("ZTO service port = %d", servicePort);
DEBUG_ERROR("fatal error: %s",ZeroTier::zt1Service->fatalErrorMessage().c_str());
break;
case ZeroTier::OneService::ONE_IDENTITY_COLLISION: {
delete ZeroTier::zt1Service;
ZeroTier::zt1Service = (ZeroTier::OneService *)0;
std::string oldid;
ZeroTier::OSUtils::readFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret").c_str(),oldid);
if (oldid.length()) {
ZeroTier::OSUtils::writeFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret.saved_after_collision").c_str(),oldid);
ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.secret").c_str());
ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
+ "identity.public").c_str());
}
}
continue; // restart!
}
break; // terminate loop -- normally we don't keep restarting
}
delete ZeroTier::zt1Service;
ZeroTier::zt1Service = (ZeroTier::OneService *)0;
return NULL;
}
void disableTaps()
{
ZeroTier::_vtaps_lock.lock();
for (int i=0; i<ZeroTier::vtaps.size(); i++) {
DEBUG_EXTRA("vt=%p", ZeroTier::vtaps[i]);
((ZeroTier::VirtualTap*)ZeroTier::vtaps[i])->_enabled = false;
}
ZeroTier::_vtaps_lock.unlock();
}
void zts_get_ipv4_address(const char *nwid, char *addrstr, const int addrlen)
{
if (ZeroTier::zt1Service) {
uint64_t nwid_int = strtoull(nwid, NULL, 16);
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
if (tap && tap->_ips.size()) {
for (int i=0; i<tap->_ips.size(); i++) {
if (tap->_ips[i].isV4()) {
char ipbuf[INET_ADDRSTRLEN];
std::string addr = tap->_ips[i].toString(ipbuf);
int len = addrlen < addr.length() ? addrlen : addr.length();
memset(addrstr, 0, len);
memcpy(addrstr, addr.c_str(), len);
return;
}
}
}
}
else
memcpy(addrstr, "\0", 1);
}
void zts_get_ipv6_address(const char *nwid, char *addrstr, const int addrlen)
{
if (ZeroTier::zt1Service) {
uint64_t nwid_int = strtoull(nwid, NULL, 16);
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
if (tap && tap->_ips.size()) {
for (int i=0; i<tap->_ips.size(); i++) {
if (tap->_ips[i].isV6()) {
char ipbuf[INET6_ADDRSTRLEN];
std::string addr = tap->_ips[i].toString(ipbuf);
int len = addrlen < addr.length() ? addrlen : addr.length();
memset(addrstr, 0, len);
memcpy(addrstr, addr.c_str(), len);
return;
}
}
}
}
else
memcpy(addrstr, "\0", 1);
}
int zts_has_ipv4_address(const char *nwid)
{
char ipv4_addr[INET_ADDRSTRLEN];
memset(ipv4_addr, 0, INET_ADDRSTRLEN);
zts_get_ipv4_address(nwid, ipv4_addr, INET_ADDRSTRLEN);
return strcmp(ipv4_addr, "\0");
}
int zts_has_ipv6_address(const char *nwid)
{
char ipv6_addr[INET6_ADDRSTRLEN];
memset(ipv6_addr, 0, INET6_ADDRSTRLEN);
zts_get_ipv6_address(nwid, ipv6_addr, INET6_ADDRSTRLEN);
return strcmp(ipv6_addr, "\0");
}
int zts_has_address(const char *nwid)
{
return zts_has_ipv4_address(nwid) || zts_has_ipv6_address(nwid);
}
void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID)
{
ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv66plane(
ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID));
char ipbuf[INET6_ADDRSTRLEN];
memcpy(addr, _6planeAddr.toIpString(ipbuf), 40);
}
void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID)
{
ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv6rfc4193(
ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID));
char ipbuf[INET6_ADDRSTRLEN];
memcpy(addr, _6planeAddr.toIpString(ipbuf), 40);
}
void zts_join(const char * nwid) {
if (ZeroTier::zt1Service) {
std::string confFile = ZeroTier::zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf";
if (ZeroTier::OSUtils::mkdir(ZeroTier::netDir) == false) {
DEBUG_ERROR("unable to create: %s", ZeroTier::netDir.c_str());
handle_general_failure();
}
if (ZeroTier::OSUtils::writeFile(confFile.c_str(), "") == false) {
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
handle_general_failure();
}
ZeroTier::zt1Service->join(nwid);
}
// provide ZTO service reference to virtual taps
// TODO: This might prove to be unreliable, but it works for now
for (int i=0;i<ZeroTier::vtaps.size(); i++) {
ZeroTier::VirtualTap *s = (ZeroTier::VirtualTap*)ZeroTier::vtaps[i];
s->zt1ServiceRef=(void*)ZeroTier::zt1Service;
}
}
void zts_join_soft(const char * filepath, const char * nwid) {
std::string net_dir = std::string(filepath) + "/networks.d/";
std::string confFile = net_dir + std::string(nwid) + ".conf";
if (ZeroTier::OSUtils::mkdir(net_dir) == false) {
DEBUG_ERROR("unable to create: %s", net_dir.c_str());
handle_general_failure();
}
if (ZeroTier::OSUtils::fileExists(confFile.c_str(), false) == false) {
if (ZeroTier::OSUtils::writeFile(confFile.c_str(), "") == false) {
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
handle_general_failure();
}
}
}
void zts_leave(const char * nwid) {
if (ZeroTier::zt1Service) {
ZeroTier::zt1Service->leave(nwid);
}
}
void zts_leave_soft(const char * filepath, const char * nwid) {
std::string net_dir = std::string(filepath) + "/networks.d/";
ZeroTier::OSUtils::rm((net_dir + nwid + ".conf").c_str());
}
int zts_running() {
return ZeroTier::zt1Service == NULL ? false : ZeroTier::zt1Service->isRunning();
}
void zts_start(const char *path)
{
if (ZeroTier::zt1Service) {
return;
}
if (path) {
ZeroTier::homeDir = path;
}
pthread_t service_thread;
pthread_create(&service_thread, NULL, zts_start_service, NULL);
}
void zts_simple_start(const char *path, const char *nwid)
{
zts_start(path);
while (zts_running() == false) {
DEBUG_EXTRA("waiting for service to start");
nanosleep((const struct timespec[]) {{0, (ZTO_WRAPPER_CHECK_INTERVAL * 1000000)}}, NULL);
}
while (true) {
DEBUG_EXTRA("trying join");
try {
zts_join(nwid);
DEBUG_EXTRA("joined");
break;
}
catch( ... ) {
DEBUG_ERROR("there was a problem joining the virtual network");
handle_general_failure();
}
}
DEBUG_EXTRA("waiting for addresss");
while (zts_has_address(nwid) == false) {
nanosleep((const struct timespec[]) {{0, (ZTO_WRAPPER_CHECK_INTERVAL * 1000000)}}, NULL);
}
}
void zts_stop() {
if (ZeroTier::zt1Service) {
ZeroTier::zt1Service->terminate();
disableTaps();
}
}
void zts_get_homepath(char *homePath, int len) {
if (ZeroTier::homeDir.length()) {
memset(homePath, 0, len);
int buf_len = len < ZeroTier::homeDir.length() ? len : ZeroTier::homeDir.length();
memcpy(homePath, ZeroTier::homeDir.c_str(), buf_len);
}
}
void zts_core_version(char *ver) {
int major, minor, revision;
ZT_version(&major, &minor, &revision);
sprintf(ver, "%d.%d.%d", major, minor, revision);
}
void zts_lib_version(char *ver) {
//sprintf(ver, "%d.%d.%d", ZT_LIB_VERSION_MAJOR, ZT_LIB_VERSION_MINOR, ZT_LIB_VERSION_REVISION);
}
int zts_get_device_id(char *devID) {
if (ZeroTier::zt1Service) {
char id[ZTO_ID_LEN];
sprintf(id, "%lx",ZeroTier::zt1Service->getNode()->address());
memcpy(devID, id, ZTO_ID_LEN);
return 0;
}
else // Service isn't online, try to read ID from file
{
std::string fname("identity.public");
std::string fpath(ZeroTier::homeDir);
if (ZeroTier::OSUtils::fileExists((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),false)) {
std::string oldid;
ZeroTier::OSUtils::readFile((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),oldid);
memcpy(devID, oldid.c_str(), ZTO_ID_LEN); // first 10 bytes of file
return 0;
}
}
return -1;
}
unsigned long zts_get_peer_count() {
if (ZeroTier::zt1Service) {
return ZeroTier::zt1Service->getNode()->peers()->peerCount;
}
else {
return 0;
}
}
int zts_get_peer_address(char *peer, const char *devID) {
if (ZeroTier::zt1Service) {
ZT_PeerList *pl = ZeroTier::zt1Service->getNode()->peers();
// uint64_t addr;
for (int i=0; i<pl->peerCount; i++) {
// ZT_Peer *p = &(pl->peers[i]);
// DEBUG_INFO("peer[%d] = %lx", i, p->address);
}
return pl->peerCount;
}
else
return -1;
}
void zts_enable_http_control_plane()
{
// TODO
}
void zts_disable_http_control_plane()
{
// TODO
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,344 +0,0 @@
/*
* 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 <errno.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 "VirtualTap.hpp"
struct tcp_pcb;
struct netif;
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int lwip_err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
#define ERR_TO_ERRNO_TABLE_SIZE LWIP_ARRAYSIZE(lwip_err_to_errno_table)
#define lwip_err_to_errno(err) \
((unsigned)(-(signed)(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
lwip_err_to_errno_table[-(signed)(err)] : EIO)
#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)
#include "lwip/ip6_addr.h"
#include "ethip6.h"
#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_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
#define NETIF_SET_STATUS_CALLBACK struct netif *netif, netif_status_callback_fn status_callback
#define LWIP_TCP_SHUTDOWN_SIG struct tcp_pcb *pcb, int shut_rx, int shut_tx
#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);
extern "C" err_t tcp_shutdown(LWIP_TCP_SHUTDOWN_SIG);
//extern "C" void netif_set_status_callback(NETIF_SET_STATUS_CALLBACK);
namespace ZeroTier {
class VirtualTap;
class VirtualSocket;
/**
* lwIP network stack driver class
*/
class lwIP
{
public:
/**
* Set up an interface in the network stack for the VirtualTap
*/
void lwip_init_interface(VirtualTap *tap, const InetAddress &ip);
/**
* Returns the number of TCP PCBs currently allocated
*/
static int lwip_num_current_tcp_pcbs();
/**
* Returns the number of UDP PCBs currently allocated
*/
static int lwip_num_current_udp_pcbs();
/**
* Returns the number of RAW PCBs currently allocated
*/
static int lwip_num_current_raw_pcbs();
/**
* Returns the total number of PCBs of any time or state
*/
int lwip_num_total_pcbs();
/**
* Registers a DNS nameserver with the network stack
*/
int lwip_add_dns_nameserver(struct sockaddr *addr);
/**
* Un-registers a DNS nameserver from the network stack
*/
int lwip_del_dns_nameserver(struct sockaddr *addr);
/**
* Main stack loop
*/
void lwip_loop(VirtualTap *tap);
/**
* Packets from the ZeroTier virtual wire enter the stack here
*/
void lwip_eth_rx(VirtualTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
/**
* Creates a stack-specific "socket" or "VirtualSocket object"
*/
int lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol);
/**
* Connect to remote host via userspace network stack interface - Called from VirtualTap
*/
int lwip_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/**
* Bind to a userspace network stack interface - Called from VirtualTap
*/
int lwip_Bind(VirtualTap *tap, VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/**
* Listen for incoming VirtualSockets - Called from VirtualTap
*/
int lwip_Listen(VirtualSocket *vs, int backlog);
/**
* Accept an incoming VirtualSocket - Called from VirtualTap
*/
VirtualSocket* lwip_Accept(VirtualSocket *vs);
/**
* Read from RX buffer to application - Called from VirtualTap
*/
int lwip_Read(VirtualSocket *vs, bool lwip_invoked);
/**
* Write to userspace network stack - Called from VirtualTap
*/
int lwip_Write(VirtualSocket *vs, void *data, ssize_t len);
/**
* Close a VirtualSocket - Called from VirtualTap
*/
int lwip_Close(VirtualSocket *vs);
/**
* Shuts down some aspect of a VirtualSocket - Called from VirtualTap
*/
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);
/**
* Callback for handling received UDP packets (already processed by network stack)
*/
static err_t lwip_cb_tcp_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err);
/**
* Callback for handling accepted connection
*/
static err_t lwip_cb_accept(void *arg, struct tcp_pcb *newPCB, err_t err);
/**
* Callback for handling received TCP packets (already processed by stack)
*/
static void lwip_cb_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, const ip_addr_t * addr, u16_t port);
/**
* Callback for handling errors from within the network stack
*/
static void lwip_cb_err(void *arg, err_t err);
/**
* Callback for handling periodic background tasks
*/
static err_t lwip_cb_poll(void* arg, struct tcp_pcb *PCB);
/**
* Callback for handling confirmation of sent packets
*/
static err_t lwip_cb_sent(void *arg, struct tcp_pcb *PCB, u16_t len);
/**
* Callback for handling successful connections
*/
static err_t lwip_cb_connected(void *arg, struct tcp_pcb *PCB, err_t err);
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,231 +0,0 @@
/*
* 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.
*/
#ifndef ZT_PICOTCP_HPP
#define ZT_PICOTCP_HPP
#include "pico_eth.h"
#include "pico_stack.h"
#include "pico_ipv4.h"
#include "pico_icmp4.h"
#include "pico_dev_tap.h"
#include "pico_protocol.h"
#include "pico_socket.h"
#include "pico_device.h"
#include "pico_ipv6.h"
#include "VirtualTap.hpp"
/****************************************************************************/
/* PicoTCP API Signatures (See libzt.h for the application-facing API) */
/****************************************************************************/
#define PICO_IPV4_TO_STRING_SIG char *ipbuf, const uint32_t ip
#define PICO_TAP_CREATE_SIG char *name
#define PICO_IPV4_LINK_ADD_SIG struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask
#define PICO_DEVICE_INIT_SIG struct pico_device *dev, const char *name, uint8_t *mac
#define PICO_STACK_RECV_SIG struct pico_device *dev, uint8_t *buffer, uint32_t len
#define PICO_ICMP4_PING_SIG char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)
#define PICO_TIMER_ADD_SIG pico_time expire, void (*timer)(pico_time, void *), void *arg
#define PICO_STRING_TO_IPV4_SIG const char *ipstr, uint32_t *ip
#define PICO_STRING_TO_IPV6_SIG const char *ipstr, uint8_t *ip
#define PICO_SOCKET_SETOPTION_SIG struct pico_socket *s, int option, void *value
#define PICO_SOCKET_SEND_SIG struct pico_socket *s, const void *buf, int len
#define PICO_SOCKET_SENDTO_SIG struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port
#define PICO_SOCKET_RECV_SIG struct pico_socket *s, void *buf, int len
#define PICO_SOCKET_RECVFROM_SIG struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port
#define PICO_SOCKET_OPEN_SIG uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)
#define PICO_SOCKET_BIND_SIG struct pico_socket *s, void *local_addr, uint16_t *port
#define PICO_SOCKET_CONNECT_SIG struct pico_socket *s, const void *srv_addr, uint16_t remote_port
#define PICO_SOCKET_LISTEN_SIG struct pico_socket *s, const int backlog
#define PICO_SOCKET_READ_SIG struct pico_socket *s, void *buf, int len
#define PICO_SOCKET_WRITE_SIG struct pico_socket *s, const void *buf, int len
#define PICO_SOCKET_CLOSE_SIG struct pico_socket *s
#define PICO_SOCKET_SHUTDOWN_SIG struct pico_socket *s, int mode
#define PICO_SOCKET_ACCEPT_SIG struct pico_socket *s, void *orig, uint16_t *port
#define PICO_IPV6_LINK_ADD_SIG struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask
#define PICO_IPV4_ROUTE_ADD_SIG struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link
#define PICO_IPV4_ROUTE_DEL_SIG struct pico_ip4 address, struct pico_ip4 netmask, int metric
#define PICO_IPV6_ROUTE_ADD_SIG struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link
#define PICO_IPV6_ROUTE_DEL_SIG struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link
#define PICO_DNS_CLIENT_NAMESERVER_SIG pico_ip4*, unsigned char
namespace ZeroTier
{
/**
* Send raw frames from the stack to the ZeroTier virtual wire
*/
int pico_eth_tx(struct pico_device *dev, void *buf, int len);
/**
* Read raw frames from RX frame buffer into the stack
*/
int pico_eth_poll(struct pico_device *dev, int loop_score);
class VirtualTap;
class VirtualSocket;
/**
* picoTCP network stack driver class
*/
class picoTCP
{
public:
/**
* Set up an interface in the network stack for the VirtualTap
*/
bool pico_init_interface(ZeroTier::VirtualTap *tap);
/**
* Register an address with the stack
*/
bool pico_register_address(VirtualTap *tap, const InetAddress &ip);
/**
* Adds a route to the picoTCP device
*/
bool pico_route_add(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric);
/**
* Deletes a route from the picoTCP device
*/
bool pico_route_del(VirtualTap *tap, const InetAddress &addr, const InetAddress &nm, int metric);
/**
* Registers a DNS nameserver with the network stack
*/
int pico_add_dns_nameserver(struct sockaddr *addr);
/**
* Un-registers a DNS nameserver from the network stack
*/
int pico_del_dns_nameserver(struct sockaddr *addr);
/**
* Main stack loop
*/
void pico_loop(VirtualTap *tap);
/**
* Read bytes from the stack to the RX buffer (prepare to be read by app)
*/
static void pico_cb_tcp_read(VirtualTap *tap, struct pico_socket *s);
/**
* Read bytes from the stack to the RX buffer (prepare to be read by app)
*/
static void pico_cb_udp_read(VirtualTap *tap, struct pico_socket *s);
/**
* Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
*/
static void pico_cb_tcp_write(VirtualTap *tap, struct pico_socket *s);
/**
* Write bytes from TX buffer to stack (prepare to be sent to ZT virtual wire)
*/
static void pico_cb_socket_ev(uint16_t ev, struct pico_socket *s);
/**
* 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);
/**
* Creates a stack-specific "socket" or "VirtualSocket object"
*/
int pico_Socket(struct pico_socket **p, int socket_family, int socket_type, int protocol);
/**
* Connect to remote host via userspace network stack interface - Called from VirtualTap
*/
int pico_Connect(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/**
* Bind to a userspace network stack interface - Called from VirtualTap
*/
int pico_Bind(VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen);
/**
* Listen for incoming VirtualSockets - Called from VirtualTap
*/
int pico_Listen(VirtualSocket *vs, int backlog);
/**
* Accept an incoming VirtualSocket - Called from VirtualTap
*/
VirtualSocket* pico_Accept(VirtualSocket *vs);
/**
* Read from RX buffer to application - Called from VirtualTap
*/
int pico_Read(VirtualTap *tap, ZeroTier::PhySocket *sock, VirtualSocket *vs, bool stack_invoked);
/**
* Write to userspace network stack - Called from VirtualTap
*/
int pico_Write(VirtualSocket *vs, void *data, ssize_t len);
/**
* Close a VirtualSocket - Called from VirtualTap
*/
int pico_Close(VirtualSocket *vs);
/**
* Shuts down some aspect of a VirtualSocket - Called from VirtualTap
*/
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
*/
static int map_pico_err_to_errno(int err);
/**
* Converts picoTCP error codes to pretty string
*/
static char *beautify_pico_error(int err);
/**
* Converts picoTCP socket states into pretty string
*/
static char *beautify_pico_state(int state);
};
}
#endif