diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-05-01 13:21:26 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-05-01 13:21:26 -0700 |
commit | 718e1d6c082453bfbab8b900f5ffde42047fc814 (patch) | |
tree | bd344066a515f2f195093dda6e84b9530d686006 | |
parent | a9ce77358484e41cd6bac42594e4eeb045a788cb (diff) | |
download | infinitytier-718e1d6c082453bfbab8b900f5ffde42047fc814.tar.gz infinitytier-718e1d6c082453bfbab8b900f5ffde42047fc814.zip |
Finish removing constantly changing stuff from controller.
-rw-r--r-- | controller/EmbeddedNetworkController.cpp | 160 | ||||
-rw-r--r-- | controller/EmbeddedNetworkController.hpp | 34 | ||||
-rw-r--r-- | controller/JSONDB.hpp | 13 | ||||
-rw-r--r-- | controller/README.md | 22 | ||||
-rw-r--r-- | node/Dictionary.hpp | 2 |
5 files changed, 143 insertions, 88 deletions
diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 70640ff5..3ec02454 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -518,7 +518,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( json member; if (!_db.getNetworkMember(nwid,address,member)) return 404; - _addMemberNonPersistedFields(member,OSUtils::now()); + _addMemberNonPersistedFields(nwid,address,member,OSUtils::now()); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; } else { @@ -569,6 +569,26 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( } // else 404 + } else if ((path.size() == 1)&&(path[0] == "memberStatus")) { + + const uint64_t now = OSUtils::now(); + Mutex::Lock _l(_memberStatus_m); + responseBody.push_back('{'); + _db.eachId([this,&responseBody,&now](uint64_t networkId,uint64_t nodeId) { + char tmp[64]; + auto ms = this->_memberStatus.find(_MemberStatusKey(networkId,nodeId)); + Utils::snprintf(tmp,sizeof(tmp),"%s\"%.16llx-%.10llx\":%s", + (responseBody.length() > 1) ? "," : "", + (unsigned long long)networkId, + (unsigned long long)nodeId, + ((ms != _memberStatus.end())&&(ms->second.online(now))) ? "true" : "false"); + responseBody.append(tmp); + }); + responseBody.push_back('}'); + responseContentType = "application/json"; + + return 200; + } else { char tmp[4096]; @@ -649,10 +669,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (!newAuth) { Revocation rev((uint32_t)_node->prng(),nwid,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(address),Revocation::CREDENTIAL_TYPE_COM); rev.sign(_signingId); - Mutex::Lock _l(_lastRequestTime_m); - for(std::map< std::pair<uint64_t,uint64_t>,uint64_t >::iterator i(_lastRequestTime.begin());i!=_lastRequestTime.end();++i) { - if ((now - i->second) < ZT_NETWORK_AUTOCONF_DELAY) - _node->ncSendRevocation(Address(i->first.first),rev); + + Mutex::Lock _l(_memberStatus_m); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == nwid)&&(i->second.online(now))) + _node->ncSendRevocation(Address(i->first.nodeId),rev); } } } @@ -720,10 +741,17 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &revj = member["revision"]; member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetworkMember(nwid,address,member); - _pushMemberUpdate(now,nwid,member); + + // Push update to member if online + try { + Mutex::Lock _l(_memberStatus_m); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,address)]; + if ((ms.online(now))&&(ms.lastRequestMetaData)) + request(nwid,InetAddress(),0,ms.identity,ms.lastRequestMetaData); + } catch ( ... ) {} } - _addMemberNonPersistedFields(member,now); + _addMemberNonPersistedFields(nwid,address,member,now); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; @@ -1022,10 +1050,12 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetwork(nwid,network); - // Send an update to all members of the network - _db.eachMember(nwid,[this,&now,&nwid](uint64_t networkId,uint64_t nodeId,const json &obj) { - this->_pushMemberUpdate(now,nwid,obj); - }); + // Send an update to all members of the network that are online + Mutex::Lock _l(_memberStatus_m); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == nwid)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) + request(nwid,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData); + } } JSONDB::NetworkSummaryInfo ns; @@ -1044,7 +1074,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json testRec; const uint64_t now = OSUtils::now(); testRec["clock"] = now; - testRec["uptime"] = (now - _startTime); + testRec["startTime"] = _startTime; testRec["content"] = b; responseBody = OSUtils::jsonDump(testRec); _db.writeRaw("pong",responseBody); @@ -1075,6 +1105,12 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( const uint64_t address = Utils::hexStrToU64(path[3].c_str()); json member = _db.eraseNetworkMember(nwid,address); + + { + Mutex::Lock _l(_memberStatus_m); + _memberStatus.erase(_MemberStatusKey(nwid,address)); + } + if (!member.size()) return 404; responseBody = OSUtils::jsonDump(member); @@ -1083,6 +1119,16 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( } } else { json network = _db.eraseNetwork(nwid); + + { + Mutex::Lock _l(_memberStatus_m); + 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); @@ -1106,6 +1152,7 @@ void EmbeddedNetworkController::threadMain() _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); } catch ( ... ) {} delete qe; + if (_running) { uint64_t now = OSUtils::now(); if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { @@ -1196,11 +1243,11 @@ void EmbeddedNetworkController::_request( const uint64_t now = OSUtils::now(); if (requestPacketId) { - Mutex::Lock _l(_lastRequestTime_m); - uint64_t &lrt = _lastRequestTime[std::pair<uint64_t,uint64_t>(identity.address().toInt(),nwid)]; - if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD) + Mutex::Lock _l(_memberStatus_m); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + if ((now - ms.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD) return; - lrt = now; + ms.lastRequestTime = now; } Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); @@ -1315,37 +1362,37 @@ void EmbeddedNetworkController::_request( member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); } - // Log this request - if (requestPacketId) { // only log if this is a request, not for generated pushes - json rlEntry = json::object(); - rlEntry["ts"] = now; - rlEntry["auth"] = (authorizedBy) ? true : false; - rlEntry["authBy"] = (authorizedBy) ? authorizedBy : ""; - rlEntry["vMajor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); - rlEntry["vMinor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); - rlEntry["vRev"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); - rlEntry["vProto"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); - if (fromAddr) - rlEntry["fromAddr"] = fromAddr.toString(); - - json recentLog = json::array(); - recentLog.push_back(rlEntry); - json &oldLog = member["recentLog"]; - if (oldLog.is_array()) { - for(unsigned long i=0;i<oldLog.size();++i) { - recentLog.push_back(oldLog[i]); - if (recentLog.size() >= ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH) - break; - } - } - member["recentLog"] = recentLog; + if (authorizedBy) { + // Update version info and meta-data if authorized and if this is a genuine request + if (requestPacketId) { + const uint64_t vMajor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); + const uint64_t vMinor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); + const uint64_t vRev = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); + const uint64_t vProto = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); - // Also only do this on real requests - member["lastRequestMetaData"] = metaData.data(); - } + member["vMajor"] = vMajor; + member["vMinor"] = vMinor; + member["vRev"] = vRev; + member["vProto"] = vProto; - // If they are not authorized, STOP! - if (!authorizedBy) { + { + Mutex::Lock _l(_memberStatus_m); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + + ms.vMajor = (int)vMajor; + ms.vMinor = (int)vMinor; + ms.vRev = (int)vRev; + ms.vProto = (int)vProto; + ms.lastRequestMetaData = metaData; + ms.identity = identity; + + if (fromAddr) + ms.physicalAddr = fromAddr; + member["physicalAddr"] = ms.physicalAddr.toString(); + } + } + } else { + // If they are not authorized, STOP! _removeMemberNonPersistedFields(member); if (origMember != member) _db.saveNetworkMember(nwid,identity.address().toInt(),member); @@ -1702,27 +1749,4 @@ void EmbeddedNetworkController::_request( _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } -void EmbeddedNetworkController::_pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member) -{ - try { - const std::string idstr = member["identity"]; - const std::string mdstr = member["lastRequestMetaData"]; - if ((idstr.length() > 0)&&(mdstr.length() > 0)) { - const Identity id(idstr); - bool online; - { - Mutex::Lock _l(_lastRequestTime_m); - std::map< std::pair<uint64_t,uint64_t>,uint64_t >::iterator lrt(_lastRequestTime.find(std::pair<uint64_t,uint64_t>(id.address().toInt(),nwid))); - online = ( (lrt != _lastRequestTime.end()) && ((now - lrt->second) < ZT_NETWORK_AUTOCONF_DELAY) ); - } - if (online) { - Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData(mdstr.c_str()); - try { - this->request(nwid,InetAddress(),0,id,metaData); - } catch ( ... ) {} - } - } - } catch ( ... ) {} -} - } // namespace ZeroTier diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 64ea6884..faf7f029 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -107,7 +107,6 @@ private: static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData); - void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member); // These init objects with default and static/informational fields inline void _initMember(nlohmann::json &member) @@ -164,9 +163,11 @@ private: network.erase("activeMemberCount"); network.erase("totalMemberCount"); } - inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now) + inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,uint64_t now) { member["clock"] = now; + Mutex::Lock _l(_memberStatus_m); + member["online"] = _memberStatus[_MemberStatusKey(nwid,nodeId)].online(now); } inline void _removeMemberNonPersistedFields(nlohmann::json &member) { @@ -191,8 +192,33 @@ private: std::list< ZT_CircuitTest > _tests; Mutex _tests_m; - std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime; // last request time by <address,networkId> - Mutex _lastRequestTime_m; + struct _MemberStatusKey + { + _MemberStatusKey() : networkId(0),nodeId(0) {} + _MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {} + uint64_t networkId; + uint64_t nodeId; + inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } + }; + struct _MemberStatus + { + _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} + uint64_t lastRequestTime; + int vMajor,vMinor,vRev,vProto; + Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData; + Identity identity; + InetAddress physicalAddr; // last known physical address + inline bool online(const uint64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } + }; + struct _MemberStatusHash + { + inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const + { + return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId); + } + }; + std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; + Mutex _memberStatus_m; }; } // namespace ZeroTier diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index ba16d97b..530f9632 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -107,6 +107,19 @@ public: } } + template<typename F> + inline void eachId(F func) + { + Mutex::Lock _l(_networks_m); + for(std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.begin());i!=_networks.end();++i) { + for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(i->second.members.begin());m!=i->second.members.end();++m) { + try { + func(i->first,m->first); + } catch ( ... ) {} + } + } + } + void threadMain() throw(); diff --git a/controller/README.md b/controller/README.md index db8d0153..3519eb11 100644 --- a/controller/README.md +++ b/controller/README.md @@ -227,22 +227,12 @@ This returns an object containing all currently online members and the most rece | activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES | | identity | string | Member's public ZeroTier identity (if known) | no | | ipAssignments | array[string] | Managed IP address assignments | YES | -| memberRevision | integer | Member revision counter | no | -| recentLog | array[object] | Recent member activity log; see below | no | +| revision | integer | Member revision counter | no | +| vMajor | integer | Most recently known major version | no | +| vMinor | integer | Most recently known minor version | no | +| vRev | integer | Most recently known revision | no | +| vProto | integer | Most recently known protocl version | no | +| physicalAddr | string | Last known physical IP/port or null if none | no | Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored. -**Recent log object format:** - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| ts | integer | Time of request, ms since epoch | -| auth | boolean | Was member authorized? | -| authBy | string | How was member authorized? | -| vMajor | integer | Client major version or -1 if unknown | -| vMinor | integer | Client minor version or -1 if unknown | -| vRev | integer | Client revision or -1 if unknown | -| vProto | integer | ZeroTier protocol version reported by client | -| fromAddr | string | Physical address if known | - -The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead. diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index e212e453..4413d628 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -99,6 +99,8 @@ public: return *this; } + inline operator bool() const { return (_d[0] != 0); } + /** * Load a dictionary from a C-string * |