use cpp-httplib for HTTP control plane (#1979)

refactored the old control plane code to use [cpp-httplib](https://github.com/yhirose/cpp-httplib) instead of a hand rolled HTTP server.  Makes the control plane code much more legible.  Also no longer randomly stops responding.
This commit is contained in:
Grant Limberg 2023-04-28 11:03:28 -07:00 committed by GitHub
parent 411e54023a
commit e5fc89821f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 5595 additions and 3345 deletions

View File

@ -15,9 +15,12 @@
namespace ZeroTier { namespace ZeroTier {
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) : DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
_listener(listener), : _listener(listener)
_running(true) , _running(true)
, _syncCheckerThread()
, _dbs()
, _dbs_l()
{ {
_syncCheckerThread = std::thread([this]() { _syncCheckerThread = std::thread([this]() {
for(;;) { for(;;) {

View File

@ -16,6 +16,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <type_traits>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/time.h> #include <sys/time.h>
@ -553,274 +554,16 @@ void EmbeddedNetworkController::request(
_queue.post(qe); _queue.post(qe);
} }
unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( std::string EmbeddedNetworkController::networkUpdateFromPostData(uint64_t networkID, const std::string &body)
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType)
{ {
if ((!path.empty())&&(path[0] == "network")) { json b = OSUtils::jsonParse(body);
if ((path.size() >= 2)&&(path[1].length() == 16)) {
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
json network;
if (!_db.get(nwid,network))
return 404;
if (path.size() >= 3) {
if (path[2] == "member") {
if (path.size() >= 4) {
// Get member
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
json member;
if (!_db.get(nwid,network,address,member))
return 404;
responseBody = OSUtils::jsonDump(member);
responseContentType = "application/json";
} else {
// List members and their revisions
responseBody = "{";
std::vector<json> members;
if (_db.get(nwid,network,members)) {
responseBody.reserve((members.size() + 2) * 32);
std::string mid;
for(auto member=members.begin();member!=members.end();++member) {
mid = OSUtils::jsonString((*member)["id"], "");
char tmp[128];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s\"%s\":%llu",(responseBody.length() > 1) ? "," : "",mid.c_str(),(unsigned long long)OSUtils::jsonInt((*member)["revision"],0));
responseBody.append(tmp);
}
}
responseBody.push_back('}');
responseContentType = "application/json";
}
return 200;
} // else 404
} else {
// Get network
responseBody = OSUtils::jsonDump(network);
responseContentType = "application/json";
return 200;
}
} else if (path.size() == 1) {
// List networks
std::set<uint64_t> networkIds;
_db.networks(networkIds);
char tmp[64];
responseBody = "[";
responseBody.reserve((networkIds.size() + 1) * 24);
for(std::set<uint64_t>::const_iterator i(networkIds.begin());i!=networkIds.end();++i) {
if (responseBody.length() > 1)
responseBody.push_back(',');
OSUtils::ztsnprintf(tmp,sizeof(tmp),"\"%.16llx\"",(unsigned long long)*i);
responseBody.append(tmp);
}
responseBody.push_back(']');
responseContentType = "application/json";
return 200;
} // else 404
} else {
// Controller status
char tmp[4096];
const bool dbOk = _db.isReady();
OSUtils::ztsnprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),dbOk ? "true" : "false");
responseBody = tmp;
responseContentType = "application/json";
return dbOk ? 200 : 503;
}
return 404;
}
unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType)
{
if (path.empty())
return 404;
json b;
try {
b = OSUtils::jsonParse(body);
if (!b.is_object()) {
responseBody = "{ \"message\": \"body is not a JSON object\" }";
responseContentType = "application/json";
return 400;
}
} catch ( ... ) {
responseBody = "{ \"message\": \"body JSON is invalid\" }";
responseContentType = "application/json";
return 400;
}
const int64_t now = OSUtils::now();
if (path[0] == "network") {
if ((path.size() >= 2)&&(path[1].length() == 16)) {
uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
char nwids[24]; char nwids[24];
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", networkID);
if (path.size() >= 3) {
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
uint64_t address = Utils::hexStrToU64(path[3].c_str());
char addrs[24];
OSUtils::ztsnprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address);
json member,network;
_db.get(nwid,network,address,member);
DB::initMember(member);
try {
if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"], false);
if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
if (b.count("remoteTraceTarget")) {
const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
if (rtt.length() == 10) {
member["remoteTraceTarget"] = rtt;
} else {
member["remoteTraceTarget"] = json();
}
}
if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL);
if (b.count("authorized")) {
const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
member["authorized"] = newAuth;
member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now;
if (newAuth) {
member["lastAuthorizedCredentialType"] = "api";
member["lastAuthorizedCredential"] = json();
}
}
}
if (b.count("ipAssignments")) {
json &ipa = b["ipAssignments"];
if (ipa.is_array()) {
json mipa(json::array());
for(unsigned long i=0;i<ipa.size();++i) {
std::string ips = ipa[i];
InetAddress ip(ips.c_str());
if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) {
char tmpip[64];
mipa.push_back(ip.toIpString(tmpip));
if (mipa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
}
member["ipAssignments"] = mipa;
}
}
if (b.count("tags")) {
json &tags = b["tags"];
if (tags.is_array()) {
std::map<uint64_t,uint64_t> mtags;
for(unsigned long i=0;i<tags.size();++i) {
json &tag = tags[i];
if ((tag.is_array())&&(tag.size() == 2))
mtags[OSUtils::jsonInt(tag[0],0ULL) & 0xffffffffULL] = OSUtils::jsonInt(tag[1],0ULL) & 0xffffffffULL;
}
json mtagsa = json::array();
for(std::map<uint64_t,uint64_t>::iterator t(mtags.begin());t!=mtags.end();++t) {
json ta = json::array();
ta.push_back(t->first);
ta.push_back(t->second);
mtagsa.push_back(ta);
if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
member["tags"] = mtagsa;
}
}
if (b.count("capabilities")) {
json &capabilities = b["capabilities"];
if (capabilities.is_array()) {
json mcaps = json::array();
for(unsigned long i=0;i<capabilities.size();++i) {
mcaps.push_back(OSUtils::jsonInt(capabilities[i],0ULL));
if (mcaps.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
std::sort(mcaps.begin(),mcaps.end());
mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end());
member["capabilities"] = mcaps;
}
}
} catch ( ... ) {
responseBody = "{ \"message\": \"exception while processing parameters in JSON body\" }";
responseContentType = "application/json";
return 400;
}
member["id"] = addrs;
member["address"] = addrs; // legacy
member["nwid"] = nwids;
DB::cleanMember(member);
_db.save(member,true);
responseBody = OSUtils::jsonDump(member);
responseContentType = "application/json";
return 200;
} // else 404
} else {
// POST to network ID
// Magic ID ending with ______ picks a random unused network ID
if (path[1].substr(10) == "______") {
nwid = 0;
uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL;
uint64_t nwidPostfix = 0;
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
if (!_db.hasNetwork(tryNwid)) {
nwid = tryNwid;
break;
}
}
if (!nwid)
return 503;
}
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
json network; json network;
_db.get(nwid,network); _db.get(networkID, network);
DB::initNetwork(network); DB::initNetwork(network);
try {
if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],"");
if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true);
if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false);
@ -1058,88 +801,281 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
} }
} }
} catch ( ... ) {
responseBody = "{ \"message\": \"exception occurred while parsing body variables\" }";
responseContentType = "application/json";
return 400;
}
network["id"] = nwids; network["id"] = nwids;
network["nwid"] = nwids; // legacy network["nwid"] = nwids;
DB::cleanNetwork(network); DB::cleanNetwork(network);
_db.save(network, true); _db.save(network, true);
responseBody = OSUtils::jsonDump(network); return network.dump();
responseContentType = "application/json";
return 200;
} // else 404
} // else 404
} }
return 404; void EmbeddedNetworkController::configureHTTPControlPlane(
} httplib::Server &s,
const std::function<void(const httplib::Request&, httplib::Response&, std::string)> setContent)
unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType)
{ {
if (path.empty()) s.Get("/controller/network", [&](const httplib::Request &req, httplib::Response &res) {
return 404; std::set<uint64_t> networkIds;
_db.networks(networkIds);
char tmp[64];
if (path[0] == "network") { auto out = json::array();
if ((path.size() >= 2)&&(path[1].length() == 16)) { for(std::set<uint64_t>::const_iterator i(networkIds.begin()); i != networkIds.end(); ++i) {
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", *i);
if (path.size() >= 3) { out.push_back(tmp);
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { }
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
setContent(req, res, out.dump());
});
s.Get("/controller/network/([0-9a-fA-F]{16})", [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1];
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
json network;
if (!_db.get(nwid, network)) {
res.status = 404;
return;
}
setContent(req, res, network.dump());
});
auto createNewNetwork = [&](const httplib::Request &req, httplib::Response &res) {
fprintf(stderr, "creating new network (new style)\n");
uint64_t nwid = 0;
uint64_t nwidPrefix = (Utils::hexStrToU64(_signingIdAddressString.c_str()) << 24) & 0xffffffffff000000ULL;
uint64_t nwidPostfix = 0;
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
if (!_db.hasNetwork(tryNwid)) {
nwid = tryNwid;
break;
}
}
if (!nwid) {
res.status = 503;
return;
}
setContent(req, res, networkUpdateFromPostData(nwid, req.body));
};
s.Put("/controller/network", createNewNetwork);
s.Post("/controller/network", createNewNetwork);
auto createNewNetworkOldAndBusted = [&](const httplib::Request &req, httplib::Response &res) {
auto inID = req.matches[1].str();
if (inID != _signingIdAddressString) {
res.status = 400;
return;
}
uint64_t nwid = 0;
uint64_t nwidPrefix = (Utils::hexStrToU64(inID.c_str()) << 24) & 0xffffffffff000000ULL;
uint64_t nwidPostfix = 0;
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
if (!_db.hasNetwork(tryNwid)) {
nwid = tryNwid;
break;
}
}
if (!nwid) {
res.status = 503;
return;
}
setContent(req, res, networkUpdateFromPostData(nwid, req.body));
};
s.Put("/controller/network/([0-9a-fA-F]{10})______", createNewNetworkOldAndBusted);
s.Post("/controller/network/([0-9a-fA-F]{10})______", createNewNetworkOldAndBusted);
s.Delete("/controller/network/([0-9a-fA-F]{16})", [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1].str();
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
json network;
if (!_db.get(nwid,network)) {
res.status = 404;
return;
}
_db.eraseNetwork(nwid);
setContent(req, res, network.dump());
});
s.Get("/controller/network/([0-9a-fA-F]{16})/member", [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1];
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
json network;
if (!_db.get(nwid, network)) {
res.status = 404;
return;
}
json out = json::array();
std::vector<json> memTmp;
if (_db.get(nwid, network, memTmp)) {
for (auto m = memTmp.begin(); m != memTmp.end(); ++m) {
int revision = OSUtils::jsonInt((*m)["revsision"], 0);
std::string id = OSUtils::jsonString((*m)["id"], "");
if (id.length() == 10) {
json tmp = json::object();
tmp[id] = revision;
out.push_back(tmp);
}
}
}
setContent(req, res, out.dump());
});
s.Get("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1];
auto memberID = req.matches[2];
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
uint64_t memid = Utils::hexStrToU64(memberID.str().c_str());
json network;
json member;
if (!_db.get(nwid, network, memid, member)) {
res.status = 404;
return;
}
setContent(req, res, member.dump());
});
auto memberPost = [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1].str();
auto memberID = req.matches[2].str();
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
uint64_t memid = Utils::hexStrToU64(memberID.c_str());
json network;
json member;
_db.get(nwid, network, memid, member);
DB::initMember(member);
json b = OSUtils::jsonParse(req.body);
if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"], false);
if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
if (b.count("remoteTraceTarget")) {
const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
if (rtt.length() == 10) {
member["remoteTraceTarget"] = rtt;
} else {
member["remoteTraceTarget"] = json();
}
}
if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL);
if (b.count("authorized")) {
const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
member["authorized"] = newAuth;
member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = OSUtils::now();
if (newAuth) {
member["lastAuthorizedCredentialType"] = "api";
member["lastAuthorizedCredential"] = json();
}
}
}
if (b.count("ipAssignments")) {
json &ipa = b["ipAssignments"];
if (ipa.is_array()) {
json mipa(json::array());
for(unsigned long i=0;i<ipa.size();++i) {
std::string ips = ipa[i];
InetAddress ip(ips.c_str());
if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) {
char tmpip[64];
mipa.push_back(ip.toIpString(tmpip));
if (mipa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
}
member["ipAssignments"] = mipa;
}
}
if (b.count("tags")) {
json &tags = b["tags"];
if (tags.is_array()) {
std::map<uint64_t,uint64_t> mtags;
for(unsigned long i=0;i<tags.size();++i) {
json &tag = tags[i];
if ((tag.is_array())&&(tag.size() == 2))
mtags[OSUtils::jsonInt(tag[0],0ULL) & 0xffffffffULL] = OSUtils::jsonInt(tag[1],0ULL) & 0xffffffffULL;
}
json mtagsa = json::array();
for(std::map<uint64_t,uint64_t>::iterator t(mtags.begin());t!=mtags.end();++t) {
json ta = json::array();
ta.push_back(t->first);
ta.push_back(t->second);
mtagsa.push_back(ta);
if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
member["tags"] = mtagsa;
}
}
if (b.count("capabilities")) {
json &capabilities = b["capabilities"];
if (capabilities.is_array()) {
json mcaps = json::array();
for(unsigned long i=0;i<capabilities.size();++i) {
mcaps.push_back(OSUtils::jsonInt(capabilities[i],0ULL));
if (mcaps.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
break;
}
std::sort(mcaps.begin(),mcaps.end());
mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end());
member["capabilities"] = mcaps;
}
}
member["id"] = memberID;
member["address"] = memberID;
member["nwid"] = networkID;
DB::cleanMember(member);
_db.save(member, true);
setContent(req, res, member.dump());
};
s.Put("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", memberPost);
s.Post("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", memberPost);
s.Delete("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", [&](const httplib::Request &req, httplib::Response &res) {
auto networkID = req.matches[1].str();
auto memberID = req.matches[2].str();
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
uint64_t address = Utils::hexStrToU64(memberID.c_str());
json network, member; json network, member;
_db.get(nwid,network,address,member);
if (!_db.get(nwid, network, address, member)) {
res.status = 404;
return;
}
if (!member.size()) {
res.status = 404;
return;
}
_db.eraseMember(nwid, address); _db.eraseMember(nwid, address);
{ setContent(req, res, member.dump());
std::lock_guard<std::mutex> l(_memberStatus_l); });
_memberStatus.erase(_MemberStatusKey(nwid,address));
}
if (!member.size())
return 404;
responseBody = OSUtils::jsonDump(member);
responseContentType = "application/json";
return 200;
}
} else {
json network;
_db.get(nwid,network);
_db.eraseNetwork(nwid);
{
std::lock_guard<std::mutex> l(_memberStatus_l);
for(auto i=_memberStatus.begin();i!=_memberStatus.end();) {
if (i->first.networkId == nwid)
_memberStatus.erase(i++);
else ++i;
}
}
if (!network.size())
return 404;
responseBody = OSUtils::jsonDump(network);
responseContentType = "application/json";
return 200;
}
} // else 404
} // else 404
return 404;
} }
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)

View File

@ -37,6 +37,8 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <cpp-httplib/httplib.h>
#include "DB.hpp" #include "DB.hpp"
#include "DBMirrorSet.hpp" #include "DBMirrorSet.hpp"
@ -66,27 +68,9 @@ public:
const Identity &identity, const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData); const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
unsigned int handleControlPlaneHttpGET( void configureHTTPControlPlane(
const std::vector<std::string> &path, httplib::Server &s,
const std::map<std::string,std::string> &urlArgs, const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType);
unsigned int handleControlPlaneHttpPOST(
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType);
unsigned int handleControlPlaneHttpDELETE(
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
const std::map<std::string,std::string> &headers,
const std::string &body,
std::string &responseBody,
std::string &responseContentType);
void handleRemoteTrace(const ZT_RemoteTrace &rt); void handleRemoteTrace(const ZT_RemoteTrace &rt);
@ -98,6 +82,8 @@ private:
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData); void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
void _startThreads(); void _startThreads();
std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
struct _RQEntry struct _RQEntry
{ {
uint64_t nwid; uint64_t nwid;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff