Pārlūkot izejas kodu

Save test results for circuit tests in memory and then cancel the test and send the results when the test is queried later. This way you can POST a test and then come GET the result at the appointed time.

Adam Ierymenko 9 gadi atpakaļ
vecāks
revīzija
9cb4bbe2b8

+ 78 - 64
controller/SqliteNetworkController.cpp

@@ -555,7 +555,11 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
 					}
 
 					test->timestamp = OSUtils::now();
-					_circuitTests[test->testId] = test;
+
+					_CircuitTestEntry &te = _circuitTests[test->testId];
+					te.test = test;
+					te.jsonResults = "";
+
 					_node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback));
 
 					return 200;
@@ -1235,6 +1239,22 @@ unsigned int SqliteNetworkController::_doCPGet(
 
 					}
 
+				} else if ((path[2] == "test")&&(path.size() >= 4)) {
+
+					std::map< uint64_t,_CircuitTestEntry >::iterator cte(_circuitTests.find(Utils::hexStrToU64(path[3].c_str())));
+					if (cte != _circuitTests.end()) {
+
+						responseBody = "[";
+						responseBody.append(cte->second.jsonResults);
+						responseBody.push_back(']');
+						responseContentType = "application/json";
+
+						_node->circuitTestEnd(cte->second.test);
+						::free((void *)cte->second.test);
+						_circuitTests.erase(cte);
+
+					} // else 404
+
 				} // else 404
 
 			} else {
@@ -1930,73 +1950,67 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c
 
 void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
 {
-	static Mutex circuitTestWriteLock;
-
-	const uint64_t now = OSUtils::now();
+	char tmp[65535];
+	SqliteNetworkController *const self = reinterpret_cast<SqliteNetworkController *>(test->ptr);
 
-	SqliteNetworkController *const c = reinterpret_cast<SqliteNetworkController *>(test->ptr);
-	char tmp[128];
+	if (!test)
+		return;
+	if (!report)
+		return;
 
-	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(self->_lock);
+	std::map< uint64_t,_CircuitTestEntry >::iterator cte(self->_circuitTests.find(test->testId));
 
-	{
-		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);
+	if (cte == self->_circuitTests.end()) { // sanity check: a circuit test we didn't launch?
+		self->_node->circuitTestEnd(test);
+		::free((void *)test);
+		return;
 	}
+
+	Utils::snprintf(tmp,sizeof(tmp),
+		"%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
+		"}",
+		((cte->second.jsonResults.length() > 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)OSUtils::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());
+
+	cte->second.jsonResults.append(tmp);
 }
 
 } // namespace ZeroTier

+ 7 - 4
controller/SqliteNetworkController.hpp

@@ -123,7 +123,7 @@ private:
 	std::string _circuitTestPath;
 	std::string _instanceId;
 
-	// A circular buffer last log
+	// Recent request log by device address and network ID
 	struct _LLEntry
 	{
 		_LLEntry()
@@ -148,12 +148,15 @@ private:
 		// Total requests by this address / network ID pair (also serves mod IN_MEMORY_LOG_SIZE as circular buffer ptr)
 		uint64_t totalRequests;
 	};
-
-	// 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;
+	struct _CircuitTestEntry
+	{
+		ZT_CircuitTest *test;
+		std::string jsonResults;
+	};
+	std::map< uint64_t,_CircuitTestEntry > _circuitTests;
 
 	sqlite3 *_db;