mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
LFDB work in progress
This commit is contained in:
parent
a0f47b12b4
commit
5edd04638d
7 changed files with 3561 additions and 6 deletions
|
@ -46,6 +46,11 @@
|
||||||
#include "../version.h"
|
#include "../version.h"
|
||||||
|
|
||||||
#include "EmbeddedNetworkController.hpp"
|
#include "EmbeddedNetworkController.hpp"
|
||||||
|
#include "LFDB.hpp"
|
||||||
|
#include "FileDB.hpp"
|
||||||
|
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||||
|
#include "PostgreSQL.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../node/Node.hpp"
|
#include "../node/Node.hpp"
|
||||||
#include "../node/CertificateOfMembership.hpp"
|
#include "../node/CertificateOfMembership.hpp"
|
||||||
|
@ -488,12 +493,49 @@ void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
|
||||||
_signingId = signingId;
|
_signingId = signingId;
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
_signingIdAddressString = signingId.address().toString(tmp);
|
_signingIdAddressString = signingId.address().toString(tmp);
|
||||||
|
|
||||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||||
if ((_path.length() > 9)&&(_path.substr(0,9) == "postgres:"))
|
if ((_path.length() > 9)&&(_path.substr(0,9) == "postgres:")) {
|
||||||
_db.reset(new PostgreSQL(this,_signingId,_path.substr(9).c_str(), _listenPort, _mqc));
|
_db.reset(new PostgreSQL(this,_signingId,_path.substr(9).c_str(), _listenPort, _mqc));
|
||||||
else // else use FileDB after endif
|
} else {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string lfJSON;
|
||||||
|
OSUtils::readFile((_path + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON);
|
||||||
|
if (lfJSON.length() > 0) {
|
||||||
|
nlohmann::json lfConfig(OSUtils::jsonParse(lfJSON));
|
||||||
|
nlohmann::json &settings = lfConfig["settings"];
|
||||||
|
if (settings.is_object()) {
|
||||||
|
nlohmann::json &controllerDb = lfConfig["controllerDb"];
|
||||||
|
if (controllerDb.is_object()) {
|
||||||
|
std::string type = controllerDb["type"];
|
||||||
|
if (type == "lf") {
|
||||||
|
std::string lfOwner = controllerDb["owner"];
|
||||||
|
std::string lfHost = controllerDb["host"];
|
||||||
|
int lfPort = controllerDb["port"];
|
||||||
|
bool storeOnlineState = controllerDb["storeOnlineState"];
|
||||||
|
if ((lfOwner.length())&&(lfHost.length())&&(lfPort > 0)&&(lfPort < 65536)) {
|
||||||
|
std::size_t pubHdrLoc = lfOwner.find("Public: ");
|
||||||
|
if ((pubHdrLoc > 0)&&((pubHdrLoc + 8) < lfOwner.length())) {
|
||||||
|
std::string lfOwnerPublic = lfOwner.substr(pubHdrLoc + 8);
|
||||||
|
std::size_t pubHdrEnd = lfOwnerPublic.find_first_of("\n\r\t ");
|
||||||
|
if (pubHdrEnd != std::string::npos) {
|
||||||
|
lfOwnerPublic = lfOwnerPublic.substr(0,pubHdrEnd);
|
||||||
|
_db.reset(new LFDB(this,_signingId,_path.c_str(),lfOwner.c_str(),lfOwnerPublic.c_str(),lfHost.c_str(),lfPort,storeOnlineState));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_db)
|
||||||
_db.reset(new FileDB(this,_signingId,_path.c_str()));
|
_db.reset(new FileDB(this,_signingId,_path.c_str()));
|
||||||
|
|
||||||
|
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
_db->waitForReady();
|
_db->waitForReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,6 @@
|
||||||
#include "../ext/json/json.hpp"
|
#include "../ext/json/json.hpp"
|
||||||
|
|
||||||
#include "DB.hpp"
|
#include "DB.hpp"
|
||||||
#include "FileDB.hpp"
|
|
||||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
|
||||||
#include "PostgreSQL.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
|
360
controller/LFDB.cpp
Normal file
360
controller/LFDB.cpp
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
/*
|
||||||
|
* ZeroTier One - Network Virtualization Everywhere
|
||||||
|
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* --
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the license by purchasing
|
||||||
|
* a commercial license. Buying such a license is mandatory as soon as you
|
||||||
|
* develop commercial closed-source software that incorporates or links
|
||||||
|
* directly against ZeroTier software without disclosing the source code
|
||||||
|
* of your own application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LFDB.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "../osdep/OSUtils.hpp"
|
||||||
|
#include "../ext/cpp-httplib/httplib.h"
|
||||||
|
|
||||||
|
namespace ZeroTier
|
||||||
|
{
|
||||||
|
|
||||||
|
LFDB::LFDB(EmbeddedNetworkController *const nc,const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState) :
|
||||||
|
DB(nc,myId,path),
|
||||||
|
_nc(nc),
|
||||||
|
_myId(myId),
|
||||||
|
_lfOwnerPrivate(lfOwnerPrivate),
|
||||||
|
_lfOwnerPublic(lfOwnerPublic),
|
||||||
|
_lfNodeHost(lfNodeHost),
|
||||||
|
_lfNodePort(lfNodePort),
|
||||||
|
_running(true),
|
||||||
|
_ready(false),
|
||||||
|
_storeOnlineState(storeOnlineState)
|
||||||
|
{
|
||||||
|
_syncThread = std::thread([this]() {
|
||||||
|
char controllerAddress[24];
|
||||||
|
_myId.address().toString(controllerAddress);
|
||||||
|
|
||||||
|
httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort,600);
|
||||||
|
while (_running) {
|
||||||
|
std::ostringstream query;
|
||||||
|
query
|
||||||
|
<< '{'
|
||||||
|
<< "\"Ranges\":[{"
|
||||||
|
<< "\"Name\": \"com.zerotier.controller.lfdb:" << controllerAddress << "\""
|
||||||
|
<< "}],"
|
||||||
|
<< "\"MaskingKey\":\"" << controllerAddress << "\","
|
||||||
|
<< "\"Owners\":[\"" << _lfOwnerPublic << "\"],"
|
||||||
|
<< "\"Open\":true"
|
||||||
|
<< '}';
|
||||||
|
auto resp = htcli.Post("/query",query.str(),"application/json");
|
||||||
|
if (resp->status == 200) {
|
||||||
|
fprintf(stderr,"%d %s\n",resp->status,resp->body.c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"ERROR: LFDB: %d from node: %s" ZT_EOL_S,resp->status,resp->body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
_ready = true;
|
||||||
|
|
||||||
|
for(int k=0;k<10;++k) {
|
||||||
|
if (!_running)
|
||||||
|
return;
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LFDB::~LFDB()
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_syncThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LFDB::waitForReady()
|
||||||
|
{
|
||||||
|
while (!_ready)
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LFDB::isReady()
|
||||||
|
{
|
||||||
|
return (_ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFDB::save(nlohmann::json *orig,nlohmann::json &record)
|
||||||
|
{
|
||||||
|
if (orig) {
|
||||||
|
if (*orig != record) {
|
||||||
|
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
record["revision"] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string objtype = record["objtype"];
|
||||||
|
if (objtype == "network") {
|
||||||
|
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
|
||||||
|
if (nwid) {
|
||||||
|
nlohmann::json old;
|
||||||
|
get(nwid,old);
|
||||||
|
if ((!old.is_object())||(old != record)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (objtype == "member") {
|
||||||
|
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
|
||||||
|
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
|
||||||
|
if ((id)&&(nwid)) {
|
||||||
|
nlohmann::json network,old;
|
||||||
|
get(nwid,network,id,old);
|
||||||
|
if ((!old.is_object())||(old != record)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFDB::eraseNetwork(const uint64_t networkId)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(_state_l);
|
||||||
|
auto nw = _state.find(networkId);
|
||||||
|
if (nw != _state.end()) {
|
||||||
|
auto m = nw->second.members.find(memberId);
|
||||||
|
if (m != nw->second.members.end()) {
|
||||||
|
m->second.lastOnlineTime = OSUtils::now();
|
||||||
|
if (physicalAddress)
|
||||||
|
m->second.lastOnlineAddress = physicalAddress;
|
||||||
|
m->second.lastOnlineDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
FileDB::FileDB(EmbeddedNetworkController *const nc,const Identity &myId,const char *path) :
|
||||||
|
DB(nc,myId,path),
|
||||||
|
_networksPath(_path + ZT_PATH_SEPARATOR_S + "network"),
|
||||||
|
_tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"),
|
||||||
|
_onlineChanged(false),
|
||||||
|
_running(true)
|
||||||
|
{
|
||||||
|
OSUtils::mkdir(_path.c_str());
|
||||||
|
OSUtils::lockDownFile(_path.c_str(),true);
|
||||||
|
OSUtils::mkdir(_networksPath.c_str());
|
||||||
|
OSUtils::mkdir(_tracePath.c_str());
|
||||||
|
|
||||||
|
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(),false));
|
||||||
|
std::string buf;
|
||||||
|
for(auto n=networks.begin();n!=networks.end();++n) {
|
||||||
|
buf.clear();
|
||||||
|
if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) {
|
||||||
|
try {
|
||||||
|
nlohmann::json network(OSUtils::jsonParse(buf));
|
||||||
|
const std::string nwids = network["id"];
|
||||||
|
if (nwids.length() == 16) {
|
||||||
|
nlohmann::json nullJson;
|
||||||
|
_networkChanged(nullJson,network,false);
|
||||||
|
std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
|
||||||
|
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false));
|
||||||
|
for(auto m=members.begin();m!=members.end();++m) {
|
||||||
|
buf.clear();
|
||||||
|
if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) {
|
||||||
|
try {
|
||||||
|
nlohmann::json member(OSUtils::jsonParse(buf));
|
||||||
|
const std::string addrs = member["id"];
|
||||||
|
if (addrs.length() == 10) {
|
||||||
|
nlohmann::json nullJson2;
|
||||||
|
_memberChanged(nullJson2,member,false);
|
||||||
|
}
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onlineUpdateThread = std::thread([this]() {
|
||||||
|
unsigned int cnt = 0;
|
||||||
|
while (this->_running) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||||
|
if ((++cnt % 20) == 0) { // 5 seconds
|
||||||
|
std::lock_guard<std::mutex> l(this->_online_l);
|
||||||
|
if (!this->_running) return;
|
||||||
|
if (this->_onlineChanged) {
|
||||||
|
char p[4096],atmp[64];
|
||||||
|
for(auto nw=this->_online.begin();nw!=this->_online.end();++nw) {
|
||||||
|
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx-online.json",_networksPath.c_str(),(unsigned long long)nw->first);
|
||||||
|
FILE *f = fopen(p,"wb");
|
||||||
|
if (f) {
|
||||||
|
fprintf(f,"{");
|
||||||
|
const char *memberPrefix = "";
|
||||||
|
for(auto m=nw->second.begin();m!=nw->second.end();++m) {
|
||||||
|
fprintf(f,"%s\"%.10llx\":{" ZT_EOL_S,memberPrefix,(unsigned long long)m->first);
|
||||||
|
memberPrefix = ",";
|
||||||
|
InetAddress lastAddr;
|
||||||
|
const char *timestampPrefix = " ";
|
||||||
|
int cnt = 0;
|
||||||
|
for(auto ts=m->second.rbegin();ts!=m->second.rend();) {
|
||||||
|
if (cnt < 25) {
|
||||||
|
if (lastAddr != ts->second) {
|
||||||
|
lastAddr = ts->second;
|
||||||
|
fprintf(f,"%s\"%lld\":\"%s\"" ZT_EOL_S,timestampPrefix,(long long)ts->first,ts->second.toString(atmp));
|
||||||
|
timestampPrefix = ",";
|
||||||
|
++cnt;
|
||||||
|
++ts;
|
||||||
|
} else {
|
||||||
|
ts = std::map<int64_t,InetAddress>::reverse_iterator(m->second.erase(std::next(ts).base()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ts = std::map<int64_t,InetAddress>::reverse_iterator(m->second.erase(std::next(ts).base()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(f,"}");
|
||||||
|
}
|
||||||
|
fprintf(f,"}" ZT_EOL_S);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->_onlineChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDB::~FileDB()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
_online_l.lock();
|
||||||
|
_running = false;
|
||||||
|
_online_l.unlock();
|
||||||
|
_onlineUpdateThread.join();
|
||||||
|
} catch ( ... ) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileDB::waitForReady() { return true; }
|
||||||
|
bool FileDB::isReady() { return true; }
|
||||||
|
|
||||||
|
void FileDB::save(nlohmann::json *orig,nlohmann::json &record)
|
||||||
|
{
|
||||||
|
char p1[4096],p2[4096],pb[4096];
|
||||||
|
try {
|
||||||
|
if (orig) {
|
||||||
|
if (*orig != record) {
|
||||||
|
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
record["revision"] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string objtype = record["objtype"];
|
||||||
|
if (objtype == "network") {
|
||||||
|
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
|
||||||
|
if (nwid) {
|
||||||
|
nlohmann::json old;
|
||||||
|
get(nwid,old);
|
||||||
|
if ((!old.is_object())||(old != record)) {
|
||||||
|
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid);
|
||||||
|
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1)))
|
||||||
|
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
|
||||||
|
_networkChanged(old,record,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (objtype == "member") {
|
||||||
|
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
|
||||||
|
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
|
||||||
|
if ((id)&&(nwid)) {
|
||||||
|
nlohmann::json network,old;
|
||||||
|
get(nwid,network,id,old);
|
||||||
|
if ((!old.is_object())||(old != record)) {
|
||||||
|
OSUtils::ztsnprintf(pb,sizeof(pb),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)nwid);
|
||||||
|
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.10llx.json",pb,(unsigned long long)id);
|
||||||
|
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
|
||||||
|
OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid);
|
||||||
|
OSUtils::mkdir(p2);
|
||||||
|
OSUtils::mkdir(pb);
|
||||||
|
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1)))
|
||||||
|
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
|
||||||
|
}
|
||||||
|
_memberChanged(old,record,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (objtype == "trace") {
|
||||||
|
const std::string id = record["id"];
|
||||||
|
if (id.length() > 0) {
|
||||||
|
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%s.json",_tracePath.c_str(),id.c_str());
|
||||||
|
OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( ... ) {} // drop invalid records missing fields
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDB::eraseNetwork(const uint64_t networkId)
|
||||||
|
{
|
||||||
|
nlohmann::json network,nullJson;
|
||||||
|
get(networkId,network);
|
||||||
|
char p[16384];
|
||||||
|
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId);
|
||||||
|
OSUtils::rm(p);
|
||||||
|
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx-online.json",_networksPath.c_str(),networkId);
|
||||||
|
OSUtils::rm(p);
|
||||||
|
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)networkId);
|
||||||
|
OSUtils::rmDashRf(p);
|
||||||
|
_networkChanged(network,nullJson,true);
|
||||||
|
std::lock_guard<std::mutex> l(this->_online_l);
|
||||||
|
this->_online.erase(networkId);
|
||||||
|
this->_onlineChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
|
||||||
|
{
|
||||||
|
nlohmann::json network,member,nullJson;
|
||||||
|
get(networkId,network);
|
||||||
|
get(memberId,member);
|
||||||
|
char p[4096];
|
||||||
|
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",_networksPath.c_str(),networkId,memberId);
|
||||||
|
OSUtils::rm(p);
|
||||||
|
_memberChanged(member,nullJson,true);
|
||||||
|
std::lock_guard<std::mutex> l(this->_online_l);
|
||||||
|
this->_online[networkId].erase(memberId);
|
||||||
|
this->_onlineChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||||
|
{
|
||||||
|
char mid[32],atmp[64];
|
||||||
|
OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId);
|
||||||
|
physicalAddress.toString(atmp);
|
||||||
|
std::lock_guard<std::mutex> l(this->_online_l);
|
||||||
|
this->_online[networkId][memberId][OSUtils::now()] = physicalAddress;
|
||||||
|
this->_onlineChanged = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
97
controller/LFDB.hpp
Normal file
97
controller/LFDB.hpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* ZeroTier One - Network Virtualization Everywhere
|
||||||
|
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* --
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the license by purchasing
|
||||||
|
* a commercial license. Buying such a license is mandatory as soon as you
|
||||||
|
* develop commercial closed-source software that incorporates or links
|
||||||
|
* directly against ZeroTier software without disclosing the source code
|
||||||
|
* of your own application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZT_CONTROLLER_LFDB_HPP
|
||||||
|
#define ZT_CONTROLLER_LFDB_HPP
|
||||||
|
|
||||||
|
#include "DB.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB implementation for controller that stores data in LF
|
||||||
|
*/
|
||||||
|
class LFDB : public DB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @param nc Network controller
|
||||||
|
* @param myId Identity of controller node (with secret)
|
||||||
|
* @param path Base path for ZeroTier node itself
|
||||||
|
* @param lfOwnerPrivate LF owner private in PEM format
|
||||||
|
* @param lfOwnerPublic LF owner public in @base62 format
|
||||||
|
* @param lfNodeHost LF node host
|
||||||
|
* @param lfNodePort LF node http (not https) port
|
||||||
|
* @param storeOnlineState If true, store online/offline state and IP info in LF (a lot of data, only for private networks!)
|
||||||
|
*/
|
||||||
|
LFDB(EmbeddedNetworkController *const nc,const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState);
|
||||||
|
virtual ~LFDB();
|
||||||
|
|
||||||
|
virtual bool waitForReady();
|
||||||
|
virtual bool isReady();
|
||||||
|
virtual void save(nlohmann::json *orig,nlohmann::json &record);
|
||||||
|
virtual void eraseNetwork(const uint64_t networkId);
|
||||||
|
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
|
||||||
|
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EmbeddedNetworkController *const _nc;
|
||||||
|
const Identity _myId;
|
||||||
|
|
||||||
|
std::string _lfOwnerPrivate;
|
||||||
|
std::string _lfOwnerPublic;
|
||||||
|
std::string _lfNodeHost;
|
||||||
|
int _lfNodePort;
|
||||||
|
|
||||||
|
struct _MemberState
|
||||||
|
{
|
||||||
|
InetAddress lastOnlineAddress;
|
||||||
|
int64_t lastOnlineTime;
|
||||||
|
bool dirty;
|
||||||
|
bool lastOnlineDirty;
|
||||||
|
};
|
||||||
|
struct _NetworkState
|
||||||
|
{
|
||||||
|
std::unordered_map<uint64_t,_MemberState> members;
|
||||||
|
bool dirty;
|
||||||
|
};
|
||||||
|
std::unordered_map<uint64_t,_NetworkState> _state;
|
||||||
|
std::mutex _state_l;
|
||||||
|
|
||||||
|
std::atomic_bool _running;
|
||||||
|
std::atomic_bool _ready;
|
||||||
|
std::thread _syncThread;
|
||||||
|
bool _storeOnlineState;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif
|
22
ext/cpp-httplib/LICENSE
Normal file
22
ext/cpp-httplib/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 yhirose
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
259
ext/cpp-httplib/README.md
Normal file
259
ext/cpp-httplib/README.md
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
cpp-httplib
|
||||||
|
===========
|
||||||
|
|
||||||
|
[](https://travis-ci.org/yhirose/cpp-httplib)
|
||||||
|
[](https://ci.appveyor.com/project/yhirose/cpp-httplib)
|
||||||
|
|
||||||
|
A C++ header-only cross platform HTTP/HTTPS library.
|
||||||
|
|
||||||
|
It's extremely easy to setup. Just include **httplib.h** file in your code!
|
||||||
|
|
||||||
|
Inspired by [Sinatra](http://www.sinatrarb.com/) and [express](https://github.com/visionmedia/express).
|
||||||
|
|
||||||
|
Server Example
|
||||||
|
--------------
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include <httplib.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
using namespace httplib;
|
||||||
|
|
||||||
|
Server svr;
|
||||||
|
|
||||||
|
svr.Get("/hi", [](const Request& req, Response& res) {
|
||||||
|
res.set_content("Hello World!", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
|
||||||
|
auto numbers = req.matches[1];
|
||||||
|
res.set_content(numbers, "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.listen("localhost", 1234);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Post`, `Put`, `Delete` and `Options` methods are also supported.
|
||||||
|
|
||||||
|
### Bind a socket to multiple interfaces and any available port
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int port = svr.bind_to_any_port("0.0.0.0");
|
||||||
|
svr.listen_after_bind();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method Chain
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.Get("/get", [](const auto& req, auto& res) {
|
||||||
|
res.set_content("get", "text/plain");
|
||||||
|
})
|
||||||
|
.Post("/post", [](const auto& req, auto& res) {
|
||||||
|
res.set_content(req.body(), "text/plain");
|
||||||
|
})
|
||||||
|
.listen("localhost", 1234);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Static File Server
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_base_dir("./www");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_logger([](const auto& req, const auto& res) {
|
||||||
|
your_logger(req, res);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Handler
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_error_handler([](const auto& req, auto& res) {
|
||||||
|
const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
snprintf(buf, sizeof(buf), fmt, res.status);
|
||||||
|
res.set_content(buf, "text/html");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 'multipart/form-data' POST data
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.Post("/multipart", [&](const auto& req, auto& res) {
|
||||||
|
auto size = req.files.size();
|
||||||
|
auto ret = req.has_file("name1"));
|
||||||
|
const auto& file = req.get_file_value("name1");
|
||||||
|
// file.filename;
|
||||||
|
// file.content_type;
|
||||||
|
auto body = req.body.substr(file.offset, file.length));
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Client Example
|
||||||
|
--------------
|
||||||
|
|
||||||
|
### GET
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include <httplib.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
httplib::Client cli("localhost", 1234);
|
||||||
|
|
||||||
|
auto res = cli.Get("/hi");
|
||||||
|
if (res && res->status == 200) {
|
||||||
|
std::cout << res->body << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET with Content Receiver
|
||||||
|
|
||||||
|
```c++
|
||||||
|
std::string body;
|
||||||
|
auto res = cli.Get("/large-data", [&](const char *data, size_t len) {
|
||||||
|
body.append(data, len);
|
||||||
|
});
|
||||||
|
assert(res->body.empty());
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST
|
||||||
|
|
||||||
|
```c++
|
||||||
|
res = cli.Post("/post", "text", "text/plain");
|
||||||
|
res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded");
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST with parameters
|
||||||
|
|
||||||
|
```c++
|
||||||
|
httplib::Params params;
|
||||||
|
params.emplace("name", "john");
|
||||||
|
params.emplace("note", "coder");
|
||||||
|
|
||||||
|
auto res = cli.Post("/post", params);
|
||||||
|
```
|
||||||
|
or
|
||||||
|
|
||||||
|
```c++
|
||||||
|
httplib::Params params{
|
||||||
|
{ "name", "john" },
|
||||||
|
{ "note", "coder" }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto res = cli.Post("/post", params);
|
||||||
|
```
|
||||||
|
|
||||||
|
### PUT
|
||||||
|
|
||||||
|
```c++
|
||||||
|
res = cli.Put("/resource/foo", "text", "text/plain");
|
||||||
|
```
|
||||||
|
|
||||||
|
### DELETE
|
||||||
|
|
||||||
|
```c++
|
||||||
|
res = cli.Delete("/resource/foo");
|
||||||
|
```
|
||||||
|
|
||||||
|
### OPTIONS
|
||||||
|
|
||||||
|
```c++
|
||||||
|
res = cli.Options("*");
|
||||||
|
res = cli.Options("/resource/foo");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Timeout
|
||||||
|
|
||||||
|
```c++
|
||||||
|
httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds
|
||||||
|
```
|
||||||
|
### With Progress Callback
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
httplib::Client client(url, port);
|
||||||
|
|
||||||
|
// prints: 0 / 000 bytes => 50% complete
|
||||||
|
std::shared_ptr<httplib::Response> res =
|
||||||
|
cli.Get("/", [](uint64_t len, uint64_t total) {
|
||||||
|
printf("%lld / %lld bytes => %d%% complete\n",
|
||||||
|
len, total,
|
||||||
|
(int)((len/total)*100));
|
||||||
|
return true; // return 'false' if you want to cancel the request.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23).
|
||||||
|
|
||||||
|
### Basic Authentication
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
httplib::Client cli("httplib.org");
|
||||||
|
|
||||||
|
auto res = cli.Get("/basic-auth/hello/world", {
|
||||||
|
httplib::make_basic_authentication_header("hello", "world")
|
||||||
|
});
|
||||||
|
// res->status should be 200
|
||||||
|
// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n".
|
||||||
|
```
|
||||||
|
|
||||||
|
### Range
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
httplib::Client cli("httpbin.org");
|
||||||
|
|
||||||
|
auto res = cli.Get("/range/32", {
|
||||||
|
httplib::make_range_header(1, 10) // 'Range: bytes=1-10'
|
||||||
|
});
|
||||||
|
// res->status should be 206.
|
||||||
|
// res->body should be "bcdefghijk".
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenSSL Support
|
||||||
|
---------------
|
||||||
|
|
||||||
|
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
|
||||||
|
SSLServer svr("./cert.pem", "./key.pem");
|
||||||
|
|
||||||
|
SSLClient cli("localhost", 8080);
|
||||||
|
cli.set_ca_cert_path("./ca-bundle.crt");
|
||||||
|
cli.enable_server_certificate_verification(true);
|
||||||
|
```
|
||||||
|
|
||||||
|
Zlib Support
|
||||||
|
------------
|
||||||
|
|
||||||
|
'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`.
|
||||||
|
|
||||||
|
The server applies gzip compression to the following MIME type contents:
|
||||||
|
|
||||||
|
* all text types
|
||||||
|
* image/svg+xml
|
||||||
|
* application/javascript
|
||||||
|
* application/json
|
||||||
|
* application/xml
|
||||||
|
* application/xhtml+xml
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
----
|
||||||
|
|
||||||
|
g++ 4.8 cannot build this library since `<regex>` in g++4.8 is [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions).
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
MIT license (© 2019 Yuji Hirose)
|
2779
ext/cpp-httplib/httplib.h
Normal file
2779
ext/cpp-httplib/httplib.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue