diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-11-23 10:46:52 -0800 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-11-23 10:46:52 -0800 |
commit | a18336fa1899a9f53b161a60e766695007c49a7b (patch) | |
tree | f464c0475ea49e3714df86d69508644adcf2e98a /controller | |
parent | 1e4a40e77205b028d799f7112127f3f2f107117e (diff) | |
parent | 764dd1c3d94527c0870a913ac314b3b17eaea282 (diff) | |
download | infinitytier-a18336fa1899a9f53b161a60e766695007c49a7b.tar.gz infinitytier-a18336fa1899a9f53b161a60e766695007c49a7b.zip |
MERGE current "dev" into "netcon" -- should not affect netcon itself but will retest -- brings ZeroTier core up to 1.1.0
Diffstat (limited to 'controller')
-rw-r--r-- | controller/SqliteNetworkController.cpp | 182 | ||||
-rw-r--r-- | controller/SqliteNetworkController.hpp | 17 |
2 files changed, 195 insertions, 4 deletions
diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 334ccc75..049db04e 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); @@ -258,8 +267,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); @@ -505,6 +512,53 @@ 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;k<j->u.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;kk<j->u.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;kkk<hop->u.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(); + _circuitTests[test->testId] = test; + _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback)); + + return 200; } // else 404 } else { @@ -946,6 +1000,59 @@ 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(;;) { + if (!_backupThreadRun) { + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + OSUtils::rm(backupPath); + return; + } + _lock.lock(); + rc = sqlite3_backup_step(bak,64); + _lock.unlock(); + if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY)) + Thread::sleep(50); + else break; + } + + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + + OSUtils::rm(backupPath2); + ::rename(backupPath,backupPath2); + } + Thread::sleep(250); + } +} + unsigned int SqliteNetworkController::_doCPGet( const std::vector<std::string> &path, const std::map<std::string,std::string> &urlArgs, @@ -1819,4 +1926,75 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c return NetworkController::NETCONF_QUERY_OK; } +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<SqliteNetworkController *>(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"%.16llx_%.10llx_%.10llx",now,report->upstream,report->current); + 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\"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 + "\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" : ""), + (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, + (unsigned long long)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<const InetAddress *>(&(report->receivedOnLocalAddress))->toString().c_str(), + reinterpret_cast<const InetAddress *>(&(report->receivedFromRemoteAddress))->toString().c_str()); + fclose(f); + } +} + } // namespace ZeroTier diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 68529e39..0e2bb63e 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -39,10 +39,14 @@ #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 +// 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; @@ -83,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 @@ -106,7 +114,11 @@ private: const Dictionary &metaData, Dictionary &netconf); + 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; @@ -140,6 +152,9 @@ private: // Last log entries by address and network ID pair std::map< std::pair<Address,uint64_t>,_LLEntry > _lastLog; + // Circuit tests outstanding + std::map< uint64_t,ZT_CircuitTest * > _circuitTests; + sqlite3 *_db; sqlite3_stmt *_sGetNetworkById; @@ -147,8 +162,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; |