|
|
|
|
@ -93,6 +93,10 @@ typedef void PhySocket;
|
|
|
|
|
* phyOnTcpClose(PhySocket *sock,void **uptr) |
|
|
|
|
* phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) |
|
|
|
|
* 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 |
|
|
|
|
* 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 |
|
|
|
|
* 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 |
|
|
|
|
@ -129,7 +136,9 @@ private:
|
|
|
|
|
ZT_PHY_SOCKET_TCP_IN = 0x03, |
|
|
|
|
ZT_PHY_SOCKET_TCP_LISTEN = 0x04, |
|
|
|
|
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 |
|
|
|
|
@ -358,6 +367,64 @@ public:
|
|
|
|
|
#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 |
|
|
|
|
* |
|
|
|
|
@ -573,6 +640,45 @@ public:
|
|
|
|
|
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 |
|
|
|
|
* |
|
|
|
|
@ -727,6 +833,56 @@ public:
|
|
|
|
|
} |
|
|
|
|
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: |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
@ -758,24 +914,29 @@ public:
|
|
|
|
|
|
|
|
|
|
ZT_PHY_CLOSE_SOCKET(sws.sock); |
|
|
|
|
|
|
|
|
|
switch(sws.type) { |
|
|
|
|
case ZT_PHY_SOCKET_TCP_OUT_PENDING: |
|
|
|
|
if (callHandlers) { |
|
|
|
|
if (callHandlers) { |
|
|
|
|
switch(sws.type) { |
|
|
|
|
case ZT_PHY_SOCKET_TCP_OUT_PENDING: |
|
|
|
|
try { |
|
|
|
|
_handler->phyOnTcpConnect(sock,&(sws.uptr),false); |
|
|
|
|
} catch ( ... ) {} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: |
|
|
|
|
case ZT_PHY_SOCKET_TCP_IN: |
|
|
|
|
if (callHandlers) { |
|
|
|
|
break; |
|
|
|
|
case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: |
|
|
|
|
case ZT_PHY_SOCKET_TCP_IN: |
|
|
|
|
try { |
|
|
|
|
_handler->phyOnTcpClose(sock,&(sws.uptr)); |
|
|
|
|
} catch ( ... ) {} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
break; |
|
|
|
|
case ZT_PHY_SOCKET_UNIX_IN: |
|
|
|
|
#ifdef __UNIX_LIKE__ |
|
|
|
|
try { |
|
|
|
|
_handler->phyOnUnixClose(sock,&(sws.uptr)); |
|
|
|
|
} catch ( ... ) {} |
|
|
|
|
#endif // __UNIX_LIKE__
|
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Causes entry to be deleted from list in poll(), ignored elsewhere
|
|
|
|
|
|