Added selectable TCP_WRITE_FLAG_COPY mode on a per-socket basis, updated lwIP driver for socket limit checks
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user