| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /** |
| * Copyright (c) 2014, Regents of the University of California, |
| * Arizona Board of Regents, |
| * Colorado State University, |
| * University Pierre & Marie Curie, Sorbonne University, |
| * Washington University in St. Louis, |
| * Beijing Institute of Technology, |
| * The University of Memphis |
| * |
| * This file is part of NFD (Named Data Networking Forwarding Daemon). |
| * See AUTHORS.md for complete list of NFD authors and contributors. |
| * |
| * NFD 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. |
| * |
| * NFD 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 |
| * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "remote-registrator.hpp" |
| #include "core/logger.hpp" |
| #include "core/scheduler.hpp" |
| |
| namespace nfd { |
| namespace rib { |
| |
| NFD_LOG_INIT("RemoteRegistrator"); |
| |
| using ndn::nfd::ControlParameters; |
| using ndn::nfd::CommandOptions; |
| |
| const Name RemoteRegistrator::LOCAL_REGISTRATION_PREFIX = "/localhost"; |
| const Name RemoteRegistrator::REMOTE_HUB_PREFIX = "/localhop/nfd"; |
| const name::Component RemoteRegistrator::IGNORE_COMMPONENT("rib"); |
| |
| RemoteRegistrator::RemoteRegistrator(ndn::nfd::Controller& controller, |
| ndn::KeyChain& keyChain, |
| Rib& rib) |
| : m_nfdController(controller) |
| , m_keyChain(keyChain) |
| , m_rib(rib) |
| , m_refreshInterval(time::seconds(25)) |
| , m_hasConnectedHub(false) |
| , m_nRetries(0) |
| { |
| } |
| |
| RemoteRegistrator::~RemoteRegistrator() |
| { |
| // cancel all periodically refresh events. |
| for (auto&& entry : m_regEntries) |
| { |
| scheduler::cancel(entry.second); |
| } |
| } |
| |
| void |
| RemoteRegistrator::loadConfig(const ConfigSection& configSection) |
| { |
| size_t cost = 15, timeout = 10000; |
| size_t retry = 0; |
| size_t interval = 0; |
| const size_t intervalDef = 25, intervalMax = 600; |
| |
| NFD_LOG_INFO("Load remote_register section in rib section"); |
| for (auto&& i : configSection) |
| { |
| if (i.first == "cost") |
| { |
| cost = i.second.get_value<size_t>(); |
| } |
| else if (i.first == "timeout") |
| { |
| timeout = i.second.get_value<size_t>(); |
| } |
| else if (i.first == "retry") |
| { |
| retry = i.second.get_value<size_t>(); |
| } |
| else if (i.first == "refresh_interval") |
| { |
| interval = i.second.get_value<size_t>(); |
| } |
| else |
| { |
| throw ConfigFile::Error("Unrecognized option \"" + i.first + |
| "\" in \"remote-registrator\" section"); |
| } |
| } |
| |
| m_controlParameters |
| .setCost(cost) |
| .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client. |
| .setFaceId(0);// the remote hub will take the input face as the faceId. |
| |
| m_commandOptions |
| .setPrefix(REMOTE_HUB_PREFIX) |
| .setTimeout(time::milliseconds(timeout)); |
| |
| m_nRetries = retry; |
| |
| if (interval == 0) |
| { |
| interval = intervalDef; |
| } |
| |
| interval = std::min(interval, intervalMax); |
| |
| m_refreshInterval = time::seconds(interval); |
| } |
| |
| void |
| RemoteRegistrator::enable() |
| { |
| // do remote registration after an entry is inserted into the RIB. |
| m_afterInsertConnection = |
| m_rib.afterInsertEntry.connect([this] (const Name& prefix) { |
| registerPrefix(prefix); |
| }); |
| |
| // do remote unregistration after an entry is erased from the RIB. |
| m_afterEraseConnection = |
| m_rib.afterEraseEntry.connect([this] (const Name& prefix) { |
| unregisterPrefix(prefix); |
| }); |
| } |
| |
| void |
| RemoteRegistrator::disable() |
| { |
| m_afterInsertConnection.disconnect(); |
| m_afterEraseConnection.disconnect(); |
| } |
| |
| void |
| RemoteRegistrator::registerPrefix(const Name& prefix) |
| { |
| if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) |
| { |
| NFD_LOG_INFO("local registration only for " << prefix); |
| return; |
| } |
| |
| bool isHubPrefix = prefix == REMOTE_HUB_PREFIX; |
| |
| if (isHubPrefix) |
| { |
| NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix); |
| |
| m_hasConnectedHub = true; |
| |
| redoRegistration(); |
| return; |
| } |
| |
| if (!m_hasConnectedHub) |
| { |
| NFD_LOG_INFO("no hub connected when registering " << prefix); |
| return; |
| } |
| |
| std::pair<Name, size_t> identity = findIdentityForRegistration(prefix); |
| |
| if (0 == identity.second) |
| { |
| NFD_LOG_INFO("no proper identity found for registering " << prefix); |
| return; |
| } |
| |
| Name prefixForRegistration; |
| if (identity.first.size() == identity.second) |
| { |
| prefixForRegistration = identity.first; |
| } |
| else |
| { |
| prefixForRegistration = identity.first.getPrefix(-1); |
| } |
| |
| if (m_regEntries.find(prefixForRegistration) != m_regEntries.end()) |
| { |
| NFD_LOG_INFO("registration already in process for " << prefix); |
| return; |
| } |
| |
| // make copies of m_controlParameters and m_commandOptions to |
| // avoid unreasonable overwriting during concurrent registration |
| // and unregistration. |
| ControlParameters parameters = m_controlParameters; |
| CommandOptions options = m_commandOptions; |
| |
| startRegistration(parameters.setName(prefixForRegistration), |
| options.setSigningIdentity(identity.first), |
| m_nRetries); |
| } |
| |
| void |
| RemoteRegistrator::unregisterPrefix(const Name& prefix) |
| { |
| if (prefix == REMOTE_HUB_PREFIX) |
| { |
| NFD_LOG_INFO("disconnected to hub with prefix: " << prefix); |
| |
| // for phase 1: suppose there is at most one hub connected. |
| // if the hub prefix has been unregistered locally, there may |
| // be no connected hub. |
| m_hasConnectedHub = false; |
| |
| clearRefreshEvents(); |
| return; |
| } |
| |
| if (!m_hasConnectedHub) |
| { |
| NFD_LOG_INFO("no hub connected when unregistering " << prefix); |
| return; |
| } |
| |
| std::pair<Name, size_t> identity = findIdentityForRegistration(prefix); |
| |
| if (0 == identity.second) |
| { |
| NFD_LOG_INFO("no proper identity found for unregistering " << prefix); |
| return; |
| } |
| |
| Name prefixForRegistration; |
| if (identity.first.size() == identity.second) |
| { |
| prefixForRegistration = identity.first; |
| } |
| else |
| { |
| prefixForRegistration = identity.first.getPrefix(-1); |
| } |
| |
| RegisteredEntryIt iRegEntry = m_regEntries.find(prefixForRegistration); |
| if (m_regEntries.end() == iRegEntry) |
| { |
| NFD_LOG_INFO("no existing entry found when unregistering " << prefix); |
| return; |
| } |
| |
| for (auto&& entry : m_rib) |
| { |
| if (prefixForRegistration.isPrefixOf(entry.first) && |
| findIdentityForRegistration(entry.first) == identity) |
| { |
| NFD_LOG_INFO("this identity should be kept for other rib entry: " |
| << entry.first); |
| return; |
| } |
| } |
| |
| scheduler::cancel(iRegEntry->second); |
| m_regEntries.erase(iRegEntry); |
| |
| // make copies of m_controlParameters and m_commandOptions to |
| // avoid unreasonable overwriting during concurrent registration |
| // and unregistration. |
| ControlParameters parameters = m_controlParameters; |
| CommandOptions options = m_commandOptions; |
| |
| startUnregistration(parameters.setName(prefixForRegistration).unsetCost(), |
| options.setSigningIdentity(identity.first), |
| m_nRetries); |
| } |
| |
| std::pair<Name, size_t> |
| RemoteRegistrator::findIdentityForRegistration(const Name& prefix) |
| { |
| std::pair<Name, size_t> candidateIdentity; |
| std::vector<Name> identities; |
| bool isPrefix = false; |
| size_t maxLength = 0, curLength = 0; |
| |
| // get all identies from the key-cahin except the default one. |
| m_keyChain.getAllIdentities(identities, false); |
| |
| // get the default identity. |
| identities.push_back(m_keyChain.getDefaultIdentity()); |
| |
| // longest prefix matching to all indenties. |
| for (auto&& i : identities) |
| { |
| if (!i.empty() && IGNORE_COMMPONENT == i.at(-1)) |
| { |
| isPrefix = i.getPrefix(-1).isPrefixOf(prefix); |
| curLength = i.size() - 1; |
| } |
| else |
| { |
| isPrefix = i.isPrefixOf(prefix); |
| curLength = i.size(); |
| } |
| |
| if (isPrefix && curLength > maxLength) |
| { |
| candidateIdentity.first = i; |
| maxLength = curLength; |
| } |
| } |
| |
| candidateIdentity.second = maxLength; |
| |
| return candidateIdentity; |
| } |
| |
| void |
| RemoteRegistrator::startRegistration(const ControlParameters& parameters, |
| const CommandOptions& options, |
| int nRetries) |
| { |
| NFD_LOG_INFO("start register " << parameters.getName()); |
| |
| m_nfdController.start<ndn::nfd::RibRegisterCommand>( |
| parameters, |
| bind(&RemoteRegistrator::onRegSuccess, |
| this, parameters, options), |
| bind(&RemoteRegistrator::onRegFailure, |
| this, _1, _2, parameters, options, nRetries), |
| options); |
| } |
| |
| void |
| RemoteRegistrator::startUnregistration(const ControlParameters& parameters, |
| const CommandOptions& options, |
| int nRetries) |
| { |
| NFD_LOG_INFO("start unregister " << parameters.getName()); |
| |
| m_nfdController.start<ndn::nfd::RibUnregisterCommand>( |
| parameters, |
| bind(&RemoteRegistrator::onUnregSuccess, |
| this, parameters, options), |
| bind(&RemoteRegistrator::onUnregFailure, |
| this, _1, _2, parameters, options, nRetries), |
| options); |
| } |
| |
| void |
| RemoteRegistrator::onRegSuccess(const ControlParameters& parameters, |
| const CommandOptions& options) |
| { |
| NFD_LOG_INFO("success to register " << parameters.getName()); |
| |
| RegisteredEntryIt iRegEntry = m_regEntries.find(parameters.getName()); |
| |
| if (m_regEntries.end() != iRegEntry) |
| { |
| NFD_LOG_DEBUG("Existing Entry: (" << iRegEntry->first |
| << ", " << iRegEntry->second |
| << ")"); |
| |
| scheduler::cancel(iRegEntry->second); |
| iRegEntry->second = scheduler::schedule( |
| m_refreshInterval, |
| bind(&RemoteRegistrator::startRegistration, |
| this, parameters, options, m_nRetries)); |
| } |
| else |
| { |
| NFD_LOG_DEBUG("New Entry"); |
| m_regEntries.insert(RegisteredEntry( |
| parameters.getName(), |
| scheduler::schedule( |
| m_refreshInterval, |
| bind(&RemoteRegistrator::startRegistration, |
| this, parameters, options, m_nRetries)))); |
| } |
| } |
| |
| void |
| RemoteRegistrator::onRegFailure(uint32_t code, const std::string& reason, |
| const ControlParameters& parameters, |
| const CommandOptions& options, |
| int nRetries) |
| { |
| NFD_LOG_INFO("fail to register " << parameters.getName() |
| << "\n\t reason:" << reason |
| << "\n\t remain retries:" << nRetries); |
| |
| if (nRetries > 0) |
| { |
| startRegistration(parameters, options, nRetries - 1); |
| } |
| } |
| |
| void |
| RemoteRegistrator::onUnregSuccess(const ControlParameters& parameters, |
| const CommandOptions& options) |
| { |
| NFD_LOG_INFO("success to unregister " << parameters.getName()); |
| } |
| |
| void |
| RemoteRegistrator::onUnregFailure(uint32_t code, const std::string& reason, |
| const ControlParameters& parameters, |
| const CommandOptions& options, |
| int nRetries) |
| { |
| NFD_LOG_INFO("fail to unregister " << parameters.getName() |
| << "\n\t reason:" << reason |
| << "\n\t remain retries:" << nRetries); |
| |
| if (nRetries > 0) |
| { |
| startUnregistration(parameters, options, nRetries - 1); |
| } |
| } |
| |
| void |
| RemoteRegistrator::redoRegistration() |
| { |
| NFD_LOG_INFO("redo " << m_regEntries.size() |
| << " registration when new Hub connection is built."); |
| |
| for (auto&& entry : m_regEntries) |
| { |
| // make copies to avoid unreasonable overwrite. |
| ControlParameters parameters = m_controlParameters; |
| CommandOptions options = m_commandOptions; |
| startRegistration(parameters.setName(entry.first), |
| options.setSigningIdentity(entry.first), |
| m_nRetries); |
| } |
| } |
| |
| void |
| RemoteRegistrator::clearRefreshEvents() |
| { |
| for (auto&& entry : m_regEntries) |
| { |
| scheduler::cancel(entry.second); |
| } |
| } |
| |
| } // namespace rib |
| } // namespace nfd |