From 5572b7ffb6377ec22c6914206c385d18bf08341e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 10 Apr 2015 17:07:06 -0700 Subject: [PATCH] Simplify Phy<> to get rid of more indirections. --- make-freebsd.mk | 2 +- make-linux.mk | 2 +- make-mac.mk | 2 +- osdep/Phy.hpp | 84 +++++++----------------- selftest.cpp | 167 ++++++++++++++++-------------------------------- service/One.cpp | 136 +++++++++++++++++++++------------------ service/One.hpp | 3 - 7 files changed, 153 insertions(+), 243 deletions(-) diff --git a/make-freebsd.mk b/make-freebsd.mk index bfa2c13c5..4d73a4eb1 100644 --- a/make-freebsd.mk +++ b/make-freebsd.mk @@ -84,7 +84,7 @@ testnet: $(TESTNET_OBJS) $(OBJS) testnet.o # ./buildinstaller.sh 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 make -j 4 ZT_DEBUG=1 diff --git a/make-linux.mk b/make-linux.mk index d4cb9d89b..d06f6cf70 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -89,7 +89,7 @@ installer: one FORCE ./buildinstaller.sh 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 make -j 4 ZT_DEBUG=1 diff --git a/make-mac.mk b/make-mac.mk index 22b6a8234..840a47b33 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -77,7 +77,7 @@ mac-ui: FORCE $(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app" 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 official: FORCE diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 96a946d15..775bc176b 100644 --- a/osdep/Phy.hpp +++ b/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 * 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 * 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 * 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 class Phy { 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 { @@ -164,27 +153,11 @@ private: 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(&_writefds); @@ -526,7 +499,7 @@ public: if ((callConnectHandler)&&(connected)) { try { - _tcpConnectHandler((PhySocket *)&sws,&(sws.uptr),true); + _handler->phyOnTcpConnect((PhySocket *)&sws,&(sws.uptr),true); } catch ( ... ) {} } @@ -664,7 +637,7 @@ public: FD_CLR(s->sock,&_exceptfds); #endif try { - _tcpConnectHandler((PhySocket *)&(*s),&(s->uptr),true); + _handler->phyOnTcpConnect((PhySocket *)&(*s),&(s->uptr),true); } catch ( ... ) {} } } @@ -678,13 +651,13 @@ public: this->close((PhySocket *)&(*s),true); } else { try { - _tcpDataHandler((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); + _handler->phyOnTcpData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); } catch ( ... ) {} } } if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) { try { - _tcpWritableHandler((PhySocket *)&(*s),&(s->uptr)); + _handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr)); } catch ( ... ) {} } break; @@ -715,7 +688,7 @@ public: sws.uptr = (void *)0; memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); 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 ( ... ) {} } } @@ -730,7 +703,7 @@ public: long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen); if (n > 0) { 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 ( ... ) {} } else if (n < 0) break; @@ -767,7 +740,7 @@ public: case ZT_PHY_SOCKET_TCP_OUT_PENDING: if (callHandlers) { try { - _tcpConnectHandler(sock,&(sws.uptr),false); + _handler->phyOnTcpConnect(sock,&(sws.uptr),false); } catch ( ... ) {} } break; @@ -775,7 +748,7 @@ public: case ZT_PHY_SOCKET_TCP_IN: if (callHandlers) { try { - _tcpCloseHandler(sock,&(sws.uptr)); + _handler->phyOnTcpClose(sock,&(sws.uptr)); } catch ( ... ) {} } 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 SimpleFunctionPhy; - } // namespace ZeroTier #endif diff --git a/selftest.cpp b/selftest.cpp index 3e56f585a..465e0088c 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -46,17 +46,15 @@ #include "node/Salsa20.hpp" #include "node/MAC.hpp" #include "node/Peer.hpp" -#include "node/NodeConfig.hpp" #include "node/Dictionary.hpp" -#include "node/EthernetTap.hpp" #include "node/SHA512.hpp" #include "node/C25519.hpp" #include "node/Poly1305.hpp" #include "node/CertificateOfMembership.hpp" -#include "node/HttpClient.hpp" #include "node/Defaults.hpp" #include "node/Node.hpp" +#include "osdep/OSUtils.hpp" #ifdef ZT_TEST_PHY #include "osdep/Phy.hpp" #endif @@ -147,69 +145,6 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = 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() { unsigned char buf1[16384]; @@ -261,12 +196,12 @@ static int testCrypto() bb[i] = (unsigned char)i; Salsa20 s20(s20TV0Key,256,s20TV0Iv,12); double bytes = 0.0; - uint64_t start = Utils::now(); + uint64_t start = OSUtils::now(); for(unsigned int i=0;i<200;++i) { s20.encrypt(bb,bb,1234567); bytes += 1234567.0; } - uint64_t end = Utils::now(); + uint64_t end = OSUtils::now(); SHA512::hash(buf1,bb,1234567); std::cout << ((bytes / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16) << ')' << std::endl; ::free((void *)bb); @@ -415,9 +350,9 @@ static int testIdentity() for(unsigned int k=0;k<4;++k) { std::cout << "[identity] Generate identity... "; std::cout.flush(); - uint64_t genstart = Utils::now(); + uint64_t genstart = OSUtils::now(); 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 << "[identity] Locally validate identity: "; if (id.locallyValidate()) { @@ -658,45 +593,54 @@ static unsigned long phyTestTcpByteCount = 0; static unsigned long phyTestTcpConnectSuccessCount = 0; static unsigned long phyTestTcpConnectFailCount = 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) +struct TestPhyHandlers; +static Phy *testPhyInstance = (Phy *)0; +struct TestPhyHandlers { - ++phyTestUdpPacketCount; -} -static void testPhyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success) -{ - 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; + } } - if ((!testMessage)||(!testMessage->length())) { - testPhyInstance->close(sock,true); + + 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); } -} + + 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 static int testPhy() @@ -717,7 +661,8 @@ static int testPhy() bindaddr.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); std::cout << "[phy] Creating phy endpoint..." << std::endl; - testPhyInstance = new SimpleFunctionPhy(testPhyOnDatagramFunction,testPhyOnTcpConnectFunction,testPhyOnTcpAcceptFunction,testPhyOnTcpCloseFunction,testPhyOnTcpDataFunction,testPhyOnTcpWritableFunction,false); + TestPhyHandlers testPhyHandlers; + testPhyInstance = new Phy(&testPhyHandlers,false); std::cout << "[phy] Binding UDP listen socket to 127.0.0.1/60002... "; PhySocket *udpListenSock = testPhyInstance->udpBind((const struct sockaddr *)&bindaddr); @@ -740,8 +685,8 @@ static int testPhy() unsigned long phyTestTcpInvalidConnectionsAttempted = 0; 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 (!testPhyInstance->udpSend(udpListenSock,(const struct sockaddr *)&bindaddr,udpTestPayload,sizeof(udpTestPayload))) { std::cout << "FAILED." << std::endl; @@ -753,8 +698,8 @@ static int testPhy() std::cout << "got " << phyTestUdpPacketCount << " packets, OK" << std::endl; 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) { ++phyTestTcpValidConnectionsAttempted; 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] default home: " << ZT_DEFAULTS.defaultHomePath << std::endl; srand((unsigned int)time(0)); r |= testPhy(); r |= testSqliteNetconfMaster(); r |= testCrypto(); - r |= testHttp(); r |= testPacket(); r |= testOther(); r |= testIdentity(); diff --git a/service/One.cpp b/service/One.cpp index 20be70061..c657bd646 100644 --- a/service/One.cpp +++ b/service/One.cpp @@ -29,9 +29,16 @@ #include #include +#include +#include +#include +#include + #include "../version.h" #include "../include/ZeroTierOne.h" +#include "../ext/http-parser/http_parser.h" + #include "../node/Constants.hpp" #include "../node/Mutex.hpp" #include "../node/Node.hpp" @@ -45,13 +52,6 @@ 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 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); @@ -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 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 { public: OneImpl(const char *hp,unsigned int port,NetworkConfigMaster *master,const char *overrideRootTopology) : _homePath((hp) ? hp : "."), - _phy(SphyOnDatagramFunction,SphyOnTcpConnectFunction,SphyOnTcpAcceptFunction,SphyOnTcpCloseFunction,SphyOnTcpDataFunction,SphyOnTcpWritableFunction,true), + _phy(this,true), _master(master), _overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""), _node((Node *)0), @@ -197,44 +217,42 @@ public: // 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(&_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(&_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) { - 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"); if (!f) @@ -304,15 +316,9 @@ public: 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) { OSUtils::rm(p.c_str()); @@ -356,8 +362,25 @@ public: } 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; - SimpleFunctionPhy _phy; + Phy _phy; NetworkConfigMaster *_master; std::string _overrideRootTopology; Node *_node; @@ -375,19 +398,6 @@ private: Mutex _run_m; }; -static void SphyOnDatagramFunction(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) -{ reinterpret_cast(*uptr)->phyOnDatagramFunction(sock,from,data,len); } -static void SphyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success) -{ reinterpret_cast(*uptr)->phyOnTcpConnectFunction(sock,success); } -static void SphyOnTcpAcceptFunction(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) -{ *uptrN = *uptrL; reinterpret_cast(*uptrL)->phyOnTcpAcceptFunction(sockN,from); } -static void SphyOnTcpCloseFunction(PhySocket *sock,void **uptr) -{ reinterpret_cast(*uptr)->phyOnTcpCloseFunction(sock); } -static void SphyOnTcpDataFunction(PhySocket *sock,void **uptr,void *data,unsigned long len) -{ reinterpret_cast(*uptr)->phyOnTcpDataFunction(sock,data,len); } -static void SphyOnTcpWritableFunction(PhySocket *sock,void **uptr) -{ reinterpret_cast(*uptr)->phyOnTcpWritableFunction(sock); } - static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf) { return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,op,nwconf); } static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData) diff --git a/service/One.hpp b/service/One.hpp index 1a33dc72e..a1e8d2ad3 100644 --- a/service/One.hpp +++ b/service/One.hpp @@ -36,9 +36,6 @@ class NetworkConfigMaster; /** * ZeroTier One -- local VPN/NVF service built around ZeroTier core - * - * Actual implementation is under the fold, hence the pure virtual - * interface. */ class One {