Simplify Phy<> to get rid of more indirections.

This commit is contained in:
Adam Ierymenko 2015-04-10 17:07:06 -07:00
parent 7576911951
commit 5572b7ffb6
7 changed files with 153 additions and 243 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 * This class is templated on a pointer to a handler class which must
* paramters: * implement the following functions:
* *
* ON_DATAGRAM_FUNCTION(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) * phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
* ON_TCP_CONNECT_FUNCTION(PhySocket *sock,void **uptr,bool success) * phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
* ON_TCP_ACCEPT_FUNCTION(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) * phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
* ON_TCP_CLOSE_FUNCTION(PhySocket *sock,void **uptr) * phyOnTcpClose(PhySocket *sock,void **uptr)
* ON_TCP_DATA_FUNCTION(PhySocket *sock,void **uptr,void *data,unsigned long len) * phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
* ON_TCP_WRITABLE_FUNCTION(PhySocket *sock,void **uptr) * 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 < template <typename HANDLER_PTR_TYPE>
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 >
class Phy class Phy
{ {
private: private:
ON_DATAGRAM_FUNCTION _datagramHandler; HANDLER_PTR_TYPE _handler;
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;
enum PhySocketType enum PhySocketType
{ {
@ -164,27 +153,11 @@ private:
public: public:
/** /**
* @param datagramHandler Function or function object to handle UDP or RAW datagrams * @param handler Pointer of type HANDLER_PTR_TYPE to handler
* @param tcpConnectHandler Handler for outgoing TCP connection attempts (success or failure) * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets
* @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
*/ */
Phy( Phy(HANDLER_PTR_TYPE handler,bool noDelay) :
ON_DATAGRAM_FUNCTION datagramHandler, _handler(handler)
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)
{ {
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

View file

@ -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; struct TestPhyHandlers;
static void testPhyOnDatagramFunction(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) static Phy<TestPhyHandlers *> *testPhyInstance = (Phy<TestPhyHandlers *> *)0;
struct TestPhyHandlers
{ {
++phyTestUdpPacketCount; inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
} {
static void testPhyOnTcpConnectFunction(PhySocket *sock,void **uptr,bool success) ++phyTestUdpPacketCount;
{
if (success) {
++phyTestTcpConnectSuccessCount;
} else {
++phyTestTcpConnectFailCount;
} }
}
static void testPhyOnTcpAcceptFunction(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
{ {
++phyTestTcpAcceptCount; if (success) {
*uptrN = new std::string(ZT_TEST_PHY_TCP_MESSAGE_SIZE,(char)0xff); ++phyTestTcpConnectSuccessCount;
testPhyInstance->tcpSetNotifyWritable(sockN,true); } else {
} ++phyTestTcpConnectFailCount;
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);
} }
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 #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; uint64_t timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS;
while ((Utils::now() < timeoutAt)&&(phyTestUdpPacketCount < ZT_TEST_PHY_NUM_UDP_PACKETS)) { 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; timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS;
while ((Utils::now() < timeoutAt)&&(phyTestTcpByteCount < (ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS * ZT_TEST_PHY_TCP_MESSAGE_SIZE))) { 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();

View file

@ -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(
ZT1_ResultCode rc = _node->processWirePacket( OSUtils::now(),
OSUtils::now(), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big
(const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big 0,
0, data,
data, len,
len, const_cast<uint64_t *>(&_nextBackgroundTaskDeadline));
const_cast<uint64_t *>(&_nextBackgroundTaskDeadline)); if (ZT1_ResultCode_isFatal(rc)) {
if (ZT1_ResultCode_isFatal(rc)) { char tmp[256];
char tmp[256]; Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket(%d)",(int)rc);
Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket(%d)",(int)rc); Mutex::Lock _l(_termReason_m);
Mutex::Lock _l(_termReason_m); _termReason = ONE_UNRECOVERABLE_ERROR;
_termReason = ONE_UNRECOVERABLE_ERROR; _fatalErrorMessage = tmp;
_fatalErrorMessage = tmp; this->terminate();
this->terminate(); }
}
} catch ( ... ) {}
} }
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); std::string p(_dataStorePrepPath(name));
p.push_back(ZT_PATH_SEPARATOR); if (!p.length())
char lastc = (char)0; return -2;
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;
}
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); std::string p(_dataStorePrepPath(name));
p.push_back(ZT_PATH_SEPARATOR); if (!p.length())
char lastc = (char)0; return -2;
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;
}
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)

View file

@ -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
{ {