diff --git a/controller/DB.hpp b/controller/DB.hpp index 461f385e6..732a6e25c 100644 --- a/controller/DB.hpp +++ b/controller/DB.hpp @@ -27,6 +27,8 @@ #ifndef ZT_CONTROLLER_DB_HPP #define ZT_CONTROLLER_DB_HPP +#define ZT_CONTROLLER_USE_LIBPQ + #include "../node/Constants.hpp" #include "../node/Identity.hpp" #include "../node/InetAddress.hpp" @@ -99,7 +101,7 @@ public: bool summary(const uint64_t networkId,NetworkSummaryInfo &info); void networks(std::vector &networks); - virtual void save(nlohmann::json *orig,nlohmann::json &record) = 0; + virtual void save(nlohmann::json &record) = 0; virtual void eraseNetwork(const uint64_t networkId) = 0; virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0; diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp new file mode 100644 index 000000000..bccdefddd --- /dev/null +++ b/controller/DBMirrorSet.cpp @@ -0,0 +1,112 @@ +/* + * 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 . + * + * -- + * + * 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 "DBMirrorSet.hpp" + +namespace ZeroTier { + +DBMirrorSet::DBMirrorSet() +{ +} + +DBMirrorSet::~DBMirrorSet() +{ +} + +bool DBMirrorSet::waitForReady() +{ + bool r = false; + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + r |= (*d)->waitForReady(); + } + return r; +} + +bool DBMirrorSet::isReady() +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if (!(*d)->isReady()) + return false; + } + return true; +} + +void DBMirrorSet::save(nlohmann::json &record) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->save(record); + } +} + +void DBMirrorSet::eraseNetwork(const uint64_t networkId) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->eraseNetwork(networkId); + } +} + +void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->eraseMember(networkId,memberId); + } +} + +void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->nodeIsOnline(networkId,memberId,physicalAddress); + } +} + +void DBMirrorSet::onNetworkUpdate(const DB *db,uint64_t networkId,const nlohmann::json &network) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if (d->get() != db) { + } + } +} + +void DBMirrorSet::onNetworkMemberUpdate(const DB *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) +{ +} + +void DBMirrorSet::onNetworkMemberDeauthorize(const DB *db,uint64_t networkId,uint64_t memberId) +{ +} + +void DBMirrorSet::onNetworkMemberOnline(const DB *db,uint64_t networkId,uint64_t memberId,const InetAddress &physicalAddress) +{ +} + +} // namespace ZeroTier diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp new file mode 100644 index 000000000..1af0018ee --- /dev/null +++ b/controller/DBMirrorSet.hpp @@ -0,0 +1,70 @@ +/* + * 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 . + * + * -- + * + * 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_DBMIRRORSET_HPP +#define ZT_DBMIRRORSET_HPP + +#include "DB.hpp" + +#include +#include +#include + +namespace ZeroTier { + +class DBMirrorSet : public DB::ChangeListener +{ +public: + DBMirrorSet(); + virtual ~DBMirrorSet(); + + bool waitForReady(); + bool isReady(); + void save(nlohmann::json &record); + void eraseNetwork(const uint64_t networkId); + void eraseMember(const uint64_t networkId,const uint64_t memberId); + void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + + // These are called by various DB instances when changes occur. + virtual void onNetworkUpdate(const DB *db,uint64_t networkId,const nlohmann::json &network); + virtual void onNetworkMemberUpdate(const DB *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member); + virtual void onNetworkMemberDeauthorize(const DB *db,uint64_t networkId,uint64_t memberId); + virtual void onNetworkMemberOnline(const DB *db,uint64_t networkId,uint64_t memberId,const InetAddress &physicalAddress); + + inline void addDB(const std::shared_ptr &db) + { + std::lock_guard l(_dbs_l); + _dbs.push_back(db); + } + +private: + std::vector< std::shared_ptr< DB > > _dbs; + std::mutex _dbs_l; +}; + +} // namespace ZeroTier + +#endif diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 80331578c..d9c6364b6 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -705,7 +705,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json member,network; _db->get(nwid,network,address,member); - json origMember(member); // for detecting changes DB::initMember(member); try { @@ -799,7 +798,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( member["nwid"] = nwids; DB::cleanMember(member); - _db->save(&origMember,member); + _db->save(member); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; @@ -830,7 +829,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json network; _db->get(nwid,network); - json origNetwork(network); // for detecting changes DB::initNetwork(network); try { @@ -1061,7 +1059,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["nwid"] = nwids; // legacy DB::cleanNetwork(network); - _db->save(&origNetwork,network); + _db->save(network); responseBody = OSUtils::jsonDump(network); responseContentType = "application/json"; @@ -1184,7 +1182,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) d["objtype"] = "trace"; d["ts"] = now; d["nodeId"] = Utils::hex10(rt.origin,tmp); - _db->save((nlohmann::json *)0,d); + _db->save(d); } catch ( ... ) { // drop invalid trace messages if an error occurs } @@ -1235,7 +1233,7 @@ void EmbeddedNetworkController::_request( { char nwids[24]; DB::NetworkSummaryInfo ns; - json network,member,origMember; + json network,member; if (!_db) return; @@ -1261,7 +1259,6 @@ void EmbeddedNetworkController::_request( _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND); return; } - origMember = member; const bool newMember = ((!member.is_object())||(member.size() == 0)); DB::initMember(member); @@ -1362,7 +1359,7 @@ void EmbeddedNetworkController::_request( } else { // If they are not authorized, STOP! DB::cleanMember(member); - _db->save(&origMember,member); + _db->save(member); _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } @@ -1734,7 +1731,7 @@ void EmbeddedNetworkController::_request( } DB::cleanMember(member); - _db->save(&origMember,member); + _db->save(member); _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp index acc8680e6..66b3d2c2e 100644 --- a/controller/FileDB.cpp +++ b/controller/FileDB.cpp @@ -85,38 +85,35 @@ FileDB::~FileDB() bool FileDB::waitForReady() { return true; } bool FileDB::isReady() { return true; } -void FileDB::save(nlohmann::json *orig,nlohmann::json &record) +void FileDB::save(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)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; 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)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; 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))) { @@ -129,12 +126,7 @@ void FileDB::save(nlohmann::json *orig,nlohmann::json &record) _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 } diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp index 33efb7257..deef88546 100644 --- a/controller/FileDB.hpp +++ b/controller/FileDB.hpp @@ -40,7 +40,7 @@ public: virtual bool waitForReady(); virtual bool isReady(); - virtual void save(nlohmann::json *orig,nlohmann::json &record); + virtual void save(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); diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp index 9203a5a18..5bf0aaf79 100644 --- a/controller/LFDB.cpp +++ b/controller/LFDB.cpp @@ -335,16 +335,8 @@ bool LFDB::isReady() return (_ready.load()); } -void LFDB::save(nlohmann::json *orig,nlohmann::json &record) +void LFDB::save(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); @@ -352,6 +344,7 @@ void LFDB::save(nlohmann::json *orig,nlohmann::json &record) nlohmann::json old; get(nwid,old); if ((!old.is_object())||(old != record)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; _networkChanged(old,record,true); { std::lock_guard l(_state_l); @@ -366,6 +359,7 @@ void LFDB::save(nlohmann::json *orig,nlohmann::json &record) nlohmann::json network,old; get(nwid,network,id,old); if ((!old.is_object())||(old != record)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; _memberChanged(old,record,true); { std::lock_guard l(_state_l); diff --git a/controller/LFDB.hpp b/controller/LFDB.hpp index 731874626..646da65df 100644 --- a/controller/LFDB.hpp +++ b/controller/LFDB.hpp @@ -56,7 +56,7 @@ public: virtual bool waitForReady(); virtual bool isReady(); - virtual void save(nlohmann::json *orig,nlohmann::json &record); + virtual void save(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); diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 45be3e518..121d00df8 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -165,12 +165,35 @@ bool PostgreSQL::isReady() return ((_ready == 2)&&(_connected)); } -void PostgreSQL::save(nlohmann::json *orig, nlohmann::json &record) +void PostgreSQL::save(nlohmann::json &record) { try { - if (!record.is_object()) { + if (!record.is_object()) return; + 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)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _commitQueue.post(new nlohmann::json(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)) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _commitQueue.post(new nlohmann::json(record)); + } + } } + /* waitForReady(); if (orig) { if (*orig != record) { @@ -181,6 +204,7 @@ void PostgreSQL::save(nlohmann::json *orig, nlohmann::json &record) record["revision"] = 1; _commitQueue.post(new nlohmann::json(record)); } + */ } catch (std::exception &e) { fprintf(stderr, "Error on PostgreSQL::save: %s\n", e.what()); } catch (...) { diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp index fe69635d1..ce6fb2428 100644 --- a/controller/PostgreSQL.hpp +++ b/controller/PostgreSQL.hpp @@ -23,16 +23,14 @@ * directly against ZeroTier software without disclosing the source code * of your own application. */ - -#define ZT_CONTROLLER_USE_LIBPQ + +#include "DB.hpp" #ifdef ZT_CONTROLLER_USE_LIBPQ #ifndef ZT_CONTROLLER_LIBPQ_HPP #define ZT_CONTROLLER_LIBPQ_HPP -#include "DB.hpp" - #define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4 extern "C" { @@ -57,7 +55,7 @@ public: virtual bool waitForReady(); virtual bool isReady(); - virtual void save(nlohmann::json *orig, nlohmann::json &record); + virtual void save(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); diff --git a/controller/RabbitMQ.cpp b/controller/RabbitMQ.cpp index cf5c567d7..e14fbf3f2 100644 --- a/controller/RabbitMQ.cpp +++ b/controller/RabbitMQ.cpp @@ -1,3 +1,30 @@ +/* + * 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 . + * + * -- + * + * 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 "RabbitMQ.hpp" #ifdef ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/RabbitMQ.hpp b/controller/RabbitMQ.hpp index 6bac68daa..c8ef31ca5 100644 --- a/controller/RabbitMQ.hpp +++ b/controller/RabbitMQ.hpp @@ -27,6 +27,8 @@ #ifndef ZT_CONTROLLER_RABBITMQ_HPP #define ZT_CONTROLLER_RABBITMQ_HPP +#include "DB.hpp" + namespace ZeroTier { struct MQConfig {