Added selectable TCP_WRITE_FLAG_COPY mode on a per-socket basis, updated lwIP driver for socket limit checks
This commit is contained in:
4
FAQ.md
4
FAQ.md
@@ -7,4 +7,6 @@ Yes! - Just let us know, and we will work out a licensing scheme. You will need
|
||||
|
||||
### Application or service won't fully come online
|
||||
|
||||
Sometimes it can take a substatial amount of time for libzt to come online and become reachable. In cases where it never seems to progress beyond this stage you should check to make sure there are no rogue processes on the machines using the same ZeroTier identity files, or no other instances on your ZeroTier network using said identity files. If this doesn't help. Contact us.
|
||||
In rare circumstances it can take a substantial amount of time for a libzt instance to come online and become reachable. In cases where it never seems to progress beyond this stage you should check to make sure there are no rogue processes on the machines using the same ZeroTier identity files, or no other instances on your ZeroTier network using said identity files. If this doesn't help. Contact us.
|
||||
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ int zts_get_pico_socket(int fd, struct pico_socket **s);
|
||||
/*
|
||||
* Whether we can add a new socket or not. Depends on stack in use
|
||||
*/
|
||||
bool can_provision_new_socket();
|
||||
bool can_provision_new_socket(int socket_type);
|
||||
|
||||
/**
|
||||
* Returns the number of sockets either already provisioned or waiting to be
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#if defined(STACK_PICO)
|
||||
#include "pico_socket.h"
|
||||
#endif
|
||||
#if defined(STACK_LWIP)
|
||||
#include "lwip/tcp.h"
|
||||
#endif
|
||||
|
||||
#include "Phy.hpp"
|
||||
|
||||
@@ -65,6 +68,18 @@ namespace ZeroTier {
|
||||
#endif
|
||||
#if defined(STACK_LWIP)
|
||||
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
|
||||
|
||||
@@ -359,7 +359,7 @@ namespace ZeroTier {
|
||||
for(int i=0; i<_VirtualSockets.size(); i++) {
|
||||
if(vs == _VirtualSockets[i]) {
|
||||
_VirtualSockets.erase(_VirtualSockets.begin() + i);
|
||||
DEBUG_INFO("Removed vs=%p from vt=%p", vs, this);
|
||||
//DEBUG_EXTRA("Removed vs=%p from vt=%p", vs, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ Darwin:
|
||||
[--] [EMFILE] The per-process descriptor table is full.
|
||||
[NA] [ENFILE] The system file table is full.
|
||||
[ ] [ENOBUFS] Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed.
|
||||
[ ] [ENOMEM] Insufficient memory was available to fulfill the request.
|
||||
[--] [ENOMEM] Insufficient memory was available to fulfill the request.
|
||||
[--] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain.
|
||||
[ ] [EPROTOTYPE] The socket type is not supported by the protocol.
|
||||
*/
|
||||
@@ -394,9 +394,7 @@ int zts_socket(ZT_SOCKET_SIG) {
|
||||
errno = EPROTONOSUPPORT; // seemingly closest match
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(socket_type == SOCK_RAW)
|
||||
{
|
||||
if(socket_type == SOCK_RAW) {
|
||||
// VirtualSocket is only used to associate a socket with a VirtualTap, it has no other implication
|
||||
ZeroTier::VirtualSocket *vs = new ZeroTier::VirtualSocket();
|
||||
vs->socket_family = socket_family;
|
||||
@@ -405,7 +403,6 @@ int zts_socket(ZT_SOCKET_SIG) {
|
||||
add_unassigned_virtual_socket(vs->app_fd, vs);
|
||||
return vs->app_fd;
|
||||
}
|
||||
|
||||
#if defined(STACK_PICO)
|
||||
struct pico_socket *p;
|
||||
err = ZeroTier::picostack->pico_Socket(&p, socket_family, socket_type, protocol);
|
||||
@@ -419,10 +416,10 @@ int zts_socket(ZT_SOCKET_SIG) {
|
||||
}
|
||||
else {
|
||||
DEBUG_ERROR("failed to create pico_socket");
|
||||
errno = ENOMEM;
|
||||
err = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STACK_LWIP)
|
||||
// TODO: check for max lwIP timers/sockets
|
||||
void *pcb;
|
||||
@@ -433,10 +430,12 @@ int zts_socket(ZT_SOCKET_SIG) {
|
||||
vs->socket_type = socket_type;
|
||||
vs->pcb = pcb;
|
||||
add_unassigned_virtual_socket(vs->app_fd, vs);
|
||||
err = vs->app_fd; // return one end of the socketpair
|
||||
// return one end of the socketpair for the app to use
|
||||
err = vs->app_fd;
|
||||
}
|
||||
else {
|
||||
DEBUG_ERROR("failed to create lwip pcb");
|
||||
errno = ENOMEM;
|
||||
err = -1;
|
||||
}
|
||||
#endif
|
||||
@@ -777,8 +776,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
|
||||
errno = EINVAL; // TODO, not actually a valid error for this function
|
||||
return -1;
|
||||
}
|
||||
// since we'll be creating a new stack socket or protocol control block when we accept the connection
|
||||
if(!can_provision_new_socket()) {
|
||||
if(!can_provision_new_socket(SOCK_STREAM)) {
|
||||
DEBUG_ERROR("cannot provision additional socket due to limitation of network stack");
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
@@ -806,7 +804,7 @@ int zts_accept(ZT_ACCEPT_SIG) {
|
||||
ZeroTier::VirtualSocket *accepted_vs;
|
||||
if(!err) {
|
||||
if(!blocking) { // non-blocking
|
||||
DEBUG_EXTRA("EWOULDBLOCK, not a real error, assuming non-blocking mode");
|
||||
DEBUG_EXTRA("EWOULDBLOCK, assuming non-blocking mode");
|
||||
errno = EWOULDBLOCK;
|
||||
err = -1;
|
||||
accepted_vs = tap->Accept(vs);
|
||||
@@ -1566,7 +1564,7 @@ ssize_t zts_recv(ZT_RECV_SIG)
|
||||
|
||||
ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
|
||||
{
|
||||
DEBUG_TRANS("fd=%d", fd);
|
||||
//DEBUG_TRANS("fd=%d", fd);
|
||||
int32_t r = 0;
|
||||
errno = 0;
|
||||
if(fd < 0 || fd >= ZT_MAX_SOCKETS) {
|
||||
@@ -1590,7 +1588,6 @@ ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
|
||||
// PEEK at the buffer and see if we can read a length, if not, err out
|
||||
r = recv(fd, msg_ptr, sizeof(int32_t), MSG_PEEK);
|
||||
if(r != sizeof(int32_t)){
|
||||
//DEBUG_ERROR("invalid datagram, PEEK, r=%d", r);
|
||||
errno = EIO; // TODO: test for this
|
||||
return -1;
|
||||
}
|
||||
@@ -2019,20 +2016,26 @@ int zts_get_pico_socket(int fd, struct pico_socket **s)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool can_provision_new_socket()
|
||||
bool can_provision_new_socket(int socket_type)
|
||||
{
|
||||
#if defined(STACK_PICO)
|
||||
if(pico_ntimers()+1 >= PICO_MAX_TIMERS) {
|
||||
return false;
|
||||
return !(pico_ntimers()+1 > PICO_MAX_TIMERS);
|
||||
#endif
|
||||
#if defined(STACK_LWIP)
|
||||
if(socket_type == SOCK_STREAM) {
|
||||
return !(ZeroTier::lwIP::lwip_num_current_tcp_pcbs()+1 > MEMP_NUM_TCP_PCB);
|
||||
}
|
||||
if(socket_type == SOCK_DGRAM) {
|
||||
return !(ZeroTier::lwIP::lwip_num_current_udp_pcbs()+1 > MEMP_NUM_UDP_PCB);
|
||||
}
|
||||
if(socket_type == SOCK_RAW) {
|
||||
return !(ZeroTier::lwIP::lwip_num_current_raw_pcbs()+1 > MEMP_NUM_RAW_PCB);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
#if defined(STACK_LWIP)
|
||||
// TODO: Add check here (see lwipopts.h)
|
||||
return true;
|
||||
#endif
|
||||
#if defined(NO_STACK)
|
||||
return true; // always true since there's no network stack timer limitation
|
||||
// always true since there's no network stack timer/memory limitation
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2186,13 +2189,13 @@ void del_virtual_socket(int fd)
|
||||
{
|
||||
ZeroTier::_multiplexer_lock.lock();
|
||||
std::map<int, ZeroTier::VirtualSocket*>::iterator un_iter = ZeroTier::unmap.find(fd);
|
||||
if(un_iter != ZeroTier::unmap.end()) {
|
||||
ZeroTier::unmap.erase(un_iter);
|
||||
}
|
||||
if(un_iter != ZeroTier::unmap.end()) {
|
||||
ZeroTier::unmap.erase(un_iter);
|
||||
}
|
||||
std::map<int, std::pair<ZeroTier::VirtualSocket*,ZeroTier::VirtualTap*>*>::iterator fd_iter = ZeroTier::fdmap.find(fd);
|
||||
if(fd_iter != ZeroTier::fdmap.end()) {
|
||||
if(fd_iter != ZeroTier::fdmap.end()) {
|
||||
ZeroTier::fdmap.erase(fd_iter);
|
||||
}
|
||||
}
|
||||
ZeroTier::_multiplexer_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
214
src/lwIP.cpp
214
src/lwIP.cpp
@@ -24,7 +24,17 @@
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
// lwIP network stack driver
|
||||
/*
|
||||
|
||||
lwIP network stack driver
|
||||
|
||||
NOTES:
|
||||
|
||||
Calls made in this network stack driver may never block since all packet
|
||||
processing (input and output) as well as timer processing (TCP mainly) is done
|
||||
in a single execution context.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -36,6 +46,8 @@
|
||||
#include "netif/ethernet.h"
|
||||
#include "lwip/etharp.h"
|
||||
|
||||
#include "priv/tcp_priv.h"
|
||||
|
||||
#if defined(LIBZT_IPV6)
|
||||
#include "lwip/ethip6.h"
|
||||
#include "lwip/nd6.h"
|
||||
@@ -169,6 +181,64 @@ namespace ZeroTier
|
||||
}
|
||||
}
|
||||
|
||||
int lwIP::lwip_num_current_tcp_pcbs()
|
||||
{
|
||||
// TODO: These will likely need some sort of locking protection
|
||||
int count = 0;
|
||||
struct tcp_pcb *pcb_ptr = tcp_active_pcbs; // PCBs that can RX/TX data
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- tcp_active_pcbs PCB COUNT = %d", count);
|
||||
}
|
||||
pcb_ptr = tcp_tw_pcbs; // PCBs in TIME-WAIT state
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- tcp_tw_pcbs PCB COUNT = %d", count);
|
||||
}
|
||||
/* TODO
|
||||
pcb_ptr = tcp_listen_pcbs;
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- tcp_listen_pcbs PCB COUNT = %d", count);
|
||||
}*/
|
||||
pcb_ptr = tcp_bound_pcbs; // PCBs in a bound state
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- tcp_bound_pcbs PCB COUNT = %d", count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int lwIP::lwip_num_current_udp_pcbs()
|
||||
{
|
||||
// TODO: These will likely need some sort of locking protection
|
||||
int count = 0;
|
||||
struct udp_pcb *pcb_ptr = udp_pcbs;
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- udp_pcbs PCB COUNT = %d", count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int lwIP::lwip_num_current_raw_pcbs()
|
||||
{
|
||||
// TODO: These will likely need some sort of locking protection
|
||||
int count = 0;
|
||||
struct raw_pcb *pcb_ptr = raw_pcbs;
|
||||
while(pcb_ptr) {
|
||||
pcb_ptr = pcb_ptr->next;
|
||||
count++;
|
||||
DEBUG_ERROR("FOUND --- raw_pcbs PCB COUNT = %d", count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int lwIP::lwip_add_dns_nameserver(struct sockaddr *addr)
|
||||
{
|
||||
return -1;
|
||||
@@ -280,8 +350,7 @@ namespace ZeroTier
|
||||
|
||||
int lwIP::lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol)
|
||||
{
|
||||
//DEBUG_INFO();
|
||||
if(!can_provision_new_socket()) {
|
||||
if(!can_provision_new_socket(socket_type)) {
|
||||
DEBUG_ERROR("unable to create new socket due to limitation of network stack");
|
||||
return -1;
|
||||
}
|
||||
@@ -340,49 +409,15 @@ namespace ZeroTier
|
||||
tcp_poll(tpcb, lwip_cb_poll, LWIP_APPLICATION_POLL_FREQ);
|
||||
tcp_arg(tpcb, vs);
|
||||
|
||||
//DEBUG_EXTRA(" pcb->state=%x", vs->TCP_pcb->state);
|
||||
//if(vs->TCP_pcb->state != CLOSED) {
|
||||
// DEBUG_INFO(" cannot connect using this PCB, PCB!=CLOSED");
|
||||
// tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN);
|
||||
// return;
|
||||
//}
|
||||
if((err = tcp_connect(tpcb,&ba,port,lwip_cb_connected)) < 0)
|
||||
{
|
||||
if(err == ERR_ISCONN) {
|
||||
// Already in connected state
|
||||
errno = EISCONN;
|
||||
return -1;
|
||||
} if(err == ERR_USE) {
|
||||
// Already in use
|
||||
errno = EADDRINUSE;
|
||||
return -1;
|
||||
} if(err == ERR_VAL) {
|
||||
// Invalid ipaddress parameter
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
} if(err == ERR_RTE) {
|
||||
// No route to host
|
||||
errno = ENETUNREACH;
|
||||
return -1;
|
||||
} if(err == ERR_BUF) {
|
||||
// No more ports available
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
if(err == ERR_MEM) {
|
||||
// TODO: Doesn't describe the problem well, but closest match
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
errno = lwip_err_to_errno(err);
|
||||
// We should only return a value if failure happens immediately
|
||||
// Otherwise, we still need to wait for a callback from lwIP.
|
||||
// - This is because an ERR_OK from tcp_connect() only verifies
|
||||
// that the SYN packet was enqueued onto the stack properly,
|
||||
// that's it!
|
||||
// - Most instances of a retval for a connect() should happen
|
||||
// in the nc_connect() and lwip_cb_err() callbacks!
|
||||
DEBUG_ERROR("unable to connect");
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -391,12 +426,12 @@ namespace ZeroTier
|
||||
|
||||
int lwIP::lwip_Bind(VirtualTap *tap, VirtualSocket *vs, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
// TODO: Check case for IP_ADDR_ANY
|
||||
//DEBUG_EXTRA("vs=%p", vs);
|
||||
ip_addr_t ba;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
memset(addrstr, 0, INET6_ADDRSTRLEN);
|
||||
int port = 0, err = 0;
|
||||
|
||||
#if defined(LIBZT_IPV4)
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in *)addr;
|
||||
if(addr->sa_family == AF_INET) {
|
||||
@@ -415,38 +450,23 @@ namespace ZeroTier
|
||||
}
|
||||
#endif
|
||||
if(vs->socket_type == SOCK_DGRAM) {
|
||||
err = udp_bind((struct udp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port);
|
||||
if(err == ERR_USE) {
|
||||
if((err = udp_bind((struct udp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port)) < 0) {
|
||||
errno = lwip_err_to_errno(err);
|
||||
err = -1;
|
||||
errno = EADDRINUSE; // port in use
|
||||
}
|
||||
else {
|
||||
// set the recv callback
|
||||
// set callback
|
||||
udp_recv((struct udp_pcb*)vs->pcb, lwip_cb_udp_recved, vs);
|
||||
err = ERR_OK;
|
||||
errno = ERR_OK; // success
|
||||
}
|
||||
}
|
||||
else if (vs->socket_type == SOCK_STREAM) {
|
||||
err = tcp_bind((struct tcp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port);
|
||||
if(err != ERR_OK) {
|
||||
DEBUG_ERROR("err=%d", err);
|
||||
if(err == ERR_USE){
|
||||
err = -1;
|
||||
errno = EADDRINUSE;
|
||||
}
|
||||
if(err == ERR_MEM){
|
||||
err = -1;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
if(err == ERR_BUF){
|
||||
err = -1;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
if((err = tcp_bind((struct tcp_pcb*)vs->pcb, (const ip_addr_t *)&ba, port)) < 0) {
|
||||
errno = lwip_err_to_errno(err);
|
||||
err = -1;
|
||||
}
|
||||
else {
|
||||
err = ERR_OK;
|
||||
errno = ERR_OK; // success
|
||||
}
|
||||
}
|
||||
return err;
|
||||
@@ -454,19 +474,25 @@ namespace ZeroTier
|
||||
|
||||
int lwIP::lwip_Listen(VirtualSocket *vs, int backlog)
|
||||
{
|
||||
//DEBUG_INFO("vs=%p", vs);
|
||||
int err = 0;
|
||||
struct tcp_pcb* listeningPCB;
|
||||
#ifdef TCP_LISTEN_BACKLOG
|
||||
listeningPCB = tcp_listen_with_backlog((struct tcp_pcb*)vs->pcb, backlog);
|
||||
#else
|
||||
listeningPCB = tcp_listen((struct tcp_pcb*)vs->pcb);
|
||||
#endif
|
||||
if(listeningPCB != NULL) {
|
||||
if(listeningPCB) {
|
||||
vs->pcb = listeningPCB;
|
||||
tcp_accept(listeningPCB, lwip_cb_accept); // set callback
|
||||
// set callback
|
||||
tcp_accept(listeningPCB, lwip_cb_accept);
|
||||
tcp_arg(listeningPCB, vs);
|
||||
err = ERR_OK;
|
||||
}
|
||||
return 0;
|
||||
else {
|
||||
errno = ENOMEM;
|
||||
err = -1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
VirtualSocket* lwIP::lwip_Accept(VirtualSocket *vs)
|
||||
@@ -536,11 +562,10 @@ namespace ZeroTier
|
||||
DEBUG_ERROR("no virtual socket");
|
||||
return -1;
|
||||
}
|
||||
if(vs->socket_type == SOCK_DGRAM)
|
||||
{
|
||||
if(vs->socket_type == SOCK_DGRAM) {
|
||||
// TODO: Packet re-assembly hasn't yet been tested with lwIP so UDP packets are limited to MTU-sized chunks
|
||||
int udp_trans_len = std::min(len, (ssize_t)ZT_MAX_MTU);
|
||||
//DEBUG_EXTRA("allocating pbuf chain of size=%d for UDP packet", udp_trans_len);
|
||||
// DEBUG_EXTRA("allocating pbuf chain of size=%d for UDP packet", udp_trans_len);
|
||||
struct pbuf * pb = pbuf_alloc(PBUF_TRANSPORT, udp_trans_len, PBUF_POOL);
|
||||
if(!pb){
|
||||
DEBUG_ERROR("unable to allocate new pbuf of size=%d", vs->TXbuf->count());
|
||||
@@ -561,8 +586,7 @@ namespace ZeroTier
|
||||
return udp_trans_len;
|
||||
}
|
||||
}
|
||||
if(vs->socket_type == SOCK_STREAM)
|
||||
{
|
||||
if(vs->socket_type == SOCK_STREAM) {
|
||||
// How much we are currently allowed to write to the VirtualSocket
|
||||
ssize_t sndbuf = ((struct tcp_pcb*)vs->pcb)->snd_buf;
|
||||
int err, r;
|
||||
@@ -589,7 +613,8 @@ namespace ZeroTier
|
||||
// Writes data pulled from the client's socket buffer to LWIP. This merely sends the
|
||||
// data to LWIP to be enqueued and eventually sent to the network.
|
||||
if(r > 0) {
|
||||
err = tcp_write((struct tcp_pcb*)vs->pcb, vs->TXbuf->get_buf(), r, TCP_WRITE_FLAG_COPY);
|
||||
|
||||
err = tcp_write((struct tcp_pcb*)vs->pcb, vs->TXbuf->get_buf(), r, vs->copymode);
|
||||
tcp_output((struct tcp_pcb*)vs->pcb);
|
||||
if(err != ERR_OK) {
|
||||
DEBUG_ERROR("error while writing to lwIP tcp_pcb, err=%d", err);
|
||||
@@ -597,7 +622,15 @@ namespace ZeroTier
|
||||
DEBUG_ERROR("lwIP out of memory");
|
||||
return -1;
|
||||
} else {
|
||||
vs->TXbuf->consume(r); // success
|
||||
if(vs->copymode & TCP_WRITE_FLAG_COPY) {
|
||||
// since we copied the data (allocated pbufs), we can consume the buffer
|
||||
vs->TXbuf->consume(r); // success
|
||||
}
|
||||
else {
|
||||
// since we only processed the data by pointer reference we
|
||||
// want to preserve it until it has been ACKed by the remote host
|
||||
// (DO NOTHING)
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
@@ -835,17 +868,16 @@ namespace ZeroTier
|
||||
err_t lwIP::lwip_cb_sent(void* arg, struct tcp_pcb *PCB, u16_t len)
|
||||
{
|
||||
//DEBUG_EXTRA("pcb=%p", PCB);
|
||||
/*
|
||||
VirtualSocket *vs = (VirtualSocket *)arg;
|
||||
Mutex::Lock _l(vs->tap->_tcpconns_m);
|
||||
if(vs && len) {
|
||||
int softmax = vs->socket_type == SOCK_STREAM ? ZT_TCP_TX_BUF_SZ : ZT_UDP_TX_BUF_SZ;
|
||||
if(vs->TXbuf->count() < softmax) {
|
||||
vs->tap->_phy.setNotifyReadable(vs->sock, true);
|
||||
vs->tap->_phy.whack();
|
||||
}
|
||||
if(!vs){
|
||||
DEBUG_ERROR("invalid vs for PCB=%p, len=%d", PCB, len);
|
||||
}
|
||||
if(!(vs->copymode & TCP_WRITE_FLAG_COPY)) {
|
||||
// since we decided in lwip_Write() not to consume the buffere data, as it
|
||||
// was not copied and was only used by pointer reference, we can now consume
|
||||
// the data on the buffer since we've got an ACK back from the remote host
|
||||
vs->TXbuf->consume(len);
|
||||
}
|
||||
*/
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -875,79 +907,63 @@ namespace ZeroTier
|
||||
VirtualSocket *vs = (VirtualSocket *)arg;
|
||||
if(!vs){
|
||||
DEBUG_ERROR("err=%d, invalid virtual socket", err);
|
||||
errno = -1; // FIXME: Find more appropriate value
|
||||
errno = -1;
|
||||
}
|
||||
DEBUG_ERROR("vs=%p, pcb=%p, fd=%d, err=%d", vs, vs->pcb, vs->app_fd, err);
|
||||
vs->tap->Close(vs);
|
||||
|
||||
switch(err)
|
||||
{
|
||||
case ERR_MEM: // -1
|
||||
DEBUG_ERROR("ERR_MEM->ENOMEM, Out of memory error.");
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case ERR_BUF: // -2
|
||||
DEBUG_ERROR("ERR_BUF->ENOBUFS, Buffer error.");
|
||||
errno = ENOBUFS;
|
||||
break;
|
||||
case ERR_TIMEOUT: // -3
|
||||
DEBUG_ERROR("ERR_TIMEOUT->ETIMEDOUT, Timeout.");
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
case ERR_RTE: // -4
|
||||
DEBUG_ERROR("ERR_RTE->ENETUNREACH, Routing problem.");
|
||||
errno = ENETUNREACH;
|
||||
break;
|
||||
case ERR_INPROGRESS: // -5
|
||||
DEBUG_ERROR("ERR_INPROGRESS->EINPROGRESS, Operation in progress.");
|
||||
errno = EINPROGRESS;
|
||||
break;
|
||||
case ERR_VAL: // -6
|
||||
DEBUG_ERROR("ERR_VAL->EINVAL, Illegal value.");
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case ERR_WOULDBLOCK: // -7
|
||||
DEBUG_ERROR("ERR_WOULDBLOCK->EWOULDBLOCK, Operation would block.");
|
||||
errno = EWOULDBLOCK;
|
||||
break;
|
||||
case ERR_USE: // -8
|
||||
DEBUG_ERROR("ERR_USE->EADDRINUSE, Address in use.");
|
||||
errno = EADDRINUSE;
|
||||
break;
|
||||
case ERR_ALREADY: // -9 ?
|
||||
DEBUG_ERROR("ERR_ALREADY->EISCONN, Already connecting.");
|
||||
errno = EISCONN;
|
||||
break;
|
||||
case ERR_ISCONN: // -10
|
||||
DEBUG_ERROR("ERR_ISCONN->EISCONN, Already connected");
|
||||
errno = EISCONN;
|
||||
break;
|
||||
case ERR_CONN: // -11 ?
|
||||
DEBUG_ERROR("ERR_CONN->EISCONN, Not connected");
|
||||
errno = EISCONN;
|
||||
break;
|
||||
case ERR_IF: // -12
|
||||
DEBUG_ERROR("ERR_IF, Low-level netif error.");
|
||||
errno = -1;
|
||||
break;
|
||||
case ERR_ABRT: // -13
|
||||
DEBUG_ERROR("ERR_ABRT, Connection aborted.");
|
||||
errno = -1;
|
||||
break;
|
||||
case ERR_RST: // -14
|
||||
DEBUG_ERROR("ERR_RST, Connection reset.");
|
||||
errno = -1;
|
||||
break;
|
||||
case ERR_CLSD: // -15
|
||||
DEBUG_ERROR("ERR_CLSD, Connection closed.");
|
||||
errno = -1;
|
||||
break;
|
||||
case ERR_ARG: // -16
|
||||
DEBUG_ERROR("ERR_ARG, Illegal argument.");
|
||||
errno = -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errno = lwip_err_to_errno(err);
|
||||
}
|
||||
}
|
||||
|
||||
43
src/lwIP.hpp
43
src/lwIP.hpp
@@ -50,6 +50,34 @@
|
||||
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
|
||||
@@ -173,6 +201,21 @@ namespace ZeroTier {
|
||||
*/
|
||||
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();
|
||||
|
||||
/*
|
||||
* Registers a DNS nameserver with the network stack
|
||||
*/
|
||||
|
||||
@@ -744,7 +744,7 @@ namespace ZeroTier {
|
||||
int picoTCP::pico_Socket(struct pico_socket **p, int socket_family, int socket_type, int protocol)
|
||||
{
|
||||
int err = 0;
|
||||
if(!can_provision_new_socket()) {
|
||||
if(!can_provision_new_socket(socket_type)) {
|
||||
DEBUG_ERROR("cannot create additional socket, see PICO_MAX_TIMERS. current=%d", pico_ntimers());
|
||||
errno = EMFILE;
|
||||
err = -1;
|
||||
|
||||
@@ -742,7 +742,7 @@ void udp_server_6(UDP_UNIT_TEST_SIG_6)
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&saddr;
|
||||
int serverlen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
if((r = RECVFROM(fd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen)) < 0) {
|
||||
if((r = RECVFROM(fd, rbuf, len, 0, (struct sockaddr *)&saddr, (socklen_t *)&serverlen)) < 0) {
|
||||
perror("recvfrom");
|
||||
*passed = false;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user