From a3876353ca1cb07213c5e1c5208b531caeda5523 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 13:25:38 -0700 Subject: Abiltiy to post a test via the controller web API, and parsing of CIRCUIT_TEST_REPORT messages. --- controller/SqliteNetworkController.cpp | 50 ++++++++++++++++++++++++++++++++++ controller/SqliteNetworkController.hpp | 8 ++++++ 2 files changed, 58 insertions(+) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 334ccc75..861cdbcf 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -505,6 +505,52 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( } return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType); + } else if ((path.size() == 3)&&(path[2] == "test")) { + ZT_CircuitTest *test = (ZT_CircuitTest *)malloc(sizeof(ZT_CircuitTest)); + memset(test,0,sizeof(ZT_CircuitTest)); + + Utils::getSecureRandom(&(test->testId),sizeof(test->testId)); + test->credentialNetworkId = nwid; + test->ptr = (void *)this; + + json_value *j = json_parse(body.c_str(),body.length()); + if (j) { + if (j->type == json_object) { + for(unsigned int k=0;ku.object.length;++k) { + + if (!strcmp(j->u.object.values[k].name,"hops")) { + if (j->u.object.values[k].value->type == json_array) { + for(unsigned int kk=0;kku.object.values[k].value->u.array.length;++kk) { + json_value *hop = j->u.object.values[k].value->u.array.values[kk]; + if (hop->type == json_array) { + for(unsigned int kkk=0;kkku.array.length;++kkk) { + if (hop->u.array.values[kkk].type == json_string) { + test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(hop->u.array.values[kkk].u.string.ptr) & 0xffffffffffULL; + } + } + ++test->hopCount; + } + } + } + } else if (!strcmp(j->u.object.values[k].name,"reportAtEveryHop")) { + if (j->u.object.values[k].value->type == json_boolean) + test->reportAtEveryHop = (j->u.object.values[k].value->u.boolean == 0) ? 0 : 1; + } + + } + } + json_value_free(j); + } + + if (!test->hopCount) { + ::free((void *)test); + return 500; + } + + test->timestamp = OSUtils::now(); + _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback)); + + return 200; } // else 404 } else { @@ -1819,4 +1865,8 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c return NetworkController::NETCONF_QUERY_OK; } +static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) +{ +} + } // namespace ZeroTier diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 68529e39..7a01487c 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -43,6 +43,9 @@ // Number of in-memory last log entries to maintain per user #define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32 +// How long do circuit tests "live"? This is just to prevent buildup in memory. +#define ZT_SQLITENETWORKCONTROLLER_CIRCUIT_TEST_TIMEOUT 300000 + namespace ZeroTier { class Node; @@ -106,6 +109,8 @@ private: const Dictionary &metaData, Dictionary &netconf); + static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); + Node *_node; std::string _dbPath; std::string _circuitTestPath; @@ -140,6 +145,9 @@ private: // Last log entries by address and network ID pair std::map< std::pair,_LLEntry > _lastLog; + // Circuit tests outstanding + std::map< uint64_t,ZT_CircuitTest * > _circuitTests; + sqlite3 *_db; sqlite3_stmt *_sGetNetworkById; -- cgit v1.2.3 From 59da8b2a4b3e36605886944f3fa111870bbb8a2c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 15:44:06 -0700 Subject: Logging of circuit test results to disk. --- controller/SqliteNetworkController.cpp | 72 ++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 861cdbcf..13a0cadd 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -524,8 +524,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( json_value *hop = j->u.object.values[k].value->u.array.values[kk]; if (hop->type == json_array) { for(unsigned int kkk=0;kkku.array.length;++kkk) { - if (hop->u.array.values[kkk].type == json_string) { - test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(hop->u.array.values[kkk].u.string.ptr) & 0xffffffffffULL; + if (hop->u.array.values[kkk]->type == json_string) { + test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(hop->u.array.values[kkk]->u.string.ptr) & 0xffffffffffULL; } } ++test->hopCount; @@ -548,6 +548,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( } test->timestamp = OSUtils::now(); + _circuitTests[test->testId] = test; _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback)); return 200; @@ -1865,8 +1866,73 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c return NetworkController::NETCONF_QUERY_OK; } -static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) +void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) { + static Mutex circuitTestWriteLock; + + const uint64_t now = OSUtils::now(); + + SqliteNetworkController *const c = reinterpret_cast(test->ptr); + char tmp[128]; + + std::string reportSavePath(c->_circuitTestPath); + OSUtils::mkdir(reportSavePath); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx",test->credentialNetworkId); + reportSavePath.append(tmp); + OSUtils::mkdir(reportSavePath); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.16llx",test->timestamp,test->testId); + reportSavePath.append(tmp); + OSUtils::mkdir(reportSavePath); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.10llx",report->address); + reportSavePath.append(tmp); + + { + Mutex::Lock _l(circuitTestWriteLock); + FILE *f = fopen(reportSavePath.c_str(),"a"); + if (!f) + return; + fseek(f,0,SEEK_END); + fprintf(f,"%s{\n" + "\t\"address\": \"%.10llx\","ZT_EOL_S + "\t\"testId\": \"%.16llx\","ZT_EOL_S + "\t\"timestamp\": %llu,"ZT_EOL_S + "\t\"receivedTimestamp\": %llu,"ZT_EOL_S + "\t\"remoteTimestamp\": %llu,"ZT_EOL_S + "\t\"sourcePacketId\": \"%.16llx\","ZT_EOL_S + "\t\"flags\": %llu,"ZT_EOL_S + "\t\"sourcePacketHopCount\": %u,"ZT_EOL_S + "\t\"errorCode\": %u,"ZT_EOL_S + "\t\"vendor\": %d,"ZT_EOL_S + "\t\"protocolVersion\": %u,"ZT_EOL_S + "\t\"majorVersion\": %u,"ZT_EOL_S + "\t\"minorVersion\": %u,"ZT_EOL_S + "\t\"revision\": %u,"ZT_EOL_S + "\t\"platform\": %d,"ZT_EOL_S + "\t\"architecture\": %d,"ZT_EOL_S + "\t\"receivedOnLocalAddress\": \"%s\","ZT_EOL_S + "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S + "}", + ((ftell(f) > 0) ? ",\n" : ""), + report->address, + test->testId, + report->timestamp, + now, + report->remoteTimestamp, + report->sourcePacketId, + report->flags, + report->sourcePacketHopCount, + report->errorCode, + (int)report->vendor, + report->protocolVersion, + report->majorVersion, + report->minorVersion, + report->revision, + (int)report->platform, + (int)report->architecture, + reinterpret_cast(&(report->receivedOnLocalAddress))->toString().c_str(), + reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str()); + fclose(f); + } } } // namespace ZeroTier -- cgit v1.2.3 From 6b5bb0b27874b3005964deaca347289e583899f8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 12:22:13 -0700 Subject: Eliminate format string warnings. --- controller/SqliteNetworkController.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 13a0cadd..40fafd79 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1913,13 +1913,13 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - report->address, - test->testId, - report->timestamp, - now, - report->remoteTimestamp, - report->sourcePacketId, - report->flags, + (unsigned long long)report->address, + (unsigned long long)test->testId, + (unsigned long long)report->timestamp, + (unsigned long long)now, + (unsigned long long)report->remoteTimestamp, + (unsigned long long)report->sourcePacketId, + (unsigned long long)report->flags, report->sourcePacketHopCount, report->errorCode, (int)report->vendor, -- cgit v1.2.3 From a95fa379cca0ddbce98d476b143c3606f3ae7bce Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 14:51:38 -0700 Subject: Circuit tests basically work but need some tweaks, and fix some issues found with valgrind. --- controller/SqliteNetworkController.cpp | 2 - controller/SqliteNetworkController.hpp | 2 - examples/api/circuit-test-pingpong.json | 13 ++++++ examples/docker/main.sh | 2 +- node/InetAddress.hpp | 72 ++++++++++++++++++++------------- node/Node.cpp | 2 +- 6 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 examples/api/circuit-test-pingpong.json (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 40fafd79..d87e5624 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -258,8 +258,6 @@ SqliteNetworkController::~SqliteNetworkController() sqlite3_finalize(_sCreateMember); sqlite3_finalize(_sGetNodeIdentity); sqlite3_finalize(_sCreateOrReplaceNode); - sqlite3_finalize(_sUpdateNode); - sqlite3_finalize(_sUpdateNode2); sqlite3_finalize(_sGetEtherTypesFromRuleTable); sqlite3_finalize(_sGetActiveBridges); sqlite3_finalize(_sGetIpAssignmentsForNode); diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 7a01487c..a3d5dfc7 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -155,8 +155,6 @@ private: sqlite3_stmt *_sCreateMember; sqlite3_stmt *_sGetNodeIdentity; sqlite3_stmt *_sCreateOrReplaceNode; - sqlite3_stmt *_sUpdateNode; - sqlite3_stmt *_sUpdateNode2; sqlite3_stmt *_sGetEtherTypesFromRuleTable; sqlite3_stmt *_sGetActiveBridges; sqlite3_stmt *_sGetIpAssignmentsForNode; diff --git a/examples/api/circuit-test-pingpong.json b/examples/api/circuit-test-pingpong.json new file mode 100644 index 00000000..8fcc5d94 --- /dev/null +++ b/examples/api/circuit-test-pingpong.json @@ -0,0 +1,13 @@ +{ + "hops": [ + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ] + ], + "reportAtEveryHop": true +} diff --git a/examples/docker/main.sh b/examples/docker/main.sh index e9febb13..53fb6540 100644 --- a/examples/docker/main.sh +++ b/examples/docker/main.sh @@ -20,6 +20,6 @@ else fi rm -f /var/lib/zerotier-one/identity.* -echo "$ZEROTIER_IDENTITY_SECRET" >identity.secret +echo "$ZEROTIER_IDENTITY_SECRET" >/var/lib/zerotier-one/identity.secret /var/lib/zerotier-one/zerotier-one diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 6970e92d..50db272a 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -100,74 +100,88 @@ struct InetAddress : public sockaddr_storage inline InetAddress &operator=(const InetAddress &a) throw() { - memcpy(this,&a,sizeof(InetAddress)); + if (&a != this) + memcpy(this,&a,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const InetAddress *a) throw() { - memcpy(this,a,sizeof(InetAddress)); + if (a != this) + memcpy(this,a,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_storage &ss) throw() { - memcpy(this,&ss,sizeof(InetAddress)); + if (reinterpret_cast(&ss) != this) + memcpy(this,&ss,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_storage *ss) throw() { - memcpy(this,ss,sizeof(InetAddress)); + if (reinterpret_cast(ss) != this) + memcpy(this,ss,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_in &sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in)); + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,&sa,sizeof(struct sockaddr_in)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in *sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in)); + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,sa,sizeof(struct sockaddr_in)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in6 &sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in6)); + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,&sa,sizeof(struct sockaddr_in6)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in6 *sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in6)); + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,sa,sizeof(struct sockaddr_in6)); + } return *this; } inline InetAddress &operator=(const struct sockaddr &sa) throw() { - memset(this,0,sizeof(InetAddress)); - switch(sa.sa_family) { - case AF_INET: - memcpy(this,&sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - break; + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + switch(sa.sa_family) { + case AF_INET: + memcpy(this,&sa,sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this,&sa,sizeof(struct sockaddr_in6)); + break; + } } return *this; } @@ -175,14 +189,16 @@ struct InetAddress : public sockaddr_storage inline InetAddress &operator=(const struct sockaddr *sa) throw() { - memset(this,0,sizeof(InetAddress)); - switch(sa->sa_family) { - case AF_INET: - memcpy(this,sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,sa,sizeof(struct sockaddr_in6)); - break; + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + switch(sa->sa_family) { + case AF_INET: + memcpy(this,sa,sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this,sa,sizeof(struct sockaddr_in6)); + break; + } } return *this; } diff --git a/node/Node.cpp b/node/Node.cpp index 84452146..1eb21914 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -491,7 +491,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true,test->credentialNetworkId); + RR->sw->send(outp,true,0); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet -- cgit v1.2.3 From aec13b50fdbb210e25c9bcfcb8f902da842ac65f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 15:05:26 -0700 Subject: Be a bit more verbose in circuit test reports to more clearly track current and upstream hop in graph traversal history. --- controller/SqliteNetworkController.cpp | 8 +++++--- include/ZeroTierOne.h | 9 +++++++-- node/IncomingPacket.cpp | 12 +++++++----- node/Packet.hpp | 1 + 4 files changed, 20 insertions(+), 10 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index d87e5624..08bd3a15 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1881,7 +1881,7 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.16llx",test->timestamp,test->testId); reportSavePath.append(tmp); OSUtils::mkdir(reportSavePath); - Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.10llx",report->address); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.10llx_%.10llx",report->upstream,report->current); reportSavePath.append(tmp); { @@ -1891,7 +1891,8 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest return; fseek(f,0,SEEK_END); fprintf(f,"%s{\n" - "\t\"address\": \"%.10llx\","ZT_EOL_S + "\t\"current\": \"%.10llx\","ZT_EOL_S + "\t\"upstream\": \"%.10llx\","ZT_EOL_S "\t\"testId\": \"%.16llx\","ZT_EOL_S "\t\"timestamp\": %llu,"ZT_EOL_S "\t\"receivedTimestamp\": %llu,"ZT_EOL_S @@ -1911,7 +1912,8 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - (unsigned long long)report->address, + (unsigned long long)report->current, + (unsigned long long)report->upstream, (unsigned long long)test->testId, (unsigned long long)report->timestamp, (unsigned long long)now, diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 175cedc5..80091f62 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -733,9 +733,14 @@ typedef struct { */ typedef struct { /** - * Sender of report + * Sender of report (current hop) */ - uint64_t address; + uint64_t current; + + /** + * Previous hop + */ + uint64_t upstream; /** * 64-bit test ID diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5d31a5d4..443ffeeb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -993,6 +993,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint16_t)0); // error code, currently unused outp.append((uint64_t)0); // flags, currently unused outp.append((uint64_t)packetId()); + peer->address().appendTo(outp); outp.append((uint8_t)hops()); _localAddress.serialize(outp); _remoteAddress.serialize(outp); @@ -1039,13 +1040,14 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S ZT_CircuitTestReport report; memset(&report,0,sizeof(report)); - report.address = peer->address().toInt(); + report.current = peer->address().toInt(); + report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16); report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); - report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 52]; + report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 report.errorCode = at(ZT_PACKET_IDX_PAYLOAD + 34); report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]); report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25]; @@ -1055,10 +1057,10 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S report.platform = (enum ZT_Platform)at(ZT_PACKET_IDX_PAYLOAD + 30); report.architecture = (enum ZT_Architecture)at(ZT_PACKET_IDX_PAYLOAD + 32); - const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53); - const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen); + const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58); + const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen); - unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; + unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; nhptr += at(nhptr) + 2; // add "additional field" length, which right now will be zero report.nextHopCount = (*this)[nhptr++]; diff --git a/node/Packet.hpp b/node/Packet.hpp index 5c7253bf..6c178e66 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1031,6 +1031,7 @@ public: * <[2] 16-bit error code (set to 0, currently unused)> * <[8] 64-bit report flags (set to 0, currently unused)> * <[8] 64-bit source packet ID> + * <[5] upstream ZeroTier address from which test was received> * <[1] 8-bit source packet hop count (ZeroTier hop count)> * <[...] local wire address on which packet was received> * <[...] remote wire address from which packet was received> -- cgit v1.2.3 From 7d01fab1326e3156b1327ead708457e5fefe8cdc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 15:18:01 -0700 Subject: Reorg fields to be in same order as FS scheme. --- controller/SqliteNetworkController.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 08bd3a15..be6145cf 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1891,10 +1891,10 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest return; fseek(f,0,SEEK_END); fprintf(f,"%s{\n" - "\t\"current\": \"%.10llx\","ZT_EOL_S - "\t\"upstream\": \"%.10llx\","ZT_EOL_S - "\t\"testId\": \"%.16llx\","ZT_EOL_S "\t\"timestamp\": %llu,"ZT_EOL_S + "\t\"testId\": \"%.16llx\","ZT_EOL_S + "\t\"upstream\": \"%.10llx\","ZT_EOL_S + "\t\"current\": \"%.10llx\","ZT_EOL_S "\t\"receivedTimestamp\": %llu,"ZT_EOL_S "\t\"remoteTimestamp\": %llu,"ZT_EOL_S "\t\"sourcePacketId\": \"%.16llx\","ZT_EOL_S @@ -1912,10 +1912,10 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - (unsigned long long)report->current, - (unsigned long long)report->upstream, - (unsigned long long)test->testId, (unsigned long long)report->timestamp, + (unsigned long long)test->testId, + (unsigned long long)report->upstream, + (unsigned long long)report->current, (unsigned long long)now, (unsigned long long)report->remoteTimestamp, (unsigned long long)report->sourcePacketId, -- cgit v1.2.3 From eff1fe3c61aee8029337971545da5251f470ac53 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 16:22:34 -0700 Subject: Create files for each hop (more convenient) and fix a packet parse bug. --- controller/SqliteNetworkController.cpp | 2 +- node/IncomingPacket.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index be6145cf..52b47665 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1881,7 +1881,7 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.16llx",test->timestamp,test->testId); reportSavePath.append(tmp); OSUtils::mkdir(reportSavePath); - Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.10llx_%.10llx",report->upstream,report->current); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.10llx_%.10llx",now,report->upstream,report->current); reportSavePath.append(tmp); { diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 443ffeeb..9f53a1c5 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1021,9 +1021,11 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); for(unsigned int h=0;hsw->send(outp,true,originatorCredentialNetworkId); + if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid + outp.newInitializationVector(); + outp.setDestination(nextHop[h]); + RR->sw->send(outp,true,originatorCredentialNetworkId); + } } } @@ -1067,7 +1069,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH; for(unsigned int h=0;h(nhptr); nhptr += 8; + report.nextHops[h].address = Address(field(nhptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); nhptr += ZT_ADDRESS_LENGTH; nhptr += reinterpret_cast(&(report.nextHops[h].physicalAddress))->deserialize(*this,nhptr); } -- cgit v1.2.3 From 7903f24a8fbe8e45a4cd242efdf1ca64c0356d43 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 3 Nov 2015 15:52:10 -0800 Subject: Create periodic backup copies of controller.db in network controller from the main process itself to facilitate easier and safer backups of controller.db. --- controller/SqliteNetworkController.cpp | 55 ++++++++++++++++++++++++++++++++++ controller/SqliteNetworkController.hpp | 7 +++++ osdep/OSUtils.hpp | 1 - 3 files changed, 62 insertions(+), 1 deletion(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 52b47665..f35bcc15 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -71,6 +71,9 @@ // than this (ms). #define ZT_NETCONF_MIN_REQUEST_PERIOD 1000 +// Delay between backups in milliseconds +#define ZT_NETCONF_BACKUP_PERIOD 60000 + namespace ZeroTier { namespace { @@ -122,6 +125,7 @@ struct NetworkRecord { SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath) : _node(node), + _backupThreadRun(true), _dbPath(dbPath), _circuitTestPath(circuitTestPath), _db((sqlite3 *)0) @@ -247,10 +251,15 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c throw std::runtime_error("SqliteNetworkController unable to read instanceId (it's NULL)"); _instanceId = iid; } + + _backupThread = Thread::start(this); } SqliteNetworkController::~SqliteNetworkController() { + _backupThreadRun = false; + Thread::join(_backupThread); + Mutex::Lock _l(_lock); if (_db) { sqlite3_finalize(_sGetNetworkById); @@ -991,6 +1000,52 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE( return 404; } +void SqliteNetworkController::threadMain() + throw() +{ + uint64_t lastBackupTime = 0; + while (_backupThreadRun) { + if ((OSUtils::now() - lastBackupTime) >= ZT_NETCONF_BACKUP_PERIOD) { + lastBackupTime = OSUtils::now(); + + char backupPath[4096],backupPath2[4096]; + Utils::snprintf(backupPath,sizeof(backupPath),"%s.backupInProgress",_dbPath.c_str()); + Utils::snprintf(backupPath2,sizeof(backupPath),"%s.backup",_dbPath.c_str()); + OSUtils::rm(backupPath); // delete any unfinished backups + + sqlite3 *bakdb = (sqlite3 *)0; + sqlite3_backup *bak = (sqlite3_backup *)0; + if (sqlite3_open_v2(backupPath,&bakdb,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK) { + fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_open_v2()"ZT_EOL_S); + continue; + } + bak = sqlite3_backup_init(bakdb,"main",_db,"main"); + if (!bak) { + sqlite3_close(bakdb); + OSUtils::rm(backupPath); // delete any unfinished backups + fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_backup_init()"ZT_EOL_S); + continue; + } + + int rc = SQLITE_OK; + for(;;) { + rc = sqlite3_backup_step(bak,1); + if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY)) + Thread::sleep(100); + else break; + } + + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + + OSUtils::rm(backupPath2); + ::rename(backupPath,backupPath2); + } + + Thread::sleep(500); + } +} + unsigned int SqliteNetworkController::_doCPGet( const std::vector &path, const std::map &urlArgs, diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index a3d5dfc7..0e2bb63e 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -39,6 +39,7 @@ #include "../node/Constants.hpp" #include "../node/NetworkController.hpp" #include "../node/Mutex.hpp" +#include "../osdep/Thread.hpp" // Number of in-memory last log entries to maintain per user #define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32 @@ -86,6 +87,10 @@ public: std::string &responseBody, std::string &responseContentType); + // threadMain() for backup thread -- do not call directly + void threadMain() + throw(); + private: enum IpAssignmentType { // IP assignment is a static IP address @@ -112,6 +117,8 @@ private: static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); Node *_node; + Thread _backupThread; + volatile bool _backupThreadRun; std::string _dbPath; std::string _circuitTestPath; std::string _instanceId; diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 5de35eba..43fd2813 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -95,7 +95,6 @@ public: static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); } static inline bool mkdir(const char *path) - throw() { #ifdef __WINDOWS__ if (::PathIsDirectoryA(path)) -- cgit v1.2.3 From f7a407ffa003edc1e9744616c80cca13a507d15e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 3 Nov 2015 15:56:24 -0800 Subject: Tweak timings and use lock in backup to make it a bit faster and still permit main thread to work. --- controller/SqliteNetworkController.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index f35bcc15..60e5bf54 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1029,9 +1029,11 @@ void SqliteNetworkController::threadMain() int rc = SQLITE_OK; for(;;) { - rc = sqlite3_backup_step(bak,1); + _lock.lock(); + rc = sqlite3_backup_step(bak,64); + _lock.unlock(); if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY)) - Thread::sleep(100); + Thread::sleep(50); else break; } @@ -1041,8 +1043,7 @@ void SqliteNetworkController::threadMain() OSUtils::rm(backupPath2); ::rename(backupPath,backupPath2); } - - Thread::sleep(500); + Thread::sleep(250); } } -- cgit v1.2.3 From 523412edfbd60c8b064f2392c413d2916e2aa9b9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 3 Nov 2015 16:03:00 -0800 Subject: Abort backup in progress if thread is told to shut down. --- controller/SqliteNetworkController.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'controller') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 60e5bf54..049db04e 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1029,6 +1029,12 @@ void SqliteNetworkController::threadMain() int rc = SQLITE_OK; for(;;) { + if (!_backupThreadRun) { + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + OSUtils::rm(backupPath); + return; + } _lock.lock(); rc = sqlite3_backup_step(bak,64); _lock.unlock(); -- cgit v1.2.3