@ -30,15 +30,17 @@
# include "EthernetTap.hpp"
# include "Logger.hpp"
# include "RuntimeEnvironment.hpp"
# include "Utils.hpp"
# include "Mutex.hpp"
# include "MulticastGroup.hpp"
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier : : MulticastGroup _blindWildcardMulticastGroup ( ZeroTier : : MAC ( 0xff ) , 0 ) ;
/* ======================================================================== */
# if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
/* ======================================================================== */
//
// TAP implementation for *nix OSes, with some specialization for different flavors
//
# ifdef __UNIX_LIKE__ /////////////////////////////////////////////////////////
# include <stdint.h>
# include <stdio.h>
@ -52,10 +54,13 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
# include <sys/stat.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
# include <sys/select.h>
# include <netinet/in.h>
# include <net/if_arp.h>
# include <arpa/inet.h>
# ifdef __LINUX__
# include <linux/if.h>
# include <linux/if_tun.h>
# include <linux/if_addr.h>
@ -64,23 +69,49 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
# define ZT_ETHERTAP_IP_COMMAND " / sbin / ip"
# define ZT_ETHERTAP_SYSCTL_COMMAND " / sbin / sysctl"
# endif // __LINUX__
# ifdef __APPLE__
# include <sys/uio.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# include <net/route.h>
# include <net/if_dl.h>
# include <ifaddrs.h>
# define ZT_ETHERTAP_IFCONFIG " / sbin / ifconfig"
# define ZT_MAC_KEXTLOAD " / sbin / kextload"
# define ZT_MAC_IPCONFIG " / usr / sbin / ipconfig"
# endif // __APPLE__
namespace ZeroTier {
// Only permit one tap to be opened concurrently across the entire process
static Mutex __tapCreateLock ;
EthernetTap : : EthernetTap ( const RuntimeEnvironment * renv , const MAC & mac , unsigned int mtu )
# ifdef __LINUX__
EthernetTap : : EthernetTap (
const RuntimeEnvironment * renv ,
const MAC & mac ,
unsigned int mtu ,
void ( * handler ) ( void * , const MAC & , const MAC & , unsigned int , const Buffer < 4096 > & ) ,
void * arg )
throw ( std : : runtime_error ) :
_mac ( mac ) ,
_mtu ( mtu ) ,
_r ( renv ) ,
_putBuf ( ( unsigned char * ) 0 ) ,
_getBuf ( ( unsigned char * ) 0 ) ,
_fd ( 0 ) ,
_isReading ( false )
_handler ( handler ) ,
_arg ( arg ) ,
_fd ( 0 )
{
char procpath [ 128 ] ;
Mutex : : Lock _l ( __tapCreateLock ) ; // create only one tap at a time, globally
if ( mtu > 4096 )
throw std : : runtime_error ( " max tap MTU is 4096 " ) ;
_fd = : : open ( " /dev/net/tun " , O_RDWR ) ;
if ( _fd < = 0 )
throw std : : runtime_error ( " could not open TUN/TAP device " ) ;
@ -152,266 +183,36 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
: : close ( sock ) ;
_putBuf = new unsigned char [ ( ( mtu + 16 ) * 2 ) ] ;
_getBuf = _putBuf + ( mtu + 16 ) ;
: : pipe ( _shutdownSignalPipe ) ;
TRACE ( " tap %s created " , _dev ) ;
}
EthernetTap : : ~ EthernetTap ( )
{
this - > close ( ) ;
delete [ ] _putBuf ;
}
void EthernetTap : : whack ( )
{
// Linux requires nothing here
}
static bool ___removeIp ( const char * _dev , std : : set < InetAddress > & _ips , const InetAddress & ip )
{
long cpid ;
if ( ( cpid = ( long ) fork ( ) ) = = 0 ) {
execl ( ZT_ETHERTAP_IP_COMMAND , ZT_ETHERTAP_IP_COMMAND , " addr " , " del " , ip . toString ( ) . c_str ( ) , " dev " , _dev , ( const char * ) 0 ) ;
exit ( 1 ) ; /* not reached unless exec fails */
} else {
int exitcode = 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
if ( exitcode = = 0 ) {
_ips . erase ( ip ) ;
return true ;
} else return false ;
}
}
bool EthernetTap : : addIP ( const InetAddress & ip )
{
Mutex : : Lock _l ( _ips_m ) ;
if ( ! ip )
return false ;
if ( _ips . count ( ip ) > 0 )
return true ;
// Remove and reconfigure if address is the same but netmask is different
for ( std : : set < InetAddress > : : iterator i ( _ips . begin ( ) ) ; i ! = _ips . end ( ) ; + + i ) {
if ( i - > ipsEqual ( ip ) ) {
___removeIp ( _dev , _ips , * i ) ;
break ;
}
}
int cpid ;
if ( ( cpid = ( int ) fork ( ) ) = = 0 ) {
execl ( ZT_ETHERTAP_IP_COMMAND , ZT_ETHERTAP_IP_COMMAND , " addr " , " add " , ip . toString ( ) . c_str ( ) , " dev " , _dev , ( const char * ) 0 ) ;
exit ( - 1 ) ;
} else {
int exitcode = - 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
if ( exitcode = = 0 ) {
_ips . insert ( ip ) ;
return true ;
} else return false ;
}
return false ;
}
bool EthernetTap : : removeIP ( const InetAddress & ip )
{
Mutex : : Lock _l ( _ips_m ) ;
if ( _ips . count ( ip ) > 0 )
return ___removeIp ( _dev , _ips , ip ) ;
return false ;
}
void EthernetTap : : put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len )
{
if ( ( _fd > 0 ) & & ( len < = _mtu ) ) {
for ( int i = 0 ; i < 6 ; + + i )
_putBuf [ i ] = to . data [ i ] ;
for ( int i = 0 ; i < 6 ; + + i )
_putBuf [ i + 6 ] = from . data [ i ] ;
* ( ( uint16_t * ) ( _putBuf + 12 ) ) = htons ( ( uint16_t ) etherType ) ;
memcpy ( _putBuf + 14 , data , len ) ;
: : write ( _fd , _putBuf , len + 14 ) ;
}
}
unsigned int EthernetTap : : get ( MAC & from , MAC & to , unsigned int & etherType , void * buf )
{
for ( ; ; ) {
if ( _fd > 0 ) {
_isReading_m . lock ( ) ;
_isReading = true ;
_isReadingThreadId = pthread_self ( ) ;
_isReading_m . unlock ( ) ;
int n = ( int ) : : read ( _fd , _getBuf , _mtu + 14 ) ;
_isReading_m . lock ( ) ;
_isReading = false ;
_isReading_m . unlock ( ) ;
if ( n > 14 ) {
for ( int i = 0 ; i < 6 ; + + i )
to . data [ i ] = _getBuf [ i ] ;
for ( int i = 0 ; i < 6 ; + + i )
from . data [ i ] = _getBuf [ i + 6 ] ;
etherType = ntohs ( ( ( uint16_t * ) _getBuf ) [ 6 ] ) ;
n - = 14 ;
memcpy ( buf , _getBuf + 14 , n ) ;
return ( unsigned int ) n ;
} else if ( n < 0 ) {
if ( _fd < = 0 )
break ;
else if ( ( errno = = EINTR ) | | ( errno = = ETIMEDOUT ) )
continue ;
else {
TRACE ( " unexpected error reading from tap: %s " , strerror ( errno ) ) ;
: : close ( _fd ) ;
_fd = 0 ;
break ;
}
} else {
TRACE ( " incomplete read from tap: %d bytes " , n ) ;
continue ;
}
}
}
return 0 ;
}
std : : string EthernetTap : : deviceName ( )
{
return std : : string ( _dev ) ;
}
bool EthernetTap : : open ( ) const
{
return ( _fd > 0 ) ;
start ( ) ;
}
void EthernetTap : : close ( )
{
Mutex : : Lock _l ( __tapCreateLock ) ; // also prevent create during close()
if ( _fd > 0 ) {
int f = _fd ;
_fd = 0 ;
: : close ( f ) ;
_isReading_m . lock ( ) ;
if ( _isReading )
pthread_kill ( _isReadingThreadId , SIGUSR2 ) ;
_isReading_m . unlock ( ) ;
}
}
bool EthernetTap : : updateMulticastGroups ( std : : set < MulticastGroup > & groups )
{
char * ptr , * ptr2 ;
unsigned char mac [ 6 ] ;
std : : set < MulticastGroup > newGroups ;
int fd = : : open ( " /proc/net/dev_mcast " , O_RDONLY ) ;
if ( fd > 0 ) {
char buf [ 131072 ] ;
int n = ( int ) : : read ( fd , buf , sizeof ( buf ) ) ;
if ( ( n > 0 ) & & ( n < ( int ) sizeof ( buf ) ) ) {
buf [ n ] = ( char ) 0 ;
for ( char * l = strtok_r ( buf , " \r \n " , & ptr ) ; ( l ) ; l = strtok_r ( ( char * ) 0 , " \r \n " , & ptr ) ) {
int fno = 0 ;
char * devname = ( char * ) 0 ;
char * mcastmac = ( char * ) 0 ;
for ( char * f = strtok_r ( l , " \t " , & ptr2 ) ; ( f ) ; f = strtok_r ( ( char * ) 0 , " \t " , & ptr2 ) ) {
if ( fno = = 1 )
devname = f ;
else if ( fno = = 4 )
mcastmac = f ;
+ + fno ;
}
if ( ( devname ) & & ( ! strcmp ( devname , _dev ) ) & & ( mcastmac ) & & ( Utils : : unhex ( mcastmac , mac , 6 ) = = 6 ) )
newGroups . insert ( MulticastGroup ( MAC ( mac ) , 0 ) ) ;
}
}
: : close ( fd ) ;
}
{
Mutex : : Lock _l ( _ips_m ) ;
for ( std : : set < InetAddress > : : const_iterator i ( _ips . begin ( ) ) ; i ! = _ips . end ( ) ; + + i )
newGroups . insert ( MulticastGroup : : deriveMulticastGroupForAddressResolution ( * i ) ) ;
}
bool changed = false ;
newGroups . insert ( _blindWildcardMulticastGroup ) ; // always join this
for ( std : : set < MulticastGroup > : : iterator mg ( newGroups . begin ( ) ) ; mg ! = newGroups . end ( ) ; + + mg ) {
if ( ! groups . count ( * mg ) ) {
groups . insert ( * mg ) ;
changed = true ;
}
}
for ( std : : set < MulticastGroup > : : iterator mg ( groups . begin ( ) ) ; mg ! = groups . end ( ) ; ) {
if ( ! newGroups . count ( * mg ) ) {
groups . erase ( mg + + ) ;
changed = true ;
} else + + mg ;
}
return changed ;
}
} // namespace ZeroTier
/* ======================================================================== */
# elif defined(__APPLE__) /* ----------------------------------------------- */
/* ======================================================================== */
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <signal.h>
# include <fcntl.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/ioctl.h>
# include <sys/uio.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <net/route.h>
# include <net/if_dl.h>
# include <ifaddrs.h>
# define ZT_ETHERTAP_IFCONFIG " / sbin / ifconfig"
# define ZT_MAC_KEXTLOAD " / sbin / kextload"
# define ZT_MAC_IPCONFIG " / usr / sbin / ipconfig"
namespace ZeroTier {
static Mutex __tapCreateLock ;
EthernetTap : : EthernetTap ( const RuntimeEnvironment * renv , const MAC & mac , unsigned int mtu )
# endif // __LINUX__
# ifdef __APPLE__
EthernetTap : : EthernetTap (
const RuntimeEnvironment * renv ,
const MAC & mac ,
unsigned int mtu ,
void ( * handler ) ( void * , const MAC & , const MAC & , unsigned int , const Buffer < 4096 > & ) ,
void * arg )
throw ( std : : runtime_error ) :
_mac ( mac ) ,
_mtu ( mtu ) ,
_r ( renv ) ,
_putBuf ( ( unsigned char * ) 0 ) ,
_getBuf ( ( unsigned char * ) 0 ) ,
_fd ( 0 ) ,
_isReading ( false )
_handler ( handler ) ,
_arg ( arg ) ,
_fd ( 0 )
{
char devpath [ 64 ] , ethaddr [ 64 ] , mtustr [ 16 ] ;
struct stat tmp ;
Mutex : : Lock _l ( __tapCreateLock ) ; // create only one tap at a time, globally
if ( mtu > 4096 )
throw std : : runtime_error ( " max tap MTU is 4096 " ) ;
// Check for existence of ZT tap devices, try to load module if not there
if ( stat ( " /dev/zt0 " , & tmp ) ) {
int kextpid ;
@ -453,8 +254,8 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
sprintf ( mtustr , " %u " , mtu ) ;
// Configure MAC address and MTU, bring interface up
int cpid ;
if ( ( cpid = ( int ) fork ( ) ) = = 0 ) {
long cpid ;
if ( ( cpid = ( long ) fork ( ) ) = = 0 ) {
execl ( ZT_ETHERTAP_IFCONFIG , ZT_ETHERTAP_IFCONFIG , _dev , " lladdr " , ethaddr , " mtu " , mtustr , " up " , ( const char * ) 0 ) ;
exit ( - 1 ) ;
} else {
@ -468,19 +269,23 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
whack ( ) ; // turns on IPv6 on OSX
_putBuf = new unsigned char [ ( ( mtu + 14 ) * 2 ) ] ;
_getBuf = _putBuf + ( mtu + 14 ) ;
: : pipe ( _shutdownSignalPipe ) ;
start ( ) ;
}
# endif // __APPLE__
EthernetTap : : ~ EthernetTap ( )
{
this - > close ( ) ;
delete [ ] _putBuf ;
: : write ( _shutdownSignalPipe [ 1 ] , " \0 " , 1 ) ; // causes thread to exit
join ( ) ;
: : close ( _fd ) ;
}
# ifdef __APPLE__
void EthernetTap : : whack ( )
{
int cpid = fork ( ) ;
long cpid = ( long ) fork ( ) ;
if ( cpid = = 0 ) {
execl ( ZT_MAC_IPCONFIG , ZT_MAC_IPCONFIG , " set " , _dev , " AUTOMATIC-V6 " , ( const char * ) 0 ) ;
exit ( - 1 ) ;
@ -492,8 +297,63 @@ void EthernetTap::whack()
}
}
}
# else
void EthernetTap : : whack ( ) { }
# endif // __APPLE__ / !__APPLE__
// Helper function to actually remove IP from network device, execs ifconfig
# ifdef __LINUX__
static bool ___removeIp ( const char * _dev , const InetAddress & ip )
{
long cpid = ( long ) fork ( ) ;
if ( cpid = = 0 ) {
execl ( ZT_ETHERTAP_IP_COMMAND , ZT_ETHERTAP_IP_COMMAND , " addr " , " del " , ip . toString ( ) . c_str ( ) , " dev " , _dev , ( const char * ) 0 ) ;
exit ( 1 ) ; /* not reached unless exec fails */
} else {
int exitcode = 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
return ( exitcode = = 0 ) ;
}
}
bool EthernetTap : : addIP ( const InetAddress & ip )
{
Mutex : : Lock _l ( _ips_m ) ;
if ( ! ip )
return false ;
if ( _ips . count ( ip ) > 0 )
return true ;
// Remove and reconfigure if address is the same but netmask is different
for ( std : : set < InetAddress > : : iterator i ( _ips . begin ( ) ) ; i ! = _ips . end ( ) ; + + i ) {
if ( i - > ipsEqual ( ip ) ) {
if ( ___removeIp ( _dev , * i ) ) {
_ips . erase ( i ) ;
break ;
} else {
LOG ( " WARNING: failed to remove old IP/netmask %s to replace with %s " , i - > toString ( ) . c_str ( ) , ip . toString ( ) . c_str ( ) ) ;
}
}
}
long cpid ;
if ( ( cpid = ( long ) fork ( ) ) = = 0 ) {
execl ( ZT_ETHERTAP_IP_COMMAND , ZT_ETHERTAP_IP_COMMAND , " addr " , " add " , ip . toString ( ) . c_str ( ) , " dev " , _dev , ( const char * ) 0 ) ;
exit ( - 1 ) ;
} else {
int exitcode = - 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
if ( exitcode = = 0 ) {
_ips . insert ( ip ) ;
return true ;
} else return false ;
}
return false ;
}
# endif // __LINUX__
# ifdef __APPLE__
static bool ___removeIp ( const char * _dev , const InetAddress & ip )
{
int cpid ;
@ -544,6 +404,7 @@ bool EthernetTap::addIP(const InetAddress &ip)
return false ;
}
# endif // __APPLE__
bool EthernetTap : : removeIP ( const InetAddress & ip )
{
@ -559,94 +420,90 @@ bool EthernetTap::removeIP(const InetAddress &ip)
void EthernetTap : : put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len )
{
char putBuf [ 4096 + 14 ] ;
if ( ( _fd > 0 ) & & ( len < = _mtu ) ) {
for ( int i = 0 ; i < 6 ; + + i )
_ putBuf[ i ] = to . data [ i ] ;
putBuf [ i ] = to . data [ i ] ;
for ( int i = 0 ; i < 6 ; + + i )
_ putBuf[ i + 6 ] = from . data [ i ] ;
* ( ( uint16_t * ) ( _ putBuf + 12 ) ) = htons ( ( uint16_t ) etherType ) ;
memcpy ( _ putBuf + 14 , data , len ) ;
putBuf [ i + 6 ] = from . data [ i ] ;
* ( ( uint16_t * ) ( putBuf + 12 ) ) = htons ( ( uint16_t ) etherType ) ;
memcpy ( putBuf + 14 , data , len ) ;
len + = 14 ;
int n = ( int ) : : write ( _fd , _ putBuf, len ) ;
int n = : : write ( _fd , putBuf , len ) ;
if ( n < = 0 ) {
LOG ( " error writing packet to Ethernet tap device: %s " , strerror ( errno ) ) ;
} else if ( n ! = ( int ) len ) {
// Saw this gremlin once, so log it if we see it again... OSX tap
// or something seems to have goofy issues with certain MTUs.
LOG ( " WARNING: Apple gremlin: tap write() wrote %d of %u bytes of frame" , n , len ) ;
LOG ( " ERROR: write underrun: %s tap write() wrote %d of %u bytes of frame" , _dev , n , len ) ;
}
}
}
unsigned int EthernetTap : : get ( MAC & from , MAC & to , unsigned int & etherType , void * buf )
std : : string EthernetTap : : deviceName ( ) const
{
for ( ; ; ) {
if ( _fd > 0 ) {
_isReading_m . lock ( ) ;
_isReading = true ;
_isReadingThreadId = pthread_self ( ) ;
_isReading_m . unlock ( ) ;
int n = ( int ) : : read ( _fd , _getBuf , _mtu + 14 ) ;
return std : : string ( _dev ) ;
}
_isReading_m . lock ( ) ;
_isReading = false ;
_isReading_m . unlock ( ) ;
# ifdef __LINUX__
bool EthernetTap : : updateMulticastGroups ( std : : set < MulticastGroup > & groups )
{
char * ptr , * ptr2 ;
unsigned char mac [ 6 ] ;
std : : set < MulticastGroup > newGroups ;
if ( n > 14 ) {
for ( int i = 0 ; i < 6 ; + + i )
to . data [ i ] = _getBuf [ i ] ;
for ( int i = 0 ; i < 6 ; + + i )
from . data [ i ] = _getBuf [ i + 6 ] ;
etherType = ntohs ( ( ( uint16_t * ) _getBuf ) [ 6 ] ) ;
n - = 14 ;
memcpy ( buf , _getBuf + 14 , n ) ;
return ( unsigned int ) n ;
} else if ( n < 0 ) {
if ( _fd < = 0 )
break ;
else if ( ( errno = = EINTR ) | | ( errno = = ETIMEDOUT ) )
continue ;
else {
TRACE ( " unexpected error reading from tap: %s " , strerror ( errno ) ) ;
: : close ( _fd ) ;
_fd = 0 ;
break ;
int fd = : : open ( " /proc/net/dev_mcast " , O_RDONLY ) ;
if ( fd > 0 ) {
char buf [ 131072 ] ;
int n = ( int ) : : read ( fd , buf , sizeof ( buf ) ) ;
if ( ( n > 0 ) & & ( n < ( int ) sizeof ( buf ) ) ) {
buf [ n ] = ( char ) 0 ;
for ( char * l = strtok_r ( buf , " \r \n " , & ptr ) ; ( l ) ; l = strtok_r ( ( char * ) 0 , " \r \n " , & ptr ) ) {
int fno = 0 ;
char * devname = ( char * ) 0 ;
char * mcastmac = ( char * ) 0 ;
for ( char * f = strtok_r ( l , " \t " , & ptr2 ) ; ( f ) ; f = strtok_r ( ( char * ) 0 , " \t " , & ptr2 ) ) {
if ( fno = = 1 )
devname = f ;
else if ( fno = = 4 )
mcastmac = f ;
+ + fno ;
}
} else {
TRACE ( " incomplete read from tap: %d bytes " , n ) ;
continue ;
if ( ( devname ) & & ( ! strcmp ( devname , _dev ) ) & & ( mcastmac ) & & ( Utils : : unhex ( mcastmac , mac , 6 ) = = 6 ) )
newGroups . insert ( MulticastGroup ( MAC ( mac ) , 0 ) ) ;
}
}
: : close ( fd ) ;
}
return 0 ;
}
std : : string EthernetTap : : deviceName ( )
{
return std : : string ( _dev ) ;
}
{
Mutex : : Lock _l ( _ips_m ) ;
for ( std : : set < InetAddress > : : const_iterator i ( _ips . begin ( ) ) ; i ! = _ips . end ( ) ; + + i )
newGroups . insert ( MulticastGroup : : deriveMulticastGroupForAddressResolution ( * i ) ) ;
}
bool EthernetTap : : open ( ) const
{
return ( _fd > 0 ) ;
}
bool changed = false ;
void EthernetTap : : close ( )
{
Mutex : : Lock _l ( __tapCreateLock ) ; // also prevent create during close()
if ( _fd > 0 ) {
int f = _fd ;
_fd = 0 ;
: : close ( f ) ;
_isReading_m . lock ( ) ;
if ( _isReading )
pthread_kill ( _isReadingThreadId , SIGUSR2 ) ;
_isReading_m . unlock ( ) ;
newGroups . insert ( _blindWildcardMulticastGroup ) ; // always join this
for ( std : : set < MulticastGroup > : : iterator mg ( newGroups . begin ( ) ) ; mg ! = newGroups . end ( ) ; + + mg ) {
if ( ! groups . count ( * mg ) ) {
groups . insert ( * mg ) ;
changed = true ;
}
}
for ( std : : set < MulticastGroup > : : iterator mg ( groups . begin ( ) ) ; mg ! = groups . end ( ) ; ) {
if ( ! newGroups . count ( * mg ) ) {
groups . erase ( mg + + ) ;
changed = true ;
} else + + mg ;
}
return changed ;
}
# endif __LINUX__
# ifdef __APPLE__
bool EthernetTap : : updateMulticastGroups ( std : : set < MulticastGroup > & groups )
{
std : : set < MulticastGroup > newGroups ;
@ -690,13 +547,54 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
return changed ;
}
# endif // __APPLE__
void EthernetTap : : main ( )
throw ( )
{
fd_set readfds , nullfds ;
MAC to , from ;
char getBuf [ 4096 + 14 ] ;
Buffer < 4096 > data ;
FD_ZERO ( & readfds ) ;
FD_ZERO ( & nullfds ) ;
int nfds = ( int ) std : : max ( _shutdownSignalPipe [ 0 ] , _fd ) + 1 ;
for ( ; ; ) {
FD_SET ( _shutdownSignalPipe [ 0 ] , & readfds ) ;
FD_SET ( _fd , & readfds ) ;
select ( nfds , & readfds , & nullfds , & nullfds , ( struct timeval * ) 0 ) ;
if ( FD_ISSET ( _shutdownSignalPipe [ 0 ] , & readfds ) ) // writes to shutdown pipe terminate thread
break ;
if ( FD_ISSET ( _fd , & readfds ) ) {
int n = ( int ) : : read ( _fd , getBuf , _mtu + 14 ) ;
if ( n > 14 ) {
for ( int i = 0 ; i < 6 ; + + i )
to . data [ i ] = ( unsigned char ) getBuf [ i ] ;
for ( int i = 0 ; i < 6 ; + + i )
from . data [ i ] = ( unsigned char ) getBuf [ i + 6 ] ;
data . copyFrom ( getBuf + 14 , ( unsigned int ) n - 14 ) ;
_handler ( _arg , from , to , ntohs ( ( ( const uint16_t * ) getBuf ) [ 6 ] ) , data ) ;
} else if ( n < 0 ) {
if ( ( errno ! = EINTR ) & & ( errno ! = ETIMEDOUT ) ) {
TRACE ( " unexpected error reading from tap: %s " , strerror ( errno ) ) ;
break ;
}
}
}
}
}
} // namespace ZeroTier
/* ======================================================================== */
# elif defined(_WIN32) /* -------------------------------------------------- */
/* ======================================================================== */
# endif // __UNIX_LIKE__ //////////////////////////////////////////////////////
# ifdef __WINDOWS__
// TODO
/* ======================================================================== */
# endif
/* ======================================================================== */
# endif // __WINDOWS__