mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
Unix domain sockets in Phy<>
This commit is contained in:
parent
b11ffc9635
commit
4838cbc350
3 changed files with 186 additions and 13 deletions
187
osdep/Phy.hpp
187
osdep/Phy.hpp
|
@ -93,6 +93,10 @@ typedef void PhySocket;
|
||||||
* phyOnTcpClose(PhySocket *sock,void **uptr)
|
* phyOnTcpClose(PhySocket *sock,void **uptr)
|
||||||
* phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
* phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||||
* phyOnTcpWritable(PhySocket *sock,void **uptr)
|
* phyOnTcpWritable(PhySocket *sock,void **uptr)
|
||||||
|
* phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN)
|
||||||
|
* phyOnUnixClose(PhySocket *sock,void **uptr)
|
||||||
|
* phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||||
|
* phyOnUnixWritable(PhySocket *sock,void **uptr)
|
||||||
*
|
*
|
||||||
* These templates typically refer to function objects. Templates are used to
|
* These templates typically refer to function objects. Templates are used to
|
||||||
* avoid the call overhead of indirection, which is surprisingly high for high
|
* avoid the call overhead of indirection, which is surprisingly high for high
|
||||||
|
@ -105,6 +109,9 @@ typedef void PhySocket;
|
||||||
* uptr: sockL and uptrL for the listen socket, and sockN and uptrN for
|
* uptr: sockL and uptrL for the listen socket, and sockN and uptrN for
|
||||||
* the new TCP connection socket that has just been created.
|
* the new TCP connection socket that has just been created.
|
||||||
*
|
*
|
||||||
|
* Note that phyOnUnix*() are only required and will only be used on systems
|
||||||
|
* that support Unix domain sockets.
|
||||||
|
*
|
||||||
* Handlers are always called. On outgoing TCP connection, CONNECT is always
|
* Handlers are always called. On outgoing TCP connection, CONNECT is always
|
||||||
* called on either success or failure followed by DATA and/or WRITABLE as
|
* called on either success or failure followed by DATA and/or WRITABLE as
|
||||||
* indicated. On socket close, handlers are called unless close() is told
|
* indicated. On socket close, handlers are called unless close() is told
|
||||||
|
@ -129,7 +136,9 @@ private:
|
||||||
ZT_PHY_SOCKET_TCP_IN = 0x03,
|
ZT_PHY_SOCKET_TCP_IN = 0x03,
|
||||||
ZT_PHY_SOCKET_TCP_LISTEN = 0x04,
|
ZT_PHY_SOCKET_TCP_LISTEN = 0x04,
|
||||||
ZT_PHY_SOCKET_RAW = 0x05,
|
ZT_PHY_SOCKET_RAW = 0x05,
|
||||||
ZT_PHY_SOCKET_UDP = 0x06
|
ZT_PHY_SOCKET_UDP = 0x06,
|
||||||
|
ZT_PHY_SOCKET_UNIX_IN = 0x07,
|
||||||
|
ZT_PHY_SOCKET_UNIX_LISTEN = 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PhySocketImpl
|
struct PhySocketImpl
|
||||||
|
@ -358,6 +367,64 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __UNIX_LIKE__
|
||||||
|
/**
|
||||||
|
* Listen for connections on a Unix domain socket
|
||||||
|
*
|
||||||
|
* @param path Path to Unix domain socket
|
||||||
|
* @param uptr Arbitrary pointer to associate
|
||||||
|
* @return PhySocket or NULL if cannot bind
|
||||||
|
*/
|
||||||
|
inline PhySocket *unixListen(const char *path,void *uptr = (void *)0)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
|
||||||
|
if (_socks.size() >= ZT_PHY_MAX_SOCKETS)
|
||||||
|
return (PhySocket *)0;
|
||||||
|
|
||||||
|
memset(&sun,0,sizeof(sun));
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
if (strlen(path) >= sizeof(sun.sun_path))
|
||||||
|
return (PhySocket *)0;
|
||||||
|
strcpy(sun.sun_path,path);
|
||||||
|
|
||||||
|
ZT_PHY_SOCKFD_TYPE s = ::socket(PF_UNIX,SOCK_STREAM,0);
|
||||||
|
if (!ZT_PHY_SOCKFD_VALID(s))
|
||||||
|
return (PhySocket *)0;
|
||||||
|
|
||||||
|
::fcntl(s,F_SETFL,O_NONBLOCK);
|
||||||
|
|
||||||
|
::unlink(path);
|
||||||
|
if (::bind(s,(struct sockaddr *)&sun,sizeof(struct sockaddr_un)) != 0) {
|
||||||
|
ZT_PHY_CLOSE_SOCKET(s);
|
||||||
|
return (PhySocket *)0;
|
||||||
|
}
|
||||||
|
if (::listen(s,128) != 0) {
|
||||||
|
ZT_PHY_CLOSE_SOCKET(s);
|
||||||
|
return (PhySocket *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_socks.push_back(PhySocketImpl());
|
||||||
|
} catch ( ... ) {
|
||||||
|
ZT_PHY_CLOSE_SOCKET(s);
|
||||||
|
return (PhySocket *)0;
|
||||||
|
}
|
||||||
|
PhySocketImpl &sws = _socks.back();
|
||||||
|
|
||||||
|
if ((long)s > _nfds)
|
||||||
|
_nfds = (long)s;
|
||||||
|
FD_SET(s,&_readfds);
|
||||||
|
sws.type = ZT_PHY_SOCKET_UNIX_LISTEN;
|
||||||
|
sws.sock = s;
|
||||||
|
sws.uptr = uptr;
|
||||||
|
memset(&(sws.saddr),0,sizeof(struct sockaddr_storage));
|
||||||
|
memcpy(&(sws.saddr),&sun,sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
|
return (PhySocket *)&sws;
|
||||||
|
}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a local listen socket to listen for new TCP connections
|
* Bind a local listen socket to listen for new TCP connections
|
||||||
*
|
*
|
||||||
|
@ -573,6 +640,45 @@ public:
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __UNIX_LIKE__
|
||||||
|
/**
|
||||||
|
* Attempt to send data to a Unix domain socket connection (non-blocking)
|
||||||
|
*
|
||||||
|
* If -1 is returned, the socket should no longer be used as it is now
|
||||||
|
* destroyed. If callCloseHandler is true, the close handler will be
|
||||||
|
* called before the function returns.
|
||||||
|
*
|
||||||
|
* @param sock An open Unix socket (other socket types will fail)
|
||||||
|
* @param data Data to send
|
||||||
|
* @param len Length of data
|
||||||
|
* @param callCloseHandler If true, call close handler on socket closing failure condition (default: true)
|
||||||
|
* @return Number of bytes actually sent or -1 on fatal error (socket closure)
|
||||||
|
*/
|
||||||
|
inline long unixSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true)
|
||||||
|
{
|
||||||
|
PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
|
||||||
|
long n = (long)::write(sws.sock,data,len);
|
||||||
|
if (n < 0) {
|
||||||
|
switch(errno) {
|
||||||
|
#ifdef EAGAIN
|
||||||
|
case EAGAIN:
|
||||||
|
#endif
|
||||||
|
#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) )
|
||||||
|
case EWOULDBLOCK:
|
||||||
|
#endif
|
||||||
|
#ifdef EINTR
|
||||||
|
case EINTR:
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
this->close(sock,callCloseHandler);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether we want to be notified via the TCP writability handler when a socket is writable
|
* Set whether we want to be notified via the TCP writability handler when a socket is writable
|
||||||
*
|
*
|
||||||
|
@ -727,6 +833,56 @@ public:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ZT_PHY_SOCKET_UNIX_IN: {
|
||||||
|
#ifdef __UNIX_LIKE__
|
||||||
|
ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable
|
||||||
|
if (FD_ISSET(sock,&rfds)) {
|
||||||
|
long n = (long)::read(sock,buf,sizeof(buf));
|
||||||
|
if (n <= 0) {
|
||||||
|
this->close((PhySocket *)&(*s),true);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
_handler->phyOnUnixData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n);
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) {
|
||||||
|
try {
|
||||||
|
_handler->phyOnUnixWritable((PhySocket *)&(*s),&(s->uptr));
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ZT_PHY_SOCKET_UNIX_LISTEN:
|
||||||
|
#ifdef __UNIX_LIKE__
|
||||||
|
if (FD_ISSET(s->sock,&rfds)) {
|
||||||
|
memset(&ss,0,sizeof(ss));
|
||||||
|
socklen_t slen = sizeof(ss);
|
||||||
|
ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen);
|
||||||
|
if (ZT_PHY_SOCKFD_VALID(newSock)) {
|
||||||
|
if (_socks.size() >= ZT_PHY_MAX_SOCKETS) {
|
||||||
|
ZT_PHY_CLOSE_SOCKET(newSock);
|
||||||
|
} else {
|
||||||
|
fcntl(newSock,F_SETFL,O_NONBLOCK);
|
||||||
|
_socks.push_back(PhySocketImpl());
|
||||||
|
PhySocketImpl &sws = _socks.back();
|
||||||
|
FD_SET(newSock,&_readfds);
|
||||||
|
if ((long)newSock > _nfds)
|
||||||
|
_nfds = (long)newSock;
|
||||||
|
sws.type = ZT_PHY_SOCKET_UNIX_IN;
|
||||||
|
sws.sock = newSock;
|
||||||
|
sws.uptr = (void *)0;
|
||||||
|
memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage));
|
||||||
|
try {
|
||||||
|
_handler->phyOnUnixAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr));
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -758,24 +914,29 @@ public:
|
||||||
|
|
||||||
ZT_PHY_CLOSE_SOCKET(sws.sock);
|
ZT_PHY_CLOSE_SOCKET(sws.sock);
|
||||||
|
|
||||||
switch(sws.type) {
|
if (callHandlers) {
|
||||||
case ZT_PHY_SOCKET_TCP_OUT_PENDING:
|
switch(sws.type) {
|
||||||
if (callHandlers) {
|
case ZT_PHY_SOCKET_TCP_OUT_PENDING:
|
||||||
try {
|
try {
|
||||||
_handler->phyOnTcpConnect(sock,&(sws.uptr),false);
|
_handler->phyOnTcpConnect(sock,&(sws.uptr),false);
|
||||||
} catch ( ... ) {}
|
} catch ( ... ) {}
|
||||||
}
|
break;
|
||||||
break;
|
case ZT_PHY_SOCKET_TCP_OUT_CONNECTED:
|
||||||
case ZT_PHY_SOCKET_TCP_OUT_CONNECTED:
|
case ZT_PHY_SOCKET_TCP_IN:
|
||||||
case ZT_PHY_SOCKET_TCP_IN:
|
|
||||||
if (callHandlers) {
|
|
||||||
try {
|
try {
|
||||||
_handler->phyOnTcpClose(sock,&(sws.uptr));
|
_handler->phyOnTcpClose(sock,&(sws.uptr));
|
||||||
} catch ( ... ) {}
|
} catch ( ... ) {}
|
||||||
}
|
break;
|
||||||
break;
|
case ZT_PHY_SOCKET_UNIX_IN:
|
||||||
default:
|
#ifdef __UNIX_LIKE__
|
||||||
break;
|
try {
|
||||||
|
_handler->phyOnUnixClose(sock,&(sws.uptr));
|
||||||
|
} catch ( ... ) {}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Causes entry to be deleted from list in poll(), ignored elsewhere
|
// Causes entry to be deleted from list in poll(), ignored elsewhere
|
||||||
|
|
|
@ -791,6 +791,13 @@ struct TestPhyHandlers
|
||||||
testPhyInstance->close(sock,true);
|
testPhyInstance->close(sock,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __UNIX_LIKE__
|
||||||
|
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {}
|
||||||
|
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {}
|
||||||
|
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
|
||||||
|
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}
|
||||||
|
#endif // __UNIX_LIKE__
|
||||||
};
|
};
|
||||||
static int testPhy()
|
static int testPhy()
|
||||||
{
|
{
|
||||||
|
|
|
@ -924,6 +924,11 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {}
|
||||||
|
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {}
|
||||||
|
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
|
||||||
|
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}
|
||||||
|
|
||||||
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwc)
|
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwc)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_taps_m);
|
Mutex::Lock _l(_taps_m);
|
||||||
|
|
Loading…
Add table
Reference in a new issue