Browse Source

Simplify Phy<> to get rid of more indirections.

Adam Ierymenko 10 years ago
parent
commit
5572b7ffb6
7 changed files with 153 additions and 243 deletions
  1. 1 1
      make-freebsd.mk
  2. 1 1
      make-linux.mk
  3. 1 1
      make-mac.mk
  4. 22 62
      osdep/Phy.hpp
  5. 55 112
      selftest.cpp
  6. 73 63
      service/One.cpp
  7. 0 3
      service/One.hpp

+ 1 - 1
make-freebsd.mk

@@ -84,7 +84,7 @@ testnet: $(TESTNET_OBJS) $(OBJS) testnet.o
 #	./buildinstaller.sh
 #	./buildinstaller.sh
 
 
 clean:
 clean:
-	rm -rf $(OBJS) $(TESTNET_OBJS) node/*.o osdep/*.o control/*.o testnet/*.o *.o zerotier-* build-* ZeroTierOneInstaller-*
+	rm -rf *.o netconf/*.o node/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o build-* zerotier-* ZeroTierOneInstaller-*
 
 
 debug:	FORCE
 debug:	FORCE
 	make -j 4 ZT_DEBUG=1
 	make -j 4 ZT_DEBUG=1

+ 1 - 1
make-linux.mk

@@ -89,7 +89,7 @@ installer: one FORCE
 	./buildinstaller.sh
 	./buildinstaller.sh
 
 
 clean:
 clean:
-	rm -rf *.o netconf/*.o node/*.o osdep/*.o control/*.o testnet/*.o ext/lz4/*.o zerotier-* build-* ZeroTierOneInstaller-* *.deb *.rpm
+	rm -rf *.o netconf/*.o node/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-* build-* ZeroTierOneInstaller-* *.deb *.rpm
 
 
 debug:	FORCE
 debug:	FORCE
 	make -j 4 ZT_DEBUG=1
 	make -j 4 ZT_DEBUG=1

+ 1 - 1
make-mac.mk

@@ -77,7 +77,7 @@ mac-ui: FORCE
 	$(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app"
 	$(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app"
 
 
 clean:
 clean:
-	rm -rf *.dSYM build-* *.o netconf/*.o control/*.o node/*.o testnet/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-* ZeroTierOneInstaller-* "ZeroTier One.zip" "ZeroTier One.dmg"
+	rm -rf *.dSYM build-* *.o netconf/*.o service/*.o node/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-* ZeroTierOneInstaller-* "ZeroTier One.zip" "ZeroTier One.dmg"
 
 
 # For our use -- builds official signed binary, packages in installer and download DMG
 # For our use -- builds official signed binary, packages in installer and download DMG
 official: FORCE
 official: FORCE

+ 22 - 62
osdep/Phy.hpp

@@ -83,15 +83,15 @@ typedef void PhySocket;
  * Yes there is boost::asio and libuv, but I like small binaries and I hate
  * Yes there is boost::asio and libuv, but I like small binaries and I hate
  * build dependencies. Both drag in a whole bunch of pasta with them.
  * build dependencies. Both drag in a whole bunch of pasta with them.
  *
  *
- * This implementation takes four functions or function objects as template
- * paramters:
+ * This class is templated on a pointer to a handler class which must
+ * implement the following functions:
  *
  *
- * ON_DATAGRAM_FUNCTION(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
- * ON_TCP_CONNECT_FUNCTION(PhySocket *sock,void **uptr,bool success)
- * ON_TCP_ACCEPT_FUNCTION(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
- * ON_TCP_CLOSE_FUNCTION(PhySocket *sock,void **uptr)
- * ON_TCP_DATA_FUNCTION(PhySocket *sock,void **uptr,void *data,unsigned long len)
- * ON_TCP_WRITABLE_FUNCTION(PhySocket *sock,void **uptr)
+ * 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)
  *
  *
  * These templates typically refer to function objects. Templates are used to
  * These templates typically refer to function objects. Templates are used to
  * avoid the call overhead of indirection, which is surprisingly high for high
  * avoid the call overhead of indirection, which is surprisingly high for high
@@ -114,22 +114,11 @@ typedef void PhySocket;
  * This isn't thread-safe with the exception of whack(), which is safe to
  * This isn't thread-safe with the exception of whack(), which is safe to
  * call from another thread to abort poll().
  * call from another thread to abort poll().
  */
  */
-template <
-	typename ON_DATAGRAM_FUNCTION,
-	typename ON_TCP_CONNECT_FUNCTION,
-	typename ON_TCP_ACCEPT_FUNCTION,
-	typename ON_TCP_CLOSE_FUNCTION,
-	typename ON_TCP_DATA_FUNCTION,
-	typename ON_TCP_WRITABLE_FUNCTION >
+template <typename HANDLER_PTR_TYPE>
 class Phy
 class Phy
 {
 {
 private:
 private:
-	ON_DATAGRAM_FUNCTION _datagramHandler;
-	ON_TCP_CONNECT_FUNCTION _tcpConnectHandler;
-	ON_TCP_ACCEPT_FUNCTION _tcpAcceptHandler;
-	ON_TCP_CLOSE_FUNCTION _tcpCloseHandler;
-	ON_TCP_DATA_FUNCTION _tcpDataHandler;
-	ON_TCP_WRITABLE_FUNCTION _tcpWritableHandler;
+	HANDLER_PTR_TYPE _handler;
 
 
 	enum PhySocketType
 	enum PhySocketType
 	{
 	{
@@ -164,27 +153,11 @@ private:
 
 
 public:
 public:
 	/**
 	/**
-	 * @param datagramHandler Function or function object to handle UDP or RAW datagrams
-	 * @param tcpConnectHandler Handler for outgoing TCP connection attempts (success or failure)
-	 * @param tcpAcceptHandler Handler for incoming TCP connections
-	 * @param tcpDataHandler Handler for incoming TCP data
-	 * @param tcpWritableHandler Handler to be called when TCP sockets are writable (if notification is on)
-	 * @param noDelay If true, disable Nagle algorithm on new TCP sockets
+	 * @param handler Pointer of type HANDLER_PTR_TYPE to handler
+	 * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets
 	 */
 	 */
-	Phy(
-		ON_DATAGRAM_FUNCTION datagramHandler,
-		ON_TCP_CONNECT_FUNCTION tcpConnectHandler,
-		ON_TCP_ACCEPT_FUNCTION tcpAcceptHandler,
-		ON_TCP_CLOSE_FUNCTION tcpCloseHandler,
-		ON_TCP_DATA_FUNCTION tcpDataHandler,
-		ON_TCP_WRITABLE_FUNCTION tcpWritableHandler,
-		bool noDelay) :
-		_datagramHandler(datagramHandler),
-		_tcpConnectHandler(tcpConnectHandler),
-		_tcpAcceptHandler(tcpAcceptHandler),
-		_tcpCloseHandler(tcpCloseHandler),
-		_tcpDataHandler(tcpDataHandler),
-		_tcpWritableHandler(tcpWritableHandler)
+	Phy(HANDLER_PTR_TYPE handler,bool noDelay) :
+		_handler(handler)
 	{
 	{
 		FD_ZERO(&_readfds);
 		FD_ZERO(&_readfds);
 		FD_ZERO(&_writefds);
 		FD_ZERO(&_writefds);
@@ -526,7 +499,7 @@ public:
 
 
 		if ((callConnectHandler)&&(connected)) {
 		if ((callConnectHandler)&&(connected)) {
 			try {
 			try {
-				_tcpConnectHandler((PhySocket *)&sws,&(sws.uptr),true);
+				_handler->phyOnTcpConnect((PhySocket *)&sws,&(sws.uptr),true);
 			} catch ( ... ) {}
 			} catch ( ... ) {}
 		}
 		}
 
 
@@ -664,7 +637,7 @@ public:
 							FD_CLR(s->sock,&_exceptfds);
 							FD_CLR(s->sock,&_exceptfds);
 #endif
 #endif
 							try {
 							try {
-								_tcpConnectHandler((PhySocket *)&(*s),&(s->uptr),true);
+								_handler->phyOnTcpConnect((PhySocket *)&(*s),&(s->uptr),true);
 							} catch ( ... ) {}
 							} catch ( ... ) {}
 						}
 						}
 					}
 					}
@@ -678,13 +651,13 @@ public:
 							this->close((PhySocket *)&(*s),true);
 							this->close((PhySocket *)&(*s),true);
 						} else {
 						} else {
 							try {
 							try {
-								_tcpDataHandler((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n);
+								_handler->phyOnTcpData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n);
 							} catch ( ... ) {}
 							} catch ( ... ) {}
 						}
 						}
 					}
 					}
 					if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) {
 					if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) {
 						try {
 						try {
-							_tcpWritableHandler((PhySocket *)&(*s),&(s->uptr));
+							_handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr));
 						} catch ( ... ) {}
 						} catch ( ... ) {}
 					}
 					}
 					break;
 					break;
@@ -715,7 +688,7 @@ public:
 								sws.uptr = (void *)0;
 								sws.uptr = (void *)0;
 								memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage));
 								memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage));
 								try {
 								try {
-									_tcpAcceptHandler((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr),(const struct sockaddr *)&(sws.saddr));
+									_handler->phyOnTcpAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr),(const struct sockaddr *)&(sws.saddr));
 								} catch ( ... ) {}
 								} catch ( ... ) {}
 							}
 							}
 						}
 						}
@@ -730,7 +703,7 @@ public:
 							long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen);
 							long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen);
 							if (n > 0) {
 							if (n > 0) {
 								try {
 								try {
-									_datagramHandler((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n);
+									_handler->phyOnDatagram((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n);
 								} catch ( ... ) {}
 								} catch ( ... ) {}
 							} else if (n < 0)
 							} else if (n < 0)
 								break;
 								break;
@@ -767,7 +740,7 @@ public:
 			case ZT_PHY_SOCKET_TCP_OUT_PENDING:
 			case ZT_PHY_SOCKET_TCP_OUT_PENDING:
 				if (callHandlers) {
 				if (callHandlers) {
 					try {
 					try {
-						_tcpConnectHandler(sock,&(sws.uptr),false);
+						_handler->phyOnTcpConnect(sock,&(sws.uptr),false);
 					} catch ( ... ) {}
 					} catch ( ... ) {}
 				}
 				}
 				break;
 				break;
@@ -775,7 +748,7 @@ public:
 			case ZT_PHY_SOCKET_TCP_IN:
 			case ZT_PHY_SOCKET_TCP_IN:
 				if (callHandlers) {
 				if (callHandlers) {
 					try {
 					try {
-						_tcpCloseHandler(sock,&(sws.uptr));
+						_handler->phyOnTcpClose(sock,&(sws.uptr));
 					} catch ( ... ) {}
 					} catch ( ... ) {}
 				}
 				}
 				break;
 				break;
@@ -805,19 +778,6 @@ public:
 	}
 	}
 };
 };
 
 
-// Typedefs for using regular naked functions as template parameters to Phy<>
-typedef void (*Phy_OnDatagramFunctionPtr)(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len);
-typedef void (*Phy_OnTcpConnectFunction)(PhySocket *sock,void **uptr,bool success);
-typedef void (*Phy_OnTcpAcceptFunction)(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from);
-typedef void (*Phy_OnTcpCloseFunction)(PhySocket *sock,void **uptr);
-typedef void (*Phy_OnTcpDataFunction)(PhySocket *sock,void **uptr,void *data,unsigned long len);
-typedef void (*Phy_OnTcpWritableFunction)(PhySocket *sock,void **uptr);
-
-/**
- * Phy<> typedef'd to use simple naked function pointers
- */
-typedef Phy<Phy_OnDatagramFunctionPtr,Phy_OnTcpConnectFunction,Phy_OnTcpAcceptFunction,Phy_OnTcpCloseFunction,Phy_OnTcpDataFunction,Phy_OnTcpWritableFunction> SimpleFunctionPhy;
-
 } // namespace ZeroTier
 } // namespace ZeroTier
 
 
 #endif
 #endif

+ 55 - 112
selftest.cpp

@@ -46,17 +46,15 @@
 #include "node/Salsa20.hpp"
 #include "node/Salsa20.hpp"
 #include "node/MAC.hpp"
 #include "node/MAC.hpp"
 #include "node/Peer.hpp"
 #include "node/Peer.hpp"
-#include "node/NodeConfig.hpp"
 #include "node/Dictionary.hpp"
 #include "node/Dictionary.hpp"
-#include "node/EthernetTap.hpp"
 #include "node/SHA512.hpp"
 #include "node/SHA512.hpp"
 #include "node/C25519.hpp"
 #include "node/C25519.hpp"
 #include "node/Poly1305.hpp"
 #include "node/Poly1305.hpp"
 #include "node/CertificateOfMembership.hpp"
 #include "node/CertificateOfMembership.hpp"
-#include "node/HttpClient.hpp"
 #include "node/Defaults.hpp"
 #include "node/Defaults.hpp"
 #include "node/Node.hpp"
 #include "node/Node.hpp"
 
 
+#include "osdep/OSUtils.hpp"
 #ifdef ZT_TEST_PHY
 #ifdef ZT_TEST_PHY
 #include "osdep/Phy.hpp"
 #include "osdep/Phy.hpp"
 #endif
 #endif
@@ -147,69 +145,6 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
 
 
 static unsigned char fuzzbuf[1048576];
 static unsigned char fuzzbuf[1048576];
 
 
-static volatile bool webDone = false;
-static std::string webSha512ShouldBe;
-static void testHttpHandler(void *arg,int code,const std::string &url,const std::string &body)
-{
-	unsigned char sha[64];
-	if (code == 200) {
-		SHA512::hash(sha,body.data(),(unsigned int)body.length());
-		if (webSha512ShouldBe == Utils::hex(sha,64))
-			std::cout << "got " << body.length() << " bytes, response code " << code << ", SHA-512 OK" << std::endl;
-		else std::cout << "got " << body.length() << " bytes, response code " << code << ", SHA-512 FAILED!" << std::endl;
-	} else std::cout << "ERROR " << code << ": " << body << std::endl;
-	webDone = true;
-}
-
-static int testHttp()
-{
-	HttpClient http;
-
-	webSha512ShouldBe = "221b348c8278ad2063c158fb15927c35dc6bb42880daf130d0574025f88ec350811c34fae38a014b576d3ef5c98af32bb540e68204810db87a51fa9b239ea567";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/1k ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/1k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "342e1a058332aad2d7a5412c1d9cd4ad02b4038178ca0c3ed9d34e3cf0905c118b684e5d2a935a158195d453d7d69e9c6e201e252620fb53f29611794a5d4b0c";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/2k ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/2k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "439562e1471dd6bdb558cb680f38dd7742e521497e280cb1456a31f74b9216b7d98145b3896c2f68008e6ac0c1662a4cb70562caeac294c5d01f378b22a21292";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/4k ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/4k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "fbd3901a9956158b9d290efa1af4fff459d8c03187c98b0e630d10a19fab61940e668652257763973f6cde34f2aa81574f9a50b1979b675b45ddd18d69a4ceb8";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/8k ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/8k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "098ae593f8c3a962f385f9f008ec2116ad22eea8bc569fc88a06a0193480fdfb27470345c427116d19179fb2a74df21d95fe5f1df575a9f2d10d99595708b765";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/4m ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/4m",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "";
-	std::cout << "[http] fetching http://download.zerotier.com/dev/NOEXIST ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://download.zerotier.com/dev/NOEXIST",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	webSha512ShouldBe = "";
-	std::cout << "[http] fetching http://1.1.1.1/SHOULD_TIME_OUT ... "; std::cout.flush();
-	webDone = false;
-	http.GET("http://1.1.1.1/SHOULD_TIME_OUT",HttpClient::NO_HEADERS,4,&testHttpHandler,(void *)0);
-	while (!webDone) Thread::sleep(500);
-
-	return 0;
-}
-
 static int testCrypto()
 static int testCrypto()
 {
 {
 	unsigned char buf1[16384];
 	unsigned char buf1[16384];
@@ -261,12 +196,12 @@ static int testCrypto()
 			bb[i] = (unsigned char)i;
 			bb[i] = (unsigned char)i;
 		Salsa20 s20(s20TV0Key,256,s20TV0Iv,12);
 		Salsa20 s20(s20TV0Key,256,s20TV0Iv,12);
 		double bytes = 0.0;
 		double bytes = 0.0;
-		uint64_t start = Utils::now();
+		uint64_t start = OSUtils::now();
 		for(unsigned int i=0;i<200;++i) {
 		for(unsigned int i=0;i<200;++i) {
 			s20.encrypt(bb,bb,1234567);
 			s20.encrypt(bb,bb,1234567);
 			bytes += 1234567.0;
 			bytes += 1234567.0;
 		}
 		}
-		uint64_t end = Utils::now();
+		uint64_t end = OSUtils::now();
 		SHA512::hash(buf1,bb,1234567);
 		SHA512::hash(buf1,bb,1234567);
 		std::cout << ((bytes / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16) << ')' << std::endl;
 		std::cout << ((bytes / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16) << ')' << std::endl;
 		::free((void *)bb);
 		::free((void *)bb);
@@ -415,9 +350,9 @@ static int testIdentity()
 
 
 	for(unsigned int k=0;k<4;++k) {
 	for(unsigned int k=0;k<4;++k) {
 		std::cout << "[identity] Generate identity... "; std::cout.flush();
 		std::cout << "[identity] Generate identity... "; std::cout.flush();
-		uint64_t genstart = Utils::now();
+		uint64_t genstart = OSUtils::now();
 		id.generate();
 		id.generate();
-		uint64_t genend = Utils::now();
+		uint64_t genend = OSUtils::now();
 		std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true) << std::endl;
 		std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true) << std::endl;
 		std::cout << "[identity] Locally validate identity: ";
 		std::cout << "[identity] Locally validate identity: ";
 		if (id.locallyValidate()) {
 		if (id.locallyValidate()) {
@@ -658,45 +593,54 @@ static unsigned long phyTestTcpByteCount = 0;
 static unsigned long phyTestTcpConnectSuccessCount = 0;
 static unsigned long phyTestTcpConnectSuccessCount = 0;
 static unsigned long phyTestTcpConnectFailCount = 0;
 static unsigned long phyTestTcpConnectFailCount = 0;
 static unsigned long phyTestTcpAcceptCount = 0;
 static unsigned long phyTestTcpAcceptCount = 0;
-static SimpleFunctionPhy *testPhyInstance = (SimpleFunctionPhy *)0;
-static void testPhyOnDatagramFunction(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
-{
-	++phyTestUdpPacketCount;
-}
-static void testPhyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success)
+struct TestPhyHandlers;
+static Phy<TestPhyHandlers *> *testPhyInstance = (Phy<TestPhyHandlers *> *)0;
+struct TestPhyHandlers
 {
 {
-	if (success) {
-		++phyTestTcpConnectSuccessCount;
-	} else {
-		++phyTestTcpConnectFailCount;
+	inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
+	{
+		++phyTestUdpPacketCount;
 	}
 	}
-}
-static void testPhyOnTcpAcceptFunction(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
-{
-	++phyTestTcpAcceptCount;
-	*uptrN = new std::string(ZT_TEST_PHY_TCP_MESSAGE_SIZE,(char)0xff);
-	testPhyInstance->tcpSetNotifyWritable(sockN,true);
-}
-static void testPhyOnTcpCloseFunction(PhySocket *sock,void **uptr)
-{
-	delete (std::string *)*uptr; // delete testMessage if any
-}
-static void testPhyOnTcpDataFunction(PhySocket *sock,void **uptr,void *data,unsigned long len)
-{
-	phyTestTcpByteCount += len;
-}
-static void testPhyOnTcpWritableFunction(PhySocket *sock,void **uptr)
-{
-	std::string *testMessage = (std::string *)*uptr;
-	if ((testMessage)&&(testMessage->length() > 0)) {
-		long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),testMessage->length(),true);
-		if (sent > 0)
-			testMessage->erase(0,sent);
+
+	inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
+	{
+		if (success) {
+			++phyTestTcpConnectSuccessCount;
+		} else {
+			++phyTestTcpConnectFailCount;
+		}
+	}
+
+	inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
+	{
+		++phyTestTcpAcceptCount;
+		*uptrN = new std::string(ZT_TEST_PHY_TCP_MESSAGE_SIZE,(char)0xff);
+		testPhyInstance->tcpSetNotifyWritable(sockN,true);
 	}
 	}
-	if ((!testMessage)||(!testMessage->length())) {
-		testPhyInstance->close(sock,true);
+
+	inline void phyOnTcpClose(PhySocket *sock,void **uptr)
+	{
+		delete (std::string *)*uptr; // delete testMessage if any
 	}
 	}
-}
+
+	inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
+	{
+		phyTestTcpByteCount += len;
+	}
+
+	inline void phyOnTcpWritable(PhySocket *sock,void **uptr)
+	{
+		std::string *testMessage = (std::string *)*uptr;
+		if ((testMessage)&&(testMessage->length() > 0)) {
+			long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),testMessage->length(),true);
+			if (sent > 0)
+				testMessage->erase(0,sent);
+		}
+		if ((!testMessage)||(!testMessage->length())) {
+			testPhyInstance->close(sock,true);
+		}
+	}
+};
 #endif // ZT_TEST_PHY
 #endif // ZT_TEST_PHY
 
 
 static int testPhy()
 static int testPhy()
@@ -717,7 +661,8 @@ static int testPhy()
 	bindaddr.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001);
 	bindaddr.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001);
 
 
 	std::cout << "[phy] Creating phy endpoint..." << std::endl;
 	std::cout << "[phy] Creating phy endpoint..." << std::endl;
-	testPhyInstance = new SimpleFunctionPhy(testPhyOnDatagramFunction,testPhyOnTcpConnectFunction,testPhyOnTcpAcceptFunction,testPhyOnTcpCloseFunction,testPhyOnTcpDataFunction,testPhyOnTcpWritableFunction,false);
+	TestPhyHandlers testPhyHandlers;
+	testPhyInstance = new Phy<TestPhyHandlers *>(&testPhyHandlers,false);
 
 
 	std::cout << "[phy] Binding UDP listen socket to 127.0.0.1/60002... ";
 	std::cout << "[phy] Binding UDP listen socket to 127.0.0.1/60002... ";
 	PhySocket *udpListenSock = testPhyInstance->udpBind((const struct sockaddr *)&bindaddr);
 	PhySocket *udpListenSock = testPhyInstance->udpBind((const struct sockaddr *)&bindaddr);
@@ -740,8 +685,8 @@ static int testPhy()
 	unsigned long phyTestTcpInvalidConnectionsAttempted = 0;
 	unsigned long phyTestTcpInvalidConnectionsAttempted = 0;
 
 
 	std::cout << "[phy] Testing UDP send/receive... "; std::cout.flush();
 	std::cout << "[phy] Testing UDP send/receive... "; std::cout.flush();
-	uint64_t timeoutAt = Utils::now() + ZT_TEST_PHY_TIMEOUT_MS;
-	while ((Utils::now() < timeoutAt)&&(phyTestUdpPacketCount < ZT_TEST_PHY_NUM_UDP_PACKETS)) {
+	uint64_t timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS;
+	while ((OSUtils::now() < timeoutAt)&&(phyTestUdpPacketCount < ZT_TEST_PHY_NUM_UDP_PACKETS)) {
 		if (phyTestUdpPacketsSent < ZT_TEST_PHY_NUM_UDP_PACKETS) {
 		if (phyTestUdpPacketsSent < ZT_TEST_PHY_NUM_UDP_PACKETS) {
 			if (!testPhyInstance->udpSend(udpListenSock,(const struct sockaddr *)&bindaddr,udpTestPayload,sizeof(udpTestPayload))) {
 			if (!testPhyInstance->udpSend(udpListenSock,(const struct sockaddr *)&bindaddr,udpTestPayload,sizeof(udpTestPayload))) {
 				std::cout << "FAILED." << std::endl;
 				std::cout << "FAILED." << std::endl;
@@ -753,8 +698,8 @@ static int testPhy()
 	std::cout << "got " << phyTestUdpPacketCount << " packets, OK" << std::endl;
 	std::cout << "got " << phyTestUdpPacketCount << " packets, OK" << std::endl;
 
 
 	std::cout << "[phy] Testing TCP... "; std::cout.flush();
 	std::cout << "[phy] Testing TCP... "; std::cout.flush();
-	timeoutAt = Utils::now() + ZT_TEST_PHY_TIMEOUT_MS;
-	while ((Utils::now() < timeoutAt)&&(phyTestTcpByteCount < (ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS * ZT_TEST_PHY_TCP_MESSAGE_SIZE))) {
+	timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS;
+	while ((OSUtils::now() < timeoutAt)&&(phyTestTcpByteCount < (ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS * ZT_TEST_PHY_TCP_MESSAGE_SIZE))) {
 		if (phyTestTcpValidConnectionsAttempted < ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS) {
 		if (phyTestTcpValidConnectionsAttempted < ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS) {
 			++phyTestTcpValidConnectionsAttempted;
 			++phyTestTcpValidConnectionsAttempted;
 			bool connected = false;
 			bool connected = false;
@@ -846,14 +791,12 @@ int main(int argc,char **argv)
 	*/
 	*/
 
 
 	std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl;
 	std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl;
-	std::cout << "[info] default home: " << ZT_DEFAULTS.defaultHomePath << std::endl;
 
 
 	srand((unsigned int)time(0));
 	srand((unsigned int)time(0));
 
 
 	r |= testPhy();
 	r |= testPhy();
 	r |= testSqliteNetconfMaster();
 	r |= testSqliteNetconfMaster();
 	r |= testCrypto();
 	r |= testCrypto();
-	r |= testHttp();
 	r |= testPacket();
 	r |= testPacket();
 	r |= testOther();
 	r |= testOther();
 	r |= testIdentity();
 	r |= testIdentity();

+ 73 - 63
service/One.cpp

@@ -29,9 +29,16 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
+#include <string>
+#include <map>
+#include <vector>
+#include <algorithm>
+
 #include "../version.h"
 #include "../version.h"
 #include "../include/ZeroTierOne.h"
 #include "../include/ZeroTierOne.h"
 
 
+#include "../ext/http-parser/http_parser.h"
+
 #include "../node/Constants.hpp"
 #include "../node/Constants.hpp"
 #include "../node/Mutex.hpp"
 #include "../node/Mutex.hpp"
 #include "../node/Node.hpp"
 #include "../node/Node.hpp"
@@ -45,13 +52,6 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-static void SphyOnDatagramFunction(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len);
-static void SphyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success);
-static void SphyOnTcpAcceptFunction(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from);
-static void SphyOnTcpCloseFunction(PhySocket *sock,void **uptr);
-static void SphyOnTcpDataFunction(PhySocket *sock,void **uptr,void *data,unsigned long len);
-static void SphyOnTcpWritableFunction(PhySocket *sock,void **uptr);
-
 static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf);
 static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf);
 static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData);
 static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData);
 static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize);
 static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize);
@@ -59,12 +59,32 @@ static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,
 static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len);
 static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len);
 static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
 static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
 
 
+static int ShttpServerOnMessageBegin(http_parser *parser);
+static int ShttpServerOnUrl(http_parser *parser,const char *ptr,size_t length);
+static int ShttpServerOnStatus(http_parser *parser,const char *ptr,size_t length);
+static int ShttpServerOnHeaderField(http_parser *parser,const char *ptr,size_t length);
+static int ShttpServerOnValue(http_parser *parser,const char *ptr,size_t length);
+static int ShttpServerOnHeadersComplete(http_parser *parser);
+static int ShttpServerOnBody(http_parser *parser,const char *ptr,size_t length);
+static int ShttpServerOnMessageComplete(http_parser *parser);
+
+static int ShttpClientOnMessageBegin(http_parser *parser);
+static int ShttpClientOnUrl(http_parser *parser,const char *ptr,size_t length);
+static int ShttpClientOnStatus(http_parser *parser,const char *ptr,size_t length);
+static int ShttpClientOnHeaderField(http_parser *parser,const char *ptr,size_t length);
+static int ShttpClientOnValue(http_parser *parser,const char *ptr,size_t length);
+static int ShttpClientOnHeadersComplete(http_parser *parser);
+static int ShttpClientOnBody(http_parser *parser,const char *ptr,size_t length);
+static int ShttpClientOnMessageComplete(http_parser *parser);
+
+class OneImpl;
+
 class OneImpl : public One
 class OneImpl : public One
 {
 {
 public:
 public:
 	OneImpl(const char *hp,unsigned int port,NetworkConfigMaster *master,const char *overrideRootTopology) :
 	OneImpl(const char *hp,unsigned int port,NetworkConfigMaster *master,const char *overrideRootTopology) :
 		_homePath((hp) ? hp : "."),
 		_homePath((hp) ? hp : "."),
-		_phy(SphyOnDatagramFunction,SphyOnTcpConnectFunction,SphyOnTcpAcceptFunction,SphyOnTcpCloseFunction,SphyOnTcpDataFunction,SphyOnTcpWritableFunction,true),
+		_phy(this,true),
 		_master(master),
 		_master(master),
 		_overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""),
 		_overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""),
 		_node((Node *)0),
 		_node((Node *)0),
@@ -197,44 +217,42 @@ public:
 
 
 	// Begin private implementation methods
 	// Begin private implementation methods
 
 
-	inline void phyOnDatagramFunction(PhySocket *sock,const struct sockaddr *from,void *data,unsigned long len)
+	inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
 	{
 	{
-		try {
-			ZT1_ResultCode rc = _node->processWirePacket(
-				OSUtils::now(),
-				(const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big
-				0,
-				data,
-				len,
-				const_cast<uint64_t *>(&_nextBackgroundTaskDeadline));
-			if (ZT1_ResultCode_isFatal(rc)) {
-				char tmp[256];
-				Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket(%d)",(int)rc);
-				Mutex::Lock _l(_termReason_m);
-				_termReason = ONE_UNRECOVERABLE_ERROR;
-				_fatalErrorMessage = tmp;
-				this->terminate();
-			}
-		} catch ( ... ) {}
+		ZT1_ResultCode rc = _node->processWirePacket(
+			OSUtils::now(),
+			(const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big
+			0,
+			data,
+			len,
+			const_cast<uint64_t *>(&_nextBackgroundTaskDeadline));
+		if (ZT1_ResultCode_isFatal(rc)) {
+			char tmp[256];
+			Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket(%d)",(int)rc);
+			Mutex::Lock _l(_termReason_m);
+			_termReason = ONE_UNRECOVERABLE_ERROR;
+			_fatalErrorMessage = tmp;
+			this->terminate();
+		}
 	}
 	}
 
 
-	inline void phyOnTcpConnectFunction(PhySocket *sock,bool success)
+	inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
 	{
 	{
 	}
 	}
 
 
-	inline void phyOnTcpAcceptFunction(PhySocket *sockN,const struct sockaddr *from)
+	inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
 	{
 	{
 	}
 	}
 
 
-	inline void phyOnTcpCloseFunction(PhySocket *sock)
+	inline void phyOnTcpClose(PhySocket *sock,void **uptr)
 	{
 	{
 	}
 	}
 
 
-	inline void phyOnTcpDataFunction(PhySocket *sock,void *data,unsigned long len)
+	inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
 	{
 	{
 	}
 	}
 
 
-	inline void phyOnTcpWritableFunction(PhySocket *sock)
+	inline void phyOnTcpWritable(PhySocket *sock,void **uptr)
 	{
 	{
 	}
 	}
 
 
@@ -270,15 +288,9 @@ public:
 
 
 	inline long nodeDataStoreGetFunction(const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize)
 	inline long nodeDataStoreGetFunction(const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize)
 	{
 	{
-		std::string p(_homePath);
-		p.push_back(ZT_PATH_SEPARATOR);
-		char lastc = (char)0;
-		for(const char *n=name;(*n);++n) {
-			if ((*n == '.')&&(lastc == '.'))
-				return -2; // security sanity check-- don't allow ../ stuff even though there's really no way Node will ever do this
-			p.push_back((*n == '/') ? ZT_PATH_SEPARATOR : *n);
-			lastc = *n;
-		}
+		std::string p(_dataStorePrepPath(name));
+		if (!p.length())
+			return -2;
 
 
 		FILE *f = fopen(p.c_str(),"rb");
 		FILE *f = fopen(p.c_str(),"rb");
 		if (!f)
 		if (!f)
@@ -304,15 +316,9 @@ public:
 
 
 	inline int nodeDataStorePutFunction(const char *name,const void *data,unsigned long len,int secure)
 	inline int nodeDataStorePutFunction(const char *name,const void *data,unsigned long len,int secure)
 	{
 	{
-		std::string p(_homePath);
-		p.push_back(ZT_PATH_SEPARATOR);
-		char lastc = (char)0;
-		for(const char *n=name;(*n);++n) {
-			if ((*n == '.')&&(lastc == '.'))
-				return -2; // security sanity check-- don't allow ../ stuff even though there's really no way Node will ever do this
-			p.push_back((*n == '/') ? ZT_PATH_SEPARATOR : *n);
-			lastc = *n;
-		}
+		std::string p(_dataStorePrepPath(name));
+		if (!p.length())
+			return -2;
 
 
 		if (!data) {
 		if (!data) {
 			OSUtils::rm(p.c_str());
 			OSUtils::rm(p.c_str());
@@ -356,8 +362,25 @@ public:
 	}
 	}
 
 
 private:
 private:
+	std::string _dataStorePrepPath(const char *name) const
+	{
+		std::string p(_homePath);
+		p.push_back(ZT_PATH_SEPARATOR);
+		char lastc = (char)0;
+		for(const char *n=name;(*n);++n) {
+			if ((*n == '.')&&(lastc == '.'))
+				return std::string(); // don't allow ../../ stuff as a precaution
+			if (*n == '/') {
+				OSUtils::mkdir(p.c_str());
+				p.push_back(ZT_PATH_SEPARATOR);
+			} else p.push_back(*n);
+			lastc = *n;
+		}
+		return p;
+	}
+
 	const std::string _homePath;
 	const std::string _homePath;
-	SimpleFunctionPhy _phy;
+	Phy<OneImpl *> _phy;
 	NetworkConfigMaster *_master;
 	NetworkConfigMaster *_master;
 	std::string _overrideRootTopology;
 	std::string _overrideRootTopology;
 	Node *_node;
 	Node *_node;
@@ -375,19 +398,6 @@ private:
 	Mutex _run_m;
 	Mutex _run_m;
 };
 };
 
 
-static void SphyOnDatagramFunction(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
-{ reinterpret_cast<OneImpl *>(*uptr)->phyOnDatagramFunction(sock,from,data,len); }
-static void SphyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success)
-{ reinterpret_cast<OneImpl *>(*uptr)->phyOnTcpConnectFunction(sock,success); }
-static void SphyOnTcpAcceptFunction(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
-{ *uptrN = *uptrL; reinterpret_cast<OneImpl *>(*uptrL)->phyOnTcpAcceptFunction(sockN,from); }
-static void SphyOnTcpCloseFunction(PhySocket *sock,void **uptr)
-{ reinterpret_cast<OneImpl *>(*uptr)->phyOnTcpCloseFunction(sock); }
-static void SphyOnTcpDataFunction(PhySocket *sock,void **uptr,void *data,unsigned long len)
-{ reinterpret_cast<OneImpl *>(*uptr)->phyOnTcpDataFunction(sock,data,len); }
-static void SphyOnTcpWritableFunction(PhySocket *sock,void **uptr)
-{ reinterpret_cast<OneImpl *>(*uptr)->phyOnTcpWritableFunction(sock); }
-
 static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf)
 static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf)
 { return reinterpret_cast<OneImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,op,nwconf); }
 { return reinterpret_cast<OneImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,op,nwconf); }
 static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData)
 static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData)

+ 0 - 3
service/One.hpp

@@ -36,9 +36,6 @@ class NetworkConfigMaster;
 
 
 /**
 /**
  * ZeroTier One -- local VPN/NVF service built around ZeroTier core
  * ZeroTier One -- local VPN/NVF service built around ZeroTier core
- *
- * Actual implementation is under the fold, hence the pure virtual
- * interface.
  */
  */
 class One
 class One
 {
 {