mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 04:57:53 +00:00
Add socketpair support to Phy.
This commit is contained in:
parent
4fbcad2468
commit
9a723be263
115
osdep/Phy.hpp
115
osdep/Phy.hpp
@ -46,6 +46,7 @@
|
||||
#define ZT_PHY_SOCKFD_VALID(s) ((s) != INVALID_SOCKET)
|
||||
#define ZT_PHY_CLOSE_SOCKET(s) ::closesocket(s)
|
||||
#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE)
|
||||
#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS
|
||||
#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage
|
||||
|
||||
#else // not Windows
|
||||
@ -58,6 +59,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
@ -67,8 +69,14 @@
|
||||
#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1)
|
||||
#define ZT_PHY_CLOSE_SOCKET(s) ::close(s)
|
||||
#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE)
|
||||
#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS
|
||||
#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage
|
||||
|
||||
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
|
||||
#define ZT_PHY_HAVE_EVENTFD 1
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
#endif // Windows or not
|
||||
|
||||
namespace ZeroTier {
|
||||
@ -87,16 +95,24 @@ typedef void PhySocket;
|
||||
* This class is templated on a pointer to a handler class which must
|
||||
* implement the following functions:
|
||||
*
|
||||
* For all platforms:
|
||||
*
|
||||
* phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
|
||||
* phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
|
||||
* phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
|
||||
* phyOnTcpClose(PhySocket *sock,void **uptr)
|
||||
* phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||
* phyOnTcpWritable(PhySocket *sock,void **uptr)
|
||||
*
|
||||
* On Linux/OSX/Unix only (not required/used on Windows or elsewhere):
|
||||
*
|
||||
* 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)
|
||||
* phyOnSocketPairEndpointClose(PhySocket *sock,void **uptr)
|
||||
* phyOnSocketPairEndpointData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||
* phyOnSocketPairEndpointWritable(PhySocket *sock,void **uptr)
|
||||
*
|
||||
* These templates typically refer to function objects. Templates are used to
|
||||
* avoid the call overhead of indirection, which is surprisingly high for high
|
||||
@ -109,9 +125,6 @@ typedef void PhySocket;
|
||||
* uptr: sockL and uptrL for the listen socket, and sockN and uptrN for
|
||||
* 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
|
||||
* called on either success or failure followed by DATA and/or WRITABLE as
|
||||
* indicated. On socket close, handlers are called unless close() is told
|
||||
@ -138,7 +151,8 @@ private:
|
||||
ZT_PHY_SOCKET_RAW = 0x05,
|
||||
ZT_PHY_SOCKET_UDP = 0x06,
|
||||
ZT_PHY_SOCKET_UNIX_IN = 0x07,
|
||||
ZT_PHY_SOCKET_UNIX_LISTEN = 0x08
|
||||
ZT_PHY_SOCKET_UNIX_LISTEN = 0x08,
|
||||
ZT_PHY_SOCKET_PAIR_ENDPOINT = 0x09
|
||||
};
|
||||
|
||||
struct PhySocketImpl
|
||||
@ -226,8 +240,17 @@ public:
|
||||
ZT_PHY_CLOSE_SOCKET(_whackSendSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Socket object
|
||||
* @return Underlying OS-type (usually int or long) file descriptor associated with object
|
||||
*/
|
||||
static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast<PhySocketImpl *>(s)->sock; }
|
||||
|
||||
/**
|
||||
* Cause poll() to stop waiting immediately
|
||||
*
|
||||
* This can be used to reset the polling loop after changes that require
|
||||
* attention, or to shut down a background thread that is waiting, etc.
|
||||
*/
|
||||
inline void whack()
|
||||
{
|
||||
@ -248,6 +271,58 @@ public:
|
||||
*/
|
||||
inline unsigned long maxCount() const throw() { return ZT_PHY_MAX_SOCKETS; }
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
/**
|
||||
* Create a two-way socket pair
|
||||
*
|
||||
* This uses socketpair() to create a local domain pair. The returned
|
||||
* PhySocket holds the local side of the socket pair, while the
|
||||
* supplied fd variable is set to the descriptor for the remote side.
|
||||
*
|
||||
* The local side is set to O_NONBLOCK to work with our poll loop, but
|
||||
* the remote descriptor is left untouched. It's up to the caller to
|
||||
* set any required fcntl(), ioctl(), or setsockopt() settings there.
|
||||
* It's also up to the caller to close the remote descriptor when
|
||||
* done, if necessary.
|
||||
*
|
||||
* @param remoteSocketDescriptor Result parameter set to remote end of socket pair's socket FD
|
||||
* @param uptr Pointer to associate with local side of socket pair
|
||||
* @return PhySocket for local side of socket pair
|
||||
*/
|
||||
inline PhySocket *createSocketPair(ZT_PHY_SOCKFD_TYPE &remoteSocketDescriptor,void *uptr = (void *)0)
|
||||
{
|
||||
if (_socks.size() >= ZT_PHY_MAX_SOCKETS)
|
||||
return (PhySocket *)0;
|
||||
|
||||
int fd[2]; fd[0] = -1; fd[1] = -1;
|
||||
if ((::socketpair(PF_LOCAL,SOCK_STREAM,0,fd) != 0)||(fd[0] <= 0)||(fd[1] <= 0))
|
||||
return (PhySocket *)0;
|
||||
fcntl(fd[0],F_SETFL,O_NONBLOCK);
|
||||
|
||||
try {
|
||||
_socks.push_back(PhySocketImpl());
|
||||
} catch ( ... ) {
|
||||
ZT_PHY_CLOSE_SOCKET(fd[0]);
|
||||
ZT_PHY_CLOSE_SOCKET(fd[1]);
|
||||
return (PhySocket *)0;
|
||||
}
|
||||
PhySocketImpl &sws = _socks.back();
|
||||
|
||||
if ((long)fd[0] > _nfds)
|
||||
_nfds = (long)fd[0];
|
||||
FD_SET(fd[0],&_readfds);
|
||||
sws.type = ZT_PHY_SOCKET_PAIR_ENDPOINT;
|
||||
sws.sock = fd[0];
|
||||
sws.uptr = uptr;
|
||||
memset(&(sws.saddr),0,sizeof(struct sockaddr_storage));
|
||||
// no sockaddr for this socket type, leave saddr null
|
||||
|
||||
remoteSocketDescriptor = fd[1];
|
||||
|
||||
return (PhySocket *)&sws;
|
||||
}
|
||||
#endif // __UNIX_LIKE__
|
||||
|
||||
/**
|
||||
* Bind a UDP socket
|
||||
*
|
||||
@ -883,6 +958,27 @@ public:
|
||||
#endif // __UNIX_LIKE__
|
||||
break;
|
||||
|
||||
case ZT_PHY_SOCKET_PAIR_ENDPOINT: {
|
||||
#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->phyOnSocketPairEndpointData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
}
|
||||
if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) {
|
||||
try {
|
||||
_handler->phyOnSocketPairEndpointWritable((PhySocket *)&(*s),&(s->uptr));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
#endif // __UNIX_LIKE__
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -914,6 +1010,11 @@ public:
|
||||
|
||||
ZT_PHY_CLOSE_SOCKET(sws.sock);
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
if (sws.type == ZT_PHY_SOCKET_UNIX_LISTEN)
|
||||
::unlink(((struct sockaddr_un *)(&(sws.saddr)))->sun_path);
|
||||
#endif // __UNIX_LIKE__
|
||||
|
||||
if (callHandlers) {
|
||||
switch(sws.type) {
|
||||
case ZT_PHY_SOCKET_TCP_OUT_PENDING:
|
||||
@ -934,6 +1035,12 @@ public:
|
||||
} catch ( ... ) {}
|
||||
#endif // __UNIX_LIKE__
|
||||
break;
|
||||
case ZT_PHY_SOCKET_PAIR_ENDPOINT:
|
||||
#ifdef __UNIX_LIKE__
|
||||
try {
|
||||
_handler->phyOnSocketPairEndpointClose(sock,&(sws.uptr));
|
||||
} catch ( ... ) {}
|
||||
#endif // __UNIX_LIKE__
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -826,6 +826,9 @@ struct TestPhyHandlers
|
||||
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 void phyOnSocketPairEndpointClose(PhySocket *sock,void **uptr) {}
|
||||
inline void phyOnSocketPairEndpointData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
|
||||
inline void phyOnSocketPairEndpointWritable(PhySocket *sock,void **uptr) {}
|
||||
#endif // __UNIX_LIKE__
|
||||
};
|
||||
static int testPhy()
|
||||
|
@ -928,6 +928,9 @@ public:
|
||||
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 void phyOnSocketPairEndpointClose(PhySocket *sock,void **uptr) {}
|
||||
inline void phyOnSocketPairEndpointData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
|
||||
inline void phyOnSocketPairEndpointWritable(PhySocket *sock,void **uptr) {}
|
||||
|
||||
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwc)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user