blob: dde85eb0a92c1abaf091c4ba3b824ddd620bf183 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2015 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* ndn-cxx library 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 Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#include "face.hpp"
#include "detail/face-impl.hpp"
#include "encoding/tlv.hpp"
#include "security/key-chain.hpp"
#include "security/signing-helpers.hpp"
#include "util/time.hpp"
#include "util/random.hpp"
#include "util/face-uri.hpp"
#include "ns3/node-list.h"
#include "ns3/ndnSIM/helper/ndn-stack-helper.hpp"
#include "ns3/ndnSIM/NFD/daemon/face/generic-link-service.hpp"
#include "ns3/ndnSIM/NFD/daemon/face/internal-transport.hpp"
namespace ndn {
Face::Face()
: m_impl(new Impl(*this))
{
construct(nullptr, ns3::ndn::StackHelper::getKeyChain());
}
Face::Face(boost::asio::io_service& ioService)
: m_impl(new Impl(*this))
{
construct(nullptr, ns3::ndn::StackHelper::getKeyChain());
}
Face::Face(shared_ptr<Transport> transport)
: m_impl(new Impl(*this))
{
construct(transport, ns3::ndn::StackHelper::getKeyChain());
}
Face::Face(shared_ptr<Transport> transport,
boost::asio::io_service& ioService)
: m_impl(new Impl(*this))
{
construct(transport, ns3::ndn::StackHelper::getKeyChain());
}
Face::Face(shared_ptr<Transport> transport,
boost::asio::io_service& ioService,
KeyChain& keyChain)
: m_impl(new Impl(*this))
{
construct(transport, keyChain);
}
shared_ptr<Transport>
Face::makeDefaultTransport()
{
ns3::Ptr<ns3::Node> node = ns3::NodeList::GetNode(ns3::Simulator::GetContext());
NS_ASSERT_MSG(node->GetObject<ns3::ndn::L3Protocol>() != 0,
"NDN stack should be installed on the node " << node);
auto uri = ::nfd::FaceUri("ndnFace://" + boost::lexical_cast<std::string>(node->GetId()));
::nfd::face::GenericLinkService::Options serviceOpts;
serviceOpts.allowLocalFields = true;
auto nfdFace = make_shared<::nfd::Face>(make_unique<::nfd::face::GenericLinkService>(serviceOpts),
make_unique<::nfd::face::InternalForwarderTransport>(uri, uri));
auto forwarderTransport = static_cast<::nfd::face::InternalForwarderTransport*>(nfdFace->getTransport());
auto clientTransport = make_shared<::nfd::face::InternalClientTransport>();
clientTransport->connectToForwarder(forwarderTransport);
node->GetObject<ns3::ndn::L3Protocol>()->addFace(nfdFace);;
return clientTransport;
}
void
Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
{
if (transport == nullptr) {
transport = makeDefaultTransport();
}
BOOST_ASSERT(transport != nullptr);
m_transport = transport;
m_nfdController.reset(new nfd::Controller(*this, keyChain));
}
Face::~Face() = default;
shared_ptr<Transport>
Face::getTransport()
{
return m_transport;
}
const PendingInterestId*
Face::expressInterest(const Interest& interest,
const DataCallback& afterSatisfied,
const NackCallback& afterNacked,
const TimeoutCallback& afterTimeout)
{
shared_ptr<Interest> interestToExpress = make_shared<Interest>(interest);
// Use `interestToExpress` to avoid wire format creation for the original Interest
if (interestToExpress->wireEncode().size() > MAX_NDN_PACKET_SIZE) {
BOOST_THROW_EXCEPTION(Error("Interest size exceeds maximum limit"));
}
// If the same ioService thread, dispatch directly calls the method
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
m_impl->asyncExpressInterest(interestToExpress, afterSatisfied,
afterNacked, afterTimeout);
});
return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
}
const PendingInterestId*
Face::expressInterest(const Interest& interest,
const OnData& onData,
const OnTimeout& onTimeout)
{
return this->expressInterest(
interest,
[onData] (const Interest& interest, const Data& data) {
if (onData != nullptr) {
onData(interest, const_cast<Data&>(data));
}
},
[onTimeout] (const Interest& interest, const lp::Nack& nack) {
if (onTimeout != nullptr) {
onTimeout(interest);
}
},
onTimeout
);
}
const PendingInterestId*
Face::expressInterest(const Name& name,
const Interest& tmpl,
const OnData& onData, const OnTimeout& onTimeout/* = nullptr*/)
{
return expressInterest(Interest(tmpl)
.setName(name)
.setNonce(0),
onData, onTimeout);
}
void
Face::put(const Data& data)
{
// Use original `data`, since wire format should already exist for the original Data
if (data.wireEncode().size() > MAX_NDN_PACKET_SIZE)
BOOST_THROW_EXCEPTION(Error("Data size exceeds maximum limit"));
shared_ptr<const Data> dataPtr;
try {
dataPtr = data.shared_from_this();
}
catch (const bad_weak_ptr& e) {
std::cerr << "Face::put WARNING: the supplied Data should be created using make_shared<Data>()"
<< std::endl;
dataPtr = make_shared<Data>(data);
}
// If the same ioService thread, dispatch directly calls the method
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncPutData(dataPtr); });
}
void
Face::put(const lp::Nack& nack)
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncPutNack(make_shared<lp::Nack>(nack)); });
}
void
Face::removePendingInterest(const PendingInterestId* pendingInterestId)
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncRemovePendingInterest(pendingInterestId); });
}
void
Face::removeAllPendingInterests()
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncRemoveAllPendingInterests(); });
}
size_t
Face::getNPendingInterests() const
{
return m_impl->m_pendingInterestTable.size();
}
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixFailureCallback& onFailure,
const security::SigningInfo& signingInfo,
uint64_t flags)
{
return setInterestFilter(interestFilter,
onInterest,
RegisterPrefixSuccessCallback(),
onFailure,
signingInfo,
flags);
}
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const security::SigningInfo& signingInfo,
uint64_t flags)
{
shared_ptr<InterestFilterRecord> filter =
make_shared<InterestFilterRecord>(interestFilter, onInterest);
nfd::CommandOptions options;
options.setSigningInfo(signingInfo);
return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
onSuccess, onFailure,
flags, options);
}
const InterestFilterId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest)
{
shared_ptr<InterestFilterRecord> filter =
make_shared<InterestFilterRecord>(interestFilter, onInterest);
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
m_impl->asyncSetInterestFilter(filter);
});
return reinterpret_cast<const InterestFilterId*>(filter.get());
}
#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const IdentityCertificate& certificate,
uint64_t flags)
{
security::SigningInfo signingInfo;
if (!certificate.getName().empty()) {
signingInfo = signingByCertificate(certificate.getName());
}
return setInterestFilter(interestFilter, onInterest,
onSuccess, onFailure,
signingInfo, flags);
}
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixFailureCallback& onFailure,
const IdentityCertificate& certificate,
uint64_t flags)
{
security::SigningInfo signingInfo;
if (!certificate.getName().empty()) {
signingInfo = signingByCertificate(certificate.getName());
}
return setInterestFilter(interestFilter, onInterest,
onFailure, signingInfo, flags);
}
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const Name& identity,
uint64_t flags)
{
security::SigningInfo signingInfo = signingByIdentity(identity);
return setInterestFilter(interestFilter, onInterest,
onSuccess, onFailure,
signingInfo, flags);
}
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const RegisterPrefixFailureCallback& onFailure,
const Name& identity,
uint64_t flags)
{
security::SigningInfo signingInfo = signingByIdentity(identity);
return setInterestFilter(interestFilter, onInterest,
onFailure, signingInfo, flags);
}
#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
const RegisteredPrefixId*
Face::registerPrefix(const Name& prefix,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const security::SigningInfo& signingInfo,
uint64_t flags)
{
nfd::CommandOptions options;
options.setSigningInfo(signingInfo);
return m_impl->registerPrefix(prefix, shared_ptr<InterestFilterRecord>(),
onSuccess, onFailure,
flags, options);
}
#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
const RegisteredPrefixId*
Face::registerPrefix(const Name& prefix,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const IdentityCertificate& certificate,
uint64_t flags)
{
security::SigningInfo signingInfo;
if (!certificate.getName().empty()) {
signingInfo = signingByCertificate(certificate.getName());
}
return registerPrefix(prefix, onSuccess,
onFailure, signingInfo, flags);
}
const RegisteredPrefixId*
Face::registerPrefix(const Name& prefix,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
const Name& identity,
uint64_t flags)
{
security::SigningInfo signingInfo = signingByIdentity(identity);
return registerPrefix(prefix, onSuccess,
onFailure, signingInfo, flags);
}
#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
void
Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,
UnregisterPrefixSuccessCallback(),
UnregisterPrefixFailureCallback()); });
}
void
Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnsetInterestFilter(interestFilterId); });
}
void
Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
const UnregisterPrefixSuccessCallback& onSuccess,
const UnregisterPrefixFailureCallback& onFailure)
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,onSuccess, onFailure); });
}
void
Face::processEvents(const time::milliseconds& timeout/* = time::milliseconds::zero()*/,
bool keepThread/* = false*/)
{
}
void
Face::shutdown()
{
m_impl->m_scheduler.scheduleEvent(time::seconds(0), [this] { this->asyncShutdown(); });
}
void
Face::asyncShutdown()
{
m_impl->m_pendingInterestTable.clear();
m_impl->m_registeredPrefixTable.clear();
if (m_transport->isConnected())
m_transport->close();
}
/**
* @brief extract local fields from NDNLPv2 packet and tag onto a network layer packet
*/
template<typename NETPKT>
static void
extractLpLocalFields(NETPKT& netPacket, const lp::Packet& lpPacket)
{
if (lpPacket.has<lp::IncomingFaceIdField>()) {
netPacket.setTag(make_shared<lp::IncomingFaceIdTag>(lpPacket.get<lp::IncomingFaceIdField>()));
}
}
void
Face::onReceiveElement(const Block& blockFromDaemon)
{
lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
// no need to distinguish
Buffer::const_iterator begin, end;
std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
Block netPacket(&*begin, std::distance(begin, end));
switch (netPacket.type()) {
case tlv::Interest: {
shared_ptr<Interest> interest = make_shared<Interest>(netPacket);
if (lpPacket.has<lp::NackField>()) {
auto nack = make_shared<lp::Nack>(std::move(*interest));
nack->setHeader(lpPacket.get<lp::NackField>());
extractLpLocalFields(*nack, lpPacket);
m_impl->nackPendingInterests(*nack);
}
else {
extractLpLocalFields(*interest, lpPacket);
m_impl->processInterestFilters(*interest);
}
break;
}
case tlv::Data: {
shared_ptr<Data> data = make_shared<Data>(netPacket);
extractLpLocalFields(*data, lpPacket);
m_impl->satisfyPendingInterests(*data);
break;
}
}
}
} // namespace ndn