Introduction of sequential-API build variant, better thread safety (lwIP only)
This commit is contained in:
68
src/Platform.cpp
Normal file
68
src/Platform.cpp
Normal 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
|
||||
@@ -24,6 +24,12 @@
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Ring buffer implementation for network stack drivers
|
||||
*/
|
||||
|
||||
#ifndef ZT_RINGBUFFER_HPP
|
||||
#define ZT_RINGBUFFER_HPP
|
||||
|
||||
|
||||
@@ -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))
|
||||
);
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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
119
src/VirtualSocket.cpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
508
src/ZT1Service.cpp
Normal 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
|
||||
2037
src/libzt.cpp
2037
src/libzt.cpp
File diff suppressed because it is too large
Load Diff
1881
src/lwIP.cpp
1881
src/lwIP.cpp
File diff suppressed because it is too large
Load Diff
344
src/lwIP.hpp
344
src/lwIP.hpp
@@ -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
|
||||
1983
src/picoTCP.cpp
1983
src/picoTCP.cpp
File diff suppressed because it is too large
Load Diff
231
src/picoTCP.hpp
231
src/picoTCP.hpp
@@ -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
|
||||
Reference in New Issue
Block a user