Răsfoiți Sursa

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 ani în urmă
părinte
comite
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;