From 7e7e28f5f7d53df8f4897b243088d2f664651ae6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 17 Oct 2013 05:37:01 -0400 Subject: Add support for pushing network config refresh hints from a MEMORY queue table. That ways it will be possible for network changes to take effect almost immediately across all active peers. --- netconf-service/netconf.cpp | 34 ++++++++++++++++++++++++++++++++++ node/Node.cpp | 28 ++++++++++++++++++++++++++++ node/Packet.hpp | 4 +--- node/PacketDecoder.cpp | 20 ++++++++++++++++---- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/netconf-service/netconf.cpp b/netconf-service/netconf.cpp index 2596a6f9..7c8bcb6e 100644 --- a/netconf-service/netconf.cpp +++ b/netconf-service/netconf.cpp @@ -158,6 +158,40 @@ int main(int argc,char **argv) return -1; } + // Check QNetworkConfigRefresh (MEMORY table) and push network + // config refreshes to queued peer/network pairs. + try { + Dictionary to; + { + Query q = dbCon->query(); + q << "SELECT LOWER(HEX(Node_id)) AS Node_id,LOWER(HEX(Network_id)) AS Network_id FROM QNetworkConfigRefresh"; + StoreQueryResult rs = q.store(); + for(unsigned long i=0;iquery(); + q << "DELETE FROM QNetworkConfigRefresh"; + q.exec(); + } + + Dictionary response; + response["type"] = "netconf-push"; + response["to"] = to.toString(); + std::string respm = response.toString(); + uint32_t respml = (uint32_t)htonl((uint32_t)respm.length()); + + stdoutWriteLock.lock(); + write(STDOUT_FILENO,&respml,4); + write(STDOUT_FILENO,respm.data(),respm.length()); + stdoutWriteLock.unlock(); + } catch ( ... ) {} + try { const std::string &reqType = request.get("type"); if (reqType == "netconf-request") { // NETWORK_CONFIG_REQUEST packet diff --git a/node/Node.cpp b/node/Node.cpp index fe95701a..71d8b097 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -269,6 +269,34 @@ static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictiona } } } + } else if (type == "netconf-push") { + if (msg.contains("to")) { + Dictionary to(msg.get("to")); // key: peer address, value: comma-delimited network list + for(Dictionary::iterator t(to.begin());t!=to.end();++t) { + Address ztaddr(t->first); + if (ztaddr) { + Packet outp(ztaddr,_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH); + + char *saveptr = (char *)0; + // Note: this loop trashes t->second, which is quasi-legal C++ but + // shouldn't break anything as long as we don't try to use 'to' + // for anything interesting after doing this. + for(char *p=Utils::stok(const_cast(t->second.c_str()),",",&saveptr);(p);p=Utils::stok((char *)0,",",&saveptr)) { + uint64_t nwid = Utils::hexStrToU64(p); + if (nwid) { + if ((outp.size() + sizeof(uint64_t)) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) { + _r->sw->send(outp,true); + outp.reset(ztaddr,_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH); + } + outp.append(nwid); + } + } + + if (outp.payloadLength()) + _r->sw->send(outp,true); + } + } + } } } catch (std::exception &exc) { LOG("unexpected exception parsing response from netconf service: %s",exc.what()); diff --git a/node/Packet.hpp b/node/Packet.hpp index 36740835..4f139de8 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -205,8 +205,6 @@ #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REFRESH_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) - #define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD) #define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8) #define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1) @@ -592,7 +590,7 @@ public: VERB_NETWORK_CONFIG_REQUEST = 11, /* Network configuration refresh request: - * <[8] 64-bit network ID> + * <[...] array of 64-bit network IDs> * * This message can be sent by the network configuration master node * to request that nodes refresh their network configuration. It can diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 2bc61ed0..a8a55602 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -140,6 +140,10 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr if (inReVerb == Packet::VERB_WHOIS) { if (_r->topology->isSupernode(source())) _r->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); + } else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { + SharedPtr network(_r->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->controller() == source())) + network->forceStatusTo(Network::NETWORK_NOT_FOUND); } break; case Packet::ERROR_IDENTITY_COLLISION: @@ -154,6 +158,11 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr if (network) network->pushMembershipCertificate(source(),true,Utils::now()); } break; + case Packet::ERROR_NETWORK_ACCESS_DENIED: { + SharedPtr network(_r->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->controller() == source())) + network->forceStatusTo(Network::NETWORK_ACCESS_DENIED); + } break; default: break; } @@ -732,10 +741,13 @@ bool PacketDecoder::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const bool PacketDecoder::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *_r,const SharedPtr &peer) { try { - uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REFRESH_IDX_NETWORK_ID); - SharedPtr nw(_r->nc->network(nwid)); - if ((nw)&&(source() == nw->controller())) // only respond to requests from controller - nw->requestConfiguration(); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; + while ((ptr + sizeof(uint64_t)) <= size()) { + uint64_t nwid = at(ptr); ptr += sizeof(uint64_t); + SharedPtr nw(_r->nc->network(nwid)); + if ((nw)&&(source() == nw->controller())) // only respond to requests from controller + nw->requestConfiguration(); + } } catch (std::exception &exc) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { -- cgit v1.2.3