Explorar el Código

Several things:

(1) Probable fix for issue #7 and major cleanup of EthernetTap code with consolidation for all unix-like systems and specialization for different flavors only when needed.

(2) Refactor of Buffer<> to make its members private, and Packet to use Buffer's methods exclusively to access them. This improves clarity and means we're no longer lying about Buffer's role in the code's security posture.

(3) Add -fstack-protect to Makefile to bounds check stack variables.
Adam Ierymenko hace 12 años
padre
commit
ef3e319c64
Se han modificado 10 ficheros con 424 adiciones y 510 borrados
  1. 1 1
      Makefile.mac
  2. 1 1
      node/Buffer.hpp
  3. 57 22
      node/Constants.hpp
  4. 230 332
      node/EthernetTap.cpp
  5. 30 40
      node/EthernetTap.hpp
  6. 9 29
      node/Network.cpp
  7. 6 8
      node/Network.hpp
  8. 87 77
      node/Packet.hpp
  9. 1 0
      node/Salsa20.cpp
  10. 2 0
      selftest.cpp

+ 1 - 1
Makefile.mac

@@ -5,7 +5,7 @@ INCLUDES=-Iext/bin/libcrypto/include -Iext/jsoncpp/include
 DEFS=-DZT_ARCH="x86_combined" -DZT_OSNAME="mac" -DZT_TRACE
 DEFS=-DZT_ARCH="x86_combined" -DZT_OSNAME="mac" -DZT_TRACE
 
 
 # Uncomment for a release optimized universal binary build
 # Uncomment for a release optimized universal binary build
-CFLAGS=-arch i386 -arch x86_64 -Wall -O3 -ftree-vectorize -pthread -mmacosx-version-min=10.6 -DNDEBUG $(INCLUDES) $(DEFS)
+CFLAGS=-arch i386 -arch x86_64 -Wall -O3 -ftree-vectorize -fstack-protector -pthread -mmacosx-version-min=10.6 -DNDEBUG $(INCLUDES) $(DEFS)
 STRIP=strip
 STRIP=strip
 
 
 # Uncomment for a debug build
 # Uncomment for a debug build

+ 1 - 1
node/Buffer.hpp

@@ -388,7 +388,7 @@ public:
 		return !(*this < b);
 		return !(*this < b);
 	}
 	}
 
 
-protected:
+private:
 	unsigned int _l;
 	unsigned int _l;
 	char ZT_VAR_MAY_ALIAS _b[C];
 	char ZT_VAR_MAY_ALIAS _b[C];
 };
 };

+ 57 - 22
node/Constants.hpp

@@ -28,10 +28,55 @@
 #ifndef _ZT_CONSTANTS_HPP
 #ifndef _ZT_CONSTANTS_HPP
 #define _ZT_CONSTANTS_HPP
 #define _ZT_CONSTANTS_HPP
 
 
-// Assume these are little-endian, since we don't support old PPC MACs
-// and all newer Mac or Windows systems are either x86_32, x86_64, or
-// ARM in little-endian mode.
-#if defined(__APPLE__) || defined(_WIN32)
+//
+// This include file also auto-detects and canonicalizes some environment
+// information defines:
+//
+// __LINUX__
+// __APPLE__
+// __UNIX_LIKE__ - any "unix like" OS (BSD, posix, etc.)
+// __WINDOWS__
+//
+// Also makes sure __BYTE_ORDER is defined reasonably.
+//
+
+// Canonicalize Linux... is this necessary? Do it anyway to be defensive.
+#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+#ifndef __LINUX__
+#define __LINUX__
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#endif
+#endif
+
+// TODO: Android is what? Linux technically, but does it define it?
+
+// OSX and iOS are unix-like OSes far as we're concerned
+#ifdef __APPLE__
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#endif
+
+// Linux has endian.h
+#ifdef __LINUX__
+#include <endian.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef __WINDOWS__
+#define __WINDOWS__
+#endif
+#undef __UNIX_LIKE__
+#define ZT_PATH_SEPARATOR '\\'
+#define ZT_PATH_SEPARATOR_S "\\"
+#define ZT_EOL_S "\r\n"
+#endif
+
+// Assume these are little-endian. PPC is not supported for OSX, and ARM
+// runs in little-endian mode for these OS families.
+#if defined(__APPLE__) || defined(__WINDOWS__)
 #undef __BYTE_ORDER
 #undef __BYTE_ORDER
 #undef __LITTLE_ENDIAN
 #undef __LITTLE_ENDIAN
 #undef __BIG_ENDIAN
 #undef __BIG_ENDIAN
@@ -40,31 +85,21 @@
 #define __BYTE_ORDER 1234
 #define __BYTE_ORDER 1234
 #endif
 #endif
 
 
-// Linux has endian.h, which should tell us
-#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
-#include <endian.h>
+#ifdef __UNIX_LIKE__
+#define ZT_PATH_SEPARATOR '/'
+#define ZT_PATH_SEPARATOR_S "/"
+#define ZT_EOL_S "\n"
 #endif
 #endif
 
 
+// Error out if required symbols are missing
 #ifndef __BYTE_ORDER
 #ifndef __BYTE_ORDER
-error_no_byte_order_defined
+error_no_byte_order_defined;
 #endif
 #endif
-
 #ifndef ZT_OSNAME
 #ifndef ZT_OSNAME
-error_no_ZT_OSNAME
+error_no_ZT_OSNAME_defined;
 #endif
 #endif
-
 #ifndef ZT_ARCH
 #ifndef ZT_ARCH
-error_no_ZT_ARCH
-#endif
-
-#ifdef _WIN32
-#define ZT_PATH_SEPARATOR '\\'
-#define ZT_PATH_SEPARATOR_S "\\"
-#define ZT_EOL_S "\r\n"
-#else
-#define ZT_PATH_SEPARATOR '/'
-#define ZT_PATH_SEPARATOR_S "/"
-#define ZT_EOL_S "\n"
+error_no_ZT_ARCH_defined;
 #endif
 #endif
 
 
 /**
 /**

+ 230 - 332
node/EthernetTap.cpp

@@ -30,15 +30,17 @@
 #include "EthernetTap.hpp"
 #include "EthernetTap.hpp"
 #include "Logger.hpp"
 #include "Logger.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "RuntimeEnvironment.hpp"
+#include "Utils.hpp"
 #include "Mutex.hpp"
 #include "Mutex.hpp"
-#include "MulticastGroup.hpp"
 
 
 // ff:ff:ff:ff:ff:ff with no ADI
 // ff:ff:ff:ff:ff:ff with no ADI
 static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
 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 <stdint.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -52,10 +54,13 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
+#include <sys/select.h>
 #include <netinet/in.h>
 #include <netinet/in.h>
 #include <net/if_arp.h>
 #include <net/if_arp.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 
 
+#ifdef __LINUX__
+
 #include <linux/if.h>
 #include <linux/if.h>
 #include <linux/if_tun.h>
 #include <linux/if_tun.h>
 #include <linux/if_addr.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_IP_COMMAND "/sbin/ip"
 #define ZT_ETHERTAP_SYSCTL_COMMAND "/sbin/sysctl"
 #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 {
 namespace ZeroTier {
 
 
+// Only permit one tap to be opened concurrently across the entire process
 static Mutex __tapCreateLock;
 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) :
 	throw(std::runtime_error) :
 	_mac(mac),
 	_mac(mac),
 	_mtu(mtu),
 	_mtu(mtu),
 	_r(renv),
 	_r(renv),
-	_putBuf((unsigned char *)0),
-	_getBuf((unsigned char *)0),
-	_fd(0),
-	_isReading(false)
+	_handler(handler),
+	_arg(arg),
+	_fd(0)
 {
 {
 	char procpath[128];
 	char procpath[128];
 	Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
 	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);
 	_fd = ::open("/dev/net/tun",O_RDWR);
 	if (_fd <= 0)
 	if (_fd <= 0)
 		throw std::runtime_error("could not open TUN/TAP device");
 		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);
 	::close(sock);
 
 
-	_putBuf = new unsigned char[((mtu + 16) * 2)];
-	_getBuf = _putBuf + (mtu + 16);
+	::pipe(_shutdownSignalPipe);
 
 
 	TRACE("tap %s created",_dev);
 	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) :
 	throw(std::runtime_error) :
 	_mac(mac),
 	_mac(mac),
 	_mtu(mtu),
 	_mtu(mtu),
 	_r(renv),
 	_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];
 	char devpath[64],ethaddr[64],mtustr[16];
 	struct stat tmp;
 	struct stat tmp;
 	Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
 	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
 	// Check for existence of ZT tap devices, try to load module if not there
 	if (stat("/dev/zt0",&tmp)) {
 	if (stat("/dev/zt0",&tmp)) {
 		int kextpid;
 		int kextpid;
@@ -453,8 +254,8 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
 	sprintf(mtustr,"%u",mtu);
 	sprintf(mtustr,"%u",mtu);
 
 
 	// Configure MAC address and MTU, bring interface up
 	// 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);
 		execl(ZT_ETHERTAP_IFCONFIG,ZT_ETHERTAP_IFCONFIG,_dev,"lladdr",ethaddr,"mtu",mtustr,"up",(const char *)0);
 		exit(-1);
 		exit(-1);
 	} else {
 	} else {
@@ -468,19 +269,23 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
 
 
 	whack(); // turns on IPv6 on OSX
 	whack(); // turns on IPv6 on OSX
 
 
-	_putBuf = new unsigned char[((mtu + 14) * 2)];
-	_getBuf = _putBuf + (mtu + 14);
+	::pipe(_shutdownSignalPipe);
+
+	start();
 }
 }
+#endif // __APPLE__
 
 
 EthernetTap::~EthernetTap()
 EthernetTap::~EthernetTap()
 {
 {
-	this->close();
-	delete [] _putBuf;
+	::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
+	join();
+	::close(_fd);
 }
 }
 
 
+#ifdef __APPLE__
 void EthernetTap::whack()
 void EthernetTap::whack()
 {
 {
-	int cpid = fork();
+	long cpid = (long)fork();
 	if (cpid == 0) {
 	if (cpid == 0) {
 		execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0);
 		execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0);
 		exit(-1);
 		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)
 static bool ___removeIp(const char *_dev,const InetAddress &ip)
 {
 {
 	int cpid;
 	int cpid;
@@ -544,6 +404,7 @@ bool EthernetTap::addIP(const InetAddress &ip)
 
 
 	return false;
 	return false;
 }
 }
+#endif // __APPLE__
 
 
 bool EthernetTap::removeIP(const InetAddress &ip)
 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)
 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)) {
 	if ((_fd > 0)&&(len <= _mtu)) {
 		for(int i=0;i<6;++i)
 		for(int i=0;i<6;++i)
-			_putBuf[i] = to.data[i];
+			putBuf[i] = to.data[i];
 		for(int i=0;i<6;++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;
 		len += 14;
-		int n = (int)::write(_fd,_putBuf,len);
+		int n = ::write(_fd,putBuf,len);
 		if (n <= 0) {
 		if (n <= 0) {
 			LOG("error writing packet to Ethernet tap device: %s",strerror(errno));
 			LOG("error writing packet to Ethernet tap device: %s",strerror(errno));
 		} else if (n != (int)len) {
 		} else if (n != (int)len) {
 			// Saw this gremlin once, so log it if we see it again... OSX tap
 			// Saw this gremlin once, so log it if we see it again... OSX tap
 			// or something seems to have goofy issues with certain MTUs.
 			// 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)
 bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
 {
 {
 	std::set<MulticastGroup> newGroups;
 	std::set<MulticastGroup> newGroups;
@@ -690,13 +547,54 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
 
 
 	return changed;
 	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
 } // namespace ZeroTier
 
 
-/* ======================================================================== */
-#elif defined(_WIN32) /* -------------------------------------------------- */
-/* ======================================================================== */
+#endif // __UNIX_LIKE__ //////////////////////////////////////////////////////
+
+#ifdef __WINDOWS__
+
+// TODO
 
 
-/* ======================================================================== */
-#endif
-/* ======================================================================== */
+#endif // __WINDOWS__

+ 30 - 40
node/EthernetTap.hpp

@@ -36,14 +36,13 @@
 #include <set>
 #include <set>
 #include <string>
 #include <string>
 #include <stdexcept>
 #include <stdexcept>
-#include "Array.hpp"
-#include "Utils.hpp"
+#include "Constants.hpp"
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
-#include "NonCopyable.hpp"
 #include "MAC.hpp"
 #include "MAC.hpp"
-#include "Constants.hpp"
 #include "Mutex.hpp"
 #include "Mutex.hpp"
 #include "MulticastGroup.hpp"
 #include "MulticastGroup.hpp"
+#include "Thread.hpp"
+#include "Buffer.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -52,21 +51,35 @@ class RuntimeEnvironment;
 /**
 /**
  * System ethernet tap device
  * System ethernet tap device
  */
  */
-class EthernetTap : NonCopyable
+class EthernetTap : protected Thread
 {
 {
 public:
 public:
 	/**
 	/**
 	 * Construct a new TAP device
 	 * Construct a new TAP device
 	 *
 	 *
+	 * Handler arguments: arg,from,to,etherType,data
+	 * 
 	 * @param renv Runtime environment
 	 * @param renv Runtime environment
 	 * @param mac MAC address of device
 	 * @param mac MAC address of device
 	 * @param mtu MTU of device
 	 * @param mtu MTU of device
+	 * @param handler Handler function to be called when data is received from the tap
+	 * @param arg First argument to handler function
 	 * @throws std::runtime_error Unable to allocate device
 	 * @throws std::runtime_error Unable to allocate device
 	 */
 	 */
-	EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned int mtu)
+	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);
 		throw(std::runtime_error);
 
 
-	~EthernetTap();
+	/**
+	 * Close tap and shut down thread
+	 *
+	 * This may block for a few seconds while thread exits.
+	 */
+	virtual ~EthernetTap();
 
 
 	/**
 	/**
 	 * Perform OS dependent actions on network configuration change detection
 	 * Perform OS dependent actions on network configuration change detection
@@ -137,31 +150,10 @@ public:
 	 */
 	 */
 	void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
 	void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
 
 
-	/**
-	 * Get the next packet from the interface, blocking if none is available.
-	 *
-	 * @param from Filled with MAC address of source (normally our own)
-	 * @param to Filled with MAC address of destination
-	 * @param etherType Filled with Ethernet frame type
-	 * @param buf Buffer to fill (must have room for MTU bytes)
-	 * @return Number of bytes read or 0 if none
-	 */
-	unsigned int get(MAC &from,MAC &to,unsigned int &etherType,void *buf);
-
 	/**
 	/**
 	 * @return OS-specific device or connection name
 	 * @return OS-specific device or connection name
 	 */
 	 */
-	std::string deviceName();
-
-	/**
-	 * @return True if tap is open
-	 */
-	bool open() const;
-
-	/**
-	 * Close this tap, invalidating the object and causing get() to abort
-	 */
-	void close();
+	std::string deviceName() const;
 
 
 	/**
 	/**
 	 * Fill or modify a set to contain multicast groups for this device
 	 * Fill or modify a set to contain multicast groups for this device
@@ -177,6 +169,10 @@ public:
 	 */
 	 */
 	bool updateMulticastGroups(std::set<MulticastGroup> &groups);
 	bool updateMulticastGroups(std::set<MulticastGroup> &groups);
 
 
+protected:
+	virtual void main()
+		throw();
+
 private:
 private:
 	const MAC _mac;
 	const MAC _mac;
 	const unsigned int _mtu;
 	const unsigned int _mtu;
@@ -186,20 +182,14 @@ private:
 	std::set<InetAddress> _ips;
 	std::set<InetAddress> _ips;
 	Mutex _ips_m;
 	Mutex _ips_m;
 
 
-#if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+	void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
+	void *_arg;
 
 
+#ifdef __UNIX_LIKE__
 	char _dev[16];
 	char _dev[16];
-	unsigned char *_putBuf;
-	unsigned char *_getBuf;
 	int _fd;
 	int _fd;
-
-	bool _isReading;
-	pthread_t _isReadingThreadId;
-	Mutex _isReading_m;
-
-#elif defined(_WIN32) /* -------------------------------------------------- */
-
-#endif /* ----------------------------------------------------------------- */
+	int _shutdownSignalPipe[2];
+#endif
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 9 - 29
node/Network.cpp

@@ -32,49 +32,29 @@ namespace ZeroTier {
 
 
 Network::Network(const RuntimeEnvironment *renv,uint64_t id)
 Network::Network(const RuntimeEnvironment *renv,uint64_t id)
 	throw(std::runtime_error) :
 	throw(std::runtime_error) :
-	Thread(),
 	_r(renv),
 	_r(renv),
 	_id(id),
 	_id(id),
-	_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU),
+	_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
 	_members(),
 	_members(),
 	_open(false),
 	_open(false),
 	_lock()
 	_lock()
 {
 {
-	TRACE("new network %llu created, TAP device: %s",id,_tap.deviceName().c_str());
-	start();
 }
 }
 
 
 Network::~Network()
 Network::~Network()
 {
 {
-	_tap.close();
-	join();
-	TRACE("network %llu (%s) closed",_id,_tap.deviceName().c_str());
 }
 }
 
 
-void Network::main()
-	throw()
+void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data)
 {
 {
-	Buffer<4096> buf;
-	MAC from,to;
-	unsigned int etherType = 0;
-
-	while (_tap.open()) {
-		unsigned int len = _tap.get(from,to,etherType,buf.data());
-		if (len) {
-			buf.setSize(len);
-			try {
-				if (!*__refCount)
-					break; // sanity check
-				_r->sw->onLocalEthernet(SharedPtr<Network>(this),from,to,etherType,buf);
-			} catch (std::exception &exc) {
-				TRACE("unexpected exception handling local packet: %s",exc.what());
-			} catch ( ... ) {
-				TRACE("unexpected exception handling local packet");
-			}
-		} else break;
+	const RuntimeEnvironment *_r = ((Network *)arg)->_r;
+	try {
+		_r->sw->onLocalEthernet(SharedPtr<Network>((Network *)arg),from,to,etherType,data);
+	} catch (std::exception &exc) {
+		TRACE("unexpected exception handling local packet: %s",exc.what());
+	} catch ( ... ) {
+		TRACE("unexpected exception handling local packet");
 	}
 	}
-
-	TRACE("network %llu thread terminating",_id);
 }
 }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 6 - 8
node/Network.hpp

@@ -40,8 +40,8 @@
 #include "SharedPtr.hpp"
 #include "SharedPtr.hpp"
 #include "AtomicCounter.hpp"
 #include "AtomicCounter.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "RuntimeEnvironment.hpp"
-#include "Thread.hpp"
 #include "MulticastGroup.hpp"
 #include "MulticastGroup.hpp"
+#include "NonCopyable.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -50,17 +50,17 @@ class NodeConfig;
 /**
 /**
  * Local network endpoint
  * Local network endpoint
  */
  */
-class Network : protected Thread
+class Network : NonCopyable
 {
 {
 	friend class SharedPtr<Network>;
 	friend class SharedPtr<Network>;
 	friend class NodeConfig;
 	friend class NodeConfig;
 
 
 private:
 private:
-	virtual ~Network();
-
 	Network(const RuntimeEnvironment *renv,uint64_t id)
 	Network(const RuntimeEnvironment *renv,uint64_t id)
 		throw(std::runtime_error);
 		throw(std::runtime_error);
 
 
+	~Network();
+
 public:
 public:
 	/**
 	/**
 	 * @return Network ID
 	 * @return Network ID
@@ -141,11 +141,9 @@ public:
 		return _multicastGroups;
 		return _multicastGroups;
 	}
 	}
 
 
-protected:
-	virtual void main()
-		throw();
-
 private:
 private:
+	static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
+
 	const RuntimeEnvironment *_r;
 	const RuntimeEnvironment *_r;
 	uint64_t _id;
 	uint64_t _id;
 	EthernetTap _tap;
 	EthernetTap _tap;

+ 87 - 77
node/Packet.hpp

@@ -263,13 +263,13 @@ public:
 			setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
 			setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
 
 
 			// NOTE: this copies both the IV/packet ID and the destination address.
 			// NOTE: this copies both the IV/packet ID and the destination address.
-			memcpy(_b + ZT_PACKET_FRAGMENT_IDX_PACKET_ID,p.data() + ZT_PACKET_IDX_IV,13);
+			memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.data() + ZT_PACKET_IDX_IV,13);
 
 
-			_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
-			_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
-			_b[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
+			(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
+			(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
+			(*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
 
 
-			memcpy(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD,p.data() + fragStart,fragLen);
+			memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.data() + fragStart,fragLen);
 		}
 		}
 
 
 		/**
 		/**
@@ -277,12 +277,12 @@ public:
 		 * 
 		 * 
 		 * @return Destination ZT address
 		 * @return Destination ZT address
 		 */
 		 */
-		inline Address destination() const { return Address(_b + ZT_PACKET_FRAGMENT_IDX_DEST); }
+		inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH)); }
 
 
 		/**
 		/**
 		 * @return True if fragment is of a valid length
 		 * @return True if fragment is of a valid length
 		 */
 		 */
-		inline bool lengthValid() const { return (_l >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
+		inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
 
 
 		/**
 		/**
 		 * @return ID of packet this is a fragment of
 		 * @return ID of packet this is a fragment of
@@ -292,36 +292,38 @@ public:
 		/**
 		/**
 		 * @return Total number of fragments in packet
 		 * @return Total number of fragments in packet
 		 */
 		 */
-		inline unsigned int totalFragments() const { return (((unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] >> 4) & 0xf); }
+		inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); }
 
 
 		/**
 		/**
 		 * @return Fragment number of this fragment
 		 * @return Fragment number of this fragment
 		 */
 		 */
-		inline unsigned int fragmentNumber() const { return ((unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] & 0xf); }
+		inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); }
 
 
 		/**
 		/**
 		 * @return Fragment ZT hop count
 		 * @return Fragment ZT hop count
 		 */
 		 */
-		inline unsigned int hops() const { return (unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_HOPS]; }
+		inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); }
 
 
 		/**
 		/**
 		 * Increment this packet's hop count
 		 * Increment this packet's hop count
 		 */
 		 */
 		inline void incrementHops()
 		inline void incrementHops()
 		{
 		{
-			_b[ZT_PACKET_FRAGMENT_IDX_HOPS] = (_b[ZT_PACKET_FRAGMENT_IDX_HOPS] + 1) & ZT_PROTO_MAX_HOPS;
+			(*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS;
 		}
 		}
 
 
 		/**
 		/**
-		 * @return Fragment payload
+		 * @return Length of payload in bytes
 		 */
 		 */
-		inline unsigned char *payload() { return (unsigned char *)(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
-		inline const unsigned char *payload() const { return (const unsigned char *)(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
+		inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
 
 
 		/**
 		/**
-		 * @return Length of payload in bytes
+		 * @return Raw packet payload
 		 */
 		 */
-		inline unsigned int payloadLength() const { return ((_l > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (_l - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
+		inline const unsigned char *payload() const
+		{
+			return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
+		}
 	};
 	};
 
 
 	/**
 	/**
@@ -495,8 +497,8 @@ public:
 	Packet() :
 	Packet() :
 		Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
 		Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
 	{
 	{
-		Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
-		_b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+		Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+		(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
 	}
 	}
 
 
 	/**
 	/**
@@ -509,10 +511,10 @@ public:
 	Packet(const Address &dest,const Address &source,const Verb v) :
 	Packet(const Address &dest,const Address &source,const Verb v) :
 		Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
 		Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
 	{
 	{
-		Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
+		Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
 		setDestination(dest);
 		setDestination(dest);
 		setSource(source);
 		setSource(source);
-		_b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+		(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
 		setVerb(v);
 		setVerb(v);
 	}
 	}
 
 
@@ -526,10 +528,10 @@ public:
 	inline void reset(const Address &dest,const Address &source,const Verb v)
 	inline void reset(const Address &dest,const Address &source,const Verb v)
 	{
 	{
 		setSize(ZT_PROTO_MIN_PACKET_LENGTH);
 		setSize(ZT_PROTO_MIN_PACKET_LENGTH);
-		Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
+		Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
 		setDestination(dest);
 		setDestination(dest);
 		setSource(source);
 		setSource(source);
-		_b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+		(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
 		setVerb(v);
 		setVerb(v);
 	}
 	}
 
 
@@ -540,8 +542,9 @@ public:
 	 */
 	 */
 	inline void setDestination(const Address &dest)
 	inline void setDestination(const Address &dest)
 	{
 	{
+		unsigned char *d = field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH);
 		for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
 		for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
-			_b[i + ZT_PACKET_IDX_DEST] = dest[i];
+			d[i] = dest[i];
 	}
 	}
 
 
 	/**
 	/**
@@ -551,8 +554,9 @@ public:
 	 */
 	 */
 	inline void setSource(const Address &source)
 	inline void setSource(const Address &source)
 	{
 	{
+		unsigned char *s = field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH);
 		for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
 		for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
-			_b[i + ZT_PACKET_IDX_SOURCE] = source[i];
+			s[i] = source[i];
 	}
 	}
 
 
 	/**
 	/**
@@ -560,29 +564,29 @@ public:
 	 * 
 	 * 
 	 * @return Destination ZT address
 	 * @return Destination ZT address
 	 */
 	 */
-	inline Address destination() const { return Address(_b + ZT_PACKET_IDX_DEST); }
+	inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH)); }
 
 
 	/**
 	/**
 	 * Get this packet's source
 	 * Get this packet's source
 	 * 
 	 * 
 	 * @return Source ZT address
 	 * @return Source ZT address
 	 */
 	 */
-	inline Address source() const { return Address(_b + ZT_PACKET_IDX_SOURCE); }
+	inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH)); }
 
 
 	/**
 	/**
 	 * @return True if packet is of valid length
 	 * @return True if packet is of valid length
 	 */
 	 */
-	inline bool lengthValid() const { return (_l >= ZT_PROTO_MIN_PACKET_LENGTH); }
+	inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); }
 
 
 	/**
 	/**
 	 * @return True if packet is encrypted
 	 * @return True if packet is encrypted
 	 */
 	 */
-	inline bool encrypted() const { return (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_ENCRYPTED)); }
+	inline bool encrypted() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_ENCRYPTED)); }
 
 
 	/**
 	/**
 	 * @return True if packet is fragmented (expect fragments)
 	 * @return True if packet is fragmented (expect fragments)
 	 */
 	 */
-	inline bool fragmented() const { return (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED)); }
+	inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED)); }
 
 
 	/**
 	/**
 	 * Set this packet's fragmented flag
 	 * Set this packet's fragmented flag
@@ -592,26 +596,26 @@ public:
 	inline void setFragmented(bool f)
 	inline void setFragmented(bool f)
 	{
 	{
 		if (f)
 		if (f)
-			_b[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
-		else _b[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
+			(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
+		else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
 	}
 	}
 
 
 	/**
 	/**
 	 * @return True if compressed (result only valid if unencrypted)
 	 * @return True if compressed (result only valid if unencrypted)
 	 */
 	 */
-	inline bool compressed() const { return (((unsigned char)_b[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED)); }
+	inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED)); }
 
 
 	/**
 	/**
 	 * @return ZeroTier forwarding hops (0 to 7)
 	 * @return ZeroTier forwarding hops (0 to 7)
 	 */
 	 */
-	inline unsigned int hops() const { return ((unsigned int)_b[ZT_PACKET_IDX_FLAGS] & 0x07); }
+	inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); }
 
 
 	/**
 	/**
 	 * Increment this packet's hop count
 	 * Increment this packet's hop count
 	 */
 	 */
 	inline void incrementHops()
 	inline void incrementHops()
 	{
 	{
-		_b[ZT_PACKET_IDX_FLAGS] = (char)((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & 0xf8) | (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] + 1) & 0x07);
+		(*this)[ZT_PACKET_IDX_FLAGS] = (char)((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & 0xf8) | (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] + 1) & 0x07);
 	}
 	}
 
 
 	/**
 	/**
@@ -629,23 +633,25 @@ public:
 	 * 
 	 * 
 	 * @param v New packet verb
 	 * @param v New packet verb
 	 */
 	 */
-	inline void setVerb(Verb v) { _b[ZT_PACKET_IDX_VERB] = (char)v; }
+	inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
 
 
 	/**
 	/**
 	 * @return Packet verb (not including flag bits)
 	 * @return Packet verb (not including flag bits)
 	 */
 	 */
-	inline Verb verb() const { return (Verb)(_b[ZT_PACKET_IDX_VERB] & 0x1f); }
+	inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); }
 
 
 	/**
 	/**
 	 * @return Length of packet payload
 	 * @return Length of packet payload
 	 */
 	 */
-	inline unsigned int payloadLength() const throw() { return ((_l < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (_l - ZT_PROTO_MIN_PACKET_LENGTH)); }
+	inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); }
 
 
 	/**
 	/**
-	 * @return Packet payload
+	 * @return Raw packet payload
 	 */
 	 */
-	inline unsigned char *payload() throw() { return (unsigned char *)(_b + ZT_PACKET_IDX_PAYLOAD); }
-	inline const unsigned char *payload() const throw() { return (const unsigned char *)(_b + ZT_PACKET_IDX_PAYLOAD); }
+	inline const unsigned char *payload() const
+	{
+		return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
+	}
 
 
 	/**
 	/**
 	 * Compute the HMAC of this packet's payload and set HMAC field
 	 * Compute the HMAC of this packet's payload and set HMAC field
@@ -655,13 +661,13 @@ public:
 	 * @param key 256-bit (32 byte) key
 	 * @param key 256-bit (32 byte) key
 	 */
 	 */
 	inline void hmacSet(const void *key)
 	inline void hmacSet(const void *key)
-		throw()
 	{
 	{
 		unsigned char mac[32];
 		unsigned char mac[32];
 		unsigned char key2[32];
 		unsigned char key2[32];
 		_mangleKey((const unsigned char *)key,key2);
 		_mangleKey((const unsigned char *)key,key2);
-		HMAC::sha256(key2,sizeof(key2),_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0,mac);
-		memcpy(_b + ZT_PACKET_IDX_HMAC,mac,8);
+		unsigned int hmacLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
+		HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
+		memcpy(field(ZT_PACKET_IDX_HMAC,8),mac,8);
 	}
 	}
 
 
 	/**
 	/**
@@ -672,15 +678,15 @@ public:
 	 * @param key 256-bit (32 byte) key
 	 * @param key 256-bit (32 byte) key
 	 */
 	 */
 	inline bool hmacVerify(const void *key) const
 	inline bool hmacVerify(const void *key) const
-		throw()
 	{
 	{
 		unsigned char mac[32];
 		unsigned char mac[32];
 		unsigned char key2[32];
 		unsigned char key2[32];
-		if (_l < ZT_PACKET_IDX_VERB)
+		if (size() < ZT_PACKET_IDX_VERB)
 			return false; // incomplete packets fail
 			return false; // incomplete packets fail
 		_mangleKey((const unsigned char *)key,key2);
 		_mangleKey((const unsigned char *)key,key2);
-		HMAC::sha256(key2,sizeof(key2),_b + ZT_PACKET_IDX_VERB,_l - ZT_PACKET_IDX_VERB,mac);
-		return (!memcmp(_b + ZT_PACKET_IDX_HMAC,mac,8));
+		unsigned int hmacLen = size() - ZT_PACKET_IDX_VERB;
+		HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
+		return (!memcmp(field(ZT_PACKET_IDX_HMAC,8),mac,8));
 	}
 	}
 
 
 	/**
 	/**
@@ -689,13 +695,16 @@ public:
 	 * @param key 256-bit (32 byte) key
 	 * @param key 256-bit (32 byte) key
 	 */
 	 */
 	inline void encrypt(const void *key)
 	inline void encrypt(const void *key)
-		throw()
 	{
 	{
-		_b[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
+		(*this)[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
 		unsigned char key2[32];
 		unsigned char key2[32];
-		_mangleKey((const unsigned char *)key,key2);
-		Salsa20 s20(key2,256,_b + ZT_PACKET_IDX_IV);
-		s20.encrypt(_b + ZT_PACKET_IDX_VERB,_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0);
+		if (size() >= ZT_PACKET_IDX_VERB) {
+			_mangleKey((const unsigned char *)key,key2);
+			Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
+			unsigned int encLen = size() - ZT_PACKET_IDX_VERB;
+			unsigned char *const encBuf = field(ZT_PACKET_IDX_VERB,encLen);
+			s20.encrypt(encBuf,encBuf,encLen);
+		}
 	}
 	}
 
 
 	/**
 	/**
@@ -704,13 +713,16 @@ public:
 	 * @param key 256-bit (32 byte) key
 	 * @param key 256-bit (32 byte) key
 	 */
 	 */
 	inline void decrypt(const void *key)
 	inline void decrypt(const void *key)
-		throw()
 	{
 	{
 		unsigned char key2[32];
 		unsigned char key2[32];
-		_mangleKey((const unsigned char *)key,key2);
-		Salsa20 s20(key2,256,_b + ZT_PACKET_IDX_IV);
-		s20.decrypt(_b + ZT_PACKET_IDX_VERB,_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0);
-		_b[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+		if (size() >= ZT_PACKET_IDX_VERB) {
+			_mangleKey((const unsigned char *)key,key2);
+			Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
+			unsigned int decLen = size() - ZT_PACKET_IDX_VERB;
+			unsigned char *const decBuf = field(ZT_PACKET_IDX_VERB,decLen);
+			s20.decrypt(decBuf,decBuf,decLen);
+		}
+		(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
 	}
 	}
 
 
 	/**
 	/**
@@ -724,20 +736,19 @@ public:
 	 * @return True if compression occurred
 	 * @return True if compression occurred
 	 */
 	 */
 	inline bool compress()
 	inline bool compress()
-		throw()
 	{
 	{
 		unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2];
 		unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2];
-		if ((!compressed())&&(_l > (ZT_PACKET_IDX_PAYLOAD + 32))) {
-			int pl = (int)(_l - ZT_PACKET_IDX_PAYLOAD);
-			int cl = LZ4_compress((const char *)(_b + ZT_PACKET_IDX_PAYLOAD),(char *)buf,pl);
+		if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 32))) {
+			int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD);
+			int cl = LZ4_compress((const char *)field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)pl),(char *)buf,pl);
 			if ((cl > 0)&&(cl < pl)) {
 			if ((cl > 0)&&(cl < pl)) {
-				_b[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
-				memcpy(_b + ZT_PACKET_IDX_PAYLOAD,buf,cl);
-				_l = (unsigned int)cl + ZT_PACKET_IDX_PAYLOAD;
+				(*this)[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
+				setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD);
+				memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)cl),buf,cl);
 				return true;
 				return true;
 			}
 			}
 		}
 		}
-		_b[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
+		(*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
 		return false;
 		return false;
 	}
 	}
 
 
@@ -750,18 +761,18 @@ public:
 	 * @return True if data is now decompressed and valid, false on error
 	 * @return True if data is now decompressed and valid, false on error
 	 */
 	 */
 	inline bool uncompress()
 	inline bool uncompress()
-		throw()
 	{
 	{
 		unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH];
 		unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH];
-		if ((compressed())&&(_l >= ZT_PROTO_MIN_PACKET_LENGTH)) {
-			if (_l > ZT_PACKET_IDX_PAYLOAD) {
-				int ucl = LZ4_uncompress_unknownOutputSize((const char *)(_b + ZT_PACKET_IDX_PAYLOAD),(char *)buf,_l - ZT_PACKET_IDX_PAYLOAD,sizeof(buf));
+		if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) {
+			if (size() > ZT_PACKET_IDX_PAYLOAD) {
+				unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD;
+				int ucl = LZ4_uncompress_unknownOutputSize((const char *)field(ZT_PACKET_IDX_PAYLOAD,compLen),(char *)buf,compLen,sizeof(buf));
 				if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) {
 				if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) {
-					memcpy(_b + ZT_PACKET_IDX_PAYLOAD,buf,ucl);
-					_l = (unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD;
+					setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD);
+					memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl);
 				} else return false;
 				} else return false;
 			}
 			}
-			_b[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
+			(*this)[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
 		}
 		}
 		return true;
 		return true;
 	}
 	}
@@ -788,19 +799,18 @@ private:
 	 * @param out Output buffer (32 bytes)
 	 * @param out Output buffer (32 bytes)
 	 */
 	 */
 	inline void _mangleKey(const unsigned char *in,unsigned char *out) const
 	inline void _mangleKey(const unsigned char *in,unsigned char *out) const
-		throw()
 	{
 	{
 		// Random IV (Salsa20 also uses the IV natively, but HMAC doesn't), and
 		// Random IV (Salsa20 also uses the IV natively, but HMAC doesn't), and
 		// destination and source addresses. Using dest and source addresses
 		// destination and source addresses. Using dest and source addresses
 		// gives us a (likely) different key space for a->b vs b->a.
 		// gives us a (likely) different key space for a->b vs b->a.
 		for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
 		for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
-			out[i] = in[i] ^ (unsigned char)_b[i];
+			out[i] = in[i] ^ (unsigned char)(*this)[i];
 		// Flags, but masking off hop count which is altered by forwarding nodes
 		// Flags, but masking off hop count which is altered by forwarding nodes
-		out[18] = in[18] ^ ((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & 0xf8);
+		out[18] = in[18] ^ ((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & 0xf8);
 		// Raw packet size in bytes -- each raw packet size defines a possibly
 		// Raw packet size in bytes -- each raw packet size defines a possibly
 		// different space of keys.
 		// different space of keys.
-		out[19] = in[19] ^ (unsigned char)(_l & 0xff);
-		out[20] = in[20] ^ (unsigned char)((_l >> 8) & 0xff); // little endian
+		out[19] = in[19] ^ (unsigned char)(size() & 0xff);
+		out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
 		// Rest of raw key is used unchanged
 		// Rest of raw key is used unchanged
 		for(unsigned int i=21;i<32;++i)
 		for(unsigned int i=21;i<32;++i)
 			out[i] = in[i];
 			out[i] = in[i];

+ 1 - 0
node/Salsa20.cpp

@@ -5,6 +5,7 @@
  */
  */
 
 
 #include "Salsa20.hpp"
 #include "Salsa20.hpp"
+#include "Constants.hpp"
 
 
 #define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c))))
 #define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c))))
 #define XOR(v,w) ((v) ^ (w))
 #define XOR(v,w) ((v) ^ (w))

+ 2 - 0
selftest.cpp

@@ -291,6 +291,8 @@ static int testNet()
 	std::cout << "[net] GET http://www.google.com/" << std::endl;
 	std::cout << "[net] GET http://www.google.com/" << std::endl;
 	new Http::Request(Http::HTTP_METHOD_GET,"http://www.google.com/",Http::EMPTY_HEADERS,std::string(),&testHttpHandler,(void *)0);
 	new Http::Request(Http::HTTP_METHOD_GET,"http://www.google.com/",Http::EMPTY_HEADERS,std::string(),&testHttpHandler,(void *)0);
 	testHttpDoneCondition.wait();
 	testHttpDoneCondition.wait();
+
+	return 0;
 }
 }
 
 
 int main(int argc,char **argv)
 int main(int argc,char **argv)