face.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2019 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
22 #include "ndn-cxx/face.hpp"
23 #include "ndn-cxx/encoding/tlv.hpp"
24 #include "ndn-cxx/impl/face-impl.hpp"
25 #include "ndn-cxx/net/face-uri.hpp"
27 #include "ndn-cxx/util/time.hpp"
28 
29 // NDN_LOG_INIT(ndn.Face) is declared in face-impl.hpp
30 
31 // A callback scheduled through io.post and io.dispatch may be invoked after the face is destructed.
32 // To prevent this situation, use these macros to capture Face::m_impl as weak_ptr and skip callback
33 // execution if the face has been destructed.
34 #define IO_CAPTURE_WEAK_IMPL(OP) \
35  { \
36  weak_ptr<Impl> implWeak(m_impl); \
37  m_ioService.OP([=] { \
38  auto impl = implWeak.lock(); \
39  if (impl != nullptr) {
40 #define IO_CAPTURE_WEAK_IMPL_END \
41  } \
42  }); \
43  }
44 
45 namespace ndn {
46 
47 Face::OversizedPacketError::OversizedPacketError(char pktType, const Name& name, size_t wireSize)
48  : Error((pktType == 'I' ? "Interest " : pktType == 'D' ? "Data " : "Nack ") +
49  name.toUri() + " encodes into " + to_string(wireSize) + " octets, "
50  "exceeding the implementation limit of " + to_string(MAX_NDN_PACKET_SIZE) + " octets")
51  , pktType(pktType)
52  , name(name)
53  , wireSize(wireSize)
54 {
55 }
56 
57 Face::Face(shared_ptr<Transport> transport)
58  : m_internalIoService(make_unique<boost::asio::io_service>())
59  , m_ioService(*m_internalIoService)
60  , m_internalKeyChain(make_unique<KeyChain>())
61 {
62  construct(std::move(transport), *m_internalKeyChain);
63 }
64 
65 Face::Face(boost::asio::io_service& ioService)
66  : m_ioService(ioService)
67  , m_internalKeyChain(make_unique<KeyChain>())
68 {
69  construct(nullptr, *m_internalKeyChain);
70 }
71 
72 Face::Face(const std::string& host, const std::string& port)
73  : m_internalIoService(make_unique<boost::asio::io_service>())
74  , m_ioService(*m_internalIoService)
75  , m_internalKeyChain(make_unique<KeyChain>())
76 {
77  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
78 }
79 
80 Face::Face(shared_ptr<Transport> transport, KeyChain& keyChain)
81  : m_internalIoService(make_unique<boost::asio::io_service>())
82  , m_ioService(*m_internalIoService)
83 {
84  construct(std::move(transport), keyChain);
85 }
86 
87 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService)
88  : m_ioService(ioService)
89  , m_internalKeyChain(make_unique<KeyChain>())
90 {
91  construct(std::move(transport), *m_internalKeyChain);
92 }
93 
94 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService, KeyChain& keyChain)
95  : m_ioService(ioService)
96 {
97  construct(std::move(transport), keyChain);
98 }
99 
100 shared_ptr<Transport>
101 Face::makeDefaultTransport()
102 {
103  // transport=unix:///var/run/nfd.sock
104  // transport=tcp://localhost:6363
105 
106  std::string transportUri;
107 
108  const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT");
109  if (transportEnviron != nullptr) {
110  transportUri = transportEnviron;
111  }
112  else {
113  ConfigFile config;
114  transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
115  }
116 
117  if (transportUri.empty()) {
118  // transport not specified, use default Unix transport.
119  return UnixTransport::create("");
120  }
121 
122  std::string protocol;
123  try {
124  FaceUri uri(transportUri);
125  protocol = uri.getScheme();
126 
127  if (protocol == "unix") {
128  return UnixTransport::create(transportUri);
129  }
130  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
131  return TcpTransport::create(transportUri);
132  }
133  else {
134  NDN_THROW(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
135  }
136  }
137  catch (const Transport::Error&) {
138  NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
139  }
140  catch (const FaceUri::Error&) {
141  NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
142  }
143 }
144 
145 void
146 Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
147 {
148  BOOST_ASSERT(m_impl == nullptr);
149  m_impl = make_shared<Impl>(*this, keyChain);
150 
151  if (transport == nullptr) {
152  transport = makeDefaultTransport();
153  BOOST_ASSERT(transport != nullptr);
154  }
155  m_transport = std::move(transport);
156 
157  IO_CAPTURE_WEAK_IMPL(post) {
158  impl->ensureConnected(false);
160 }
161 
162 Face::~Face() = default;
163 
166  const DataCallback& afterSatisfied,
167  const NackCallback& afterNacked,
168  const TimeoutCallback& afterTimeout)
169 {
170  auto id = m_impl->m_pendingInterestTable.allocateId();
171 
172  auto interest2 = make_shared<Interest>(interest);
173  interest2->getNonce();
174 
175  IO_CAPTURE_WEAK_IMPL(post) {
176  impl->asyncExpressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout);
178 
179  return PendingInterestHandle(*this, reinterpret_cast<const PendingInterestId*>(id));
180 }
181 
182 void
183 Face::cancelPendingInterest(const PendingInterestId* pendingInterestId)
184 {
185  IO_CAPTURE_WEAK_IMPL(post) {
186  impl->asyncRemovePendingInterest(reinterpret_cast<RecordId>(pendingInterestId));
188 }
189 
190 void
192 {
193  IO_CAPTURE_WEAK_IMPL(post) {
194  impl->asyncRemoveAllPendingInterests();
196 }
197 
198 size_t
200 {
201  return m_impl->m_pendingInterestTable.size();
202 }
203 
204 void
206 {
207  IO_CAPTURE_WEAK_IMPL(post) {
208  impl->asyncPutData(data);
210 }
211 
212 void
214 {
215  IO_CAPTURE_WEAK_IMPL(post) {
216  impl->asyncPutNack(nack);
218 }
219 
221 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest,
222  const RegisterPrefixFailureCallback& onFailure,
223  const security::SigningInfo& signingInfo, uint64_t flags)
224 {
225  return setInterestFilter(filter, onInterest, nullptr, onFailure, signingInfo, flags);
226 }
227 
229 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest,
230  const RegisterPrefixSuccessCallback& onSuccess,
231  const RegisterPrefixFailureCallback& onFailure,
232  const security::SigningInfo& signingInfo, uint64_t flags)
233 {
234  nfd::CommandOptions options;
235  options.setSigningInfo(signingInfo);
236 
237  auto id = m_impl->registerPrefix(filter.getPrefix(), onSuccess, onFailure, flags, options,
238  filter, onInterest);
239  return RegisteredPrefixHandle(*this, reinterpret_cast<const RegisteredPrefixId*>(id));
240 }
241 
243 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest)
244 {
245  auto id = m_impl->m_interestFilterTable.allocateId();
246 
247  IO_CAPTURE_WEAK_IMPL(post) {
248  impl->asyncSetInterestFilter(id, filter, onInterest);
250 
251  return InterestFilterHandle(*this, reinterpret_cast<const InterestFilterId*>(id));
252 }
253 
254 void
255 Face::clearInterestFilter(const InterestFilterId* interestFilterId)
256 {
257  IO_CAPTURE_WEAK_IMPL(post) {
258  impl->asyncUnsetInterestFilter(reinterpret_cast<RecordId>(interestFilterId));
260 }
261 
264  const RegisterPrefixSuccessCallback& onSuccess,
265  const RegisterPrefixFailureCallback& onFailure,
266  const security::SigningInfo& signingInfo,
267  uint64_t flags)
268 {
269  nfd::CommandOptions options;
270  options.setSigningInfo(signingInfo);
271 
272  auto id = m_impl->registerPrefix(prefix, onSuccess, onFailure, flags, options, nullopt, nullptr);
273  return RegisteredPrefixHandle(*this, reinterpret_cast<const RegisteredPrefixId*>(id));
274 }
275 
276 void
277 Face::unregisterPrefixImpl(const RegisteredPrefixId* registeredPrefixId,
278  const UnregisterPrefixSuccessCallback& onSuccess,
279  const UnregisterPrefixFailureCallback& onFailure)
280 {
281  IO_CAPTURE_WEAK_IMPL(post) {
282  impl->asyncUnregisterPrefix(reinterpret_cast<RecordId>(registeredPrefixId),
283  onSuccess, onFailure);
285 }
286 
287 void
288 Face::doProcessEvents(time::milliseconds timeout, bool keepThread)
289 {
290  if (m_ioService.stopped()) {
291  m_ioService.reset(); // ensure that run()/poll() will do some work
292  }
293 
294  try {
295  if (timeout < time::milliseconds::zero()) {
296  // do not block if timeout is negative, but process pending events
297  m_ioService.poll();
298  return;
299  }
300 
301  if (timeout > time::milliseconds::zero()) {
302  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.schedule(timeout,
303  [&io = m_ioService, &work = m_impl->m_ioServiceWork] {
304  io.stop();
305  work.reset();
306  });
307  }
308 
309  if (keepThread) {
310  // work will ensure that m_ioService is running until work object exists
311  m_impl->m_ioServiceWork = make_unique<boost::asio::io_service::work>(m_ioService);
312  }
313 
314  m_ioService.run();
315  }
316  catch (...) {
317  m_impl->shutdown();
318  throw;
319  }
320 }
321 
322 void
324 {
325  IO_CAPTURE_WEAK_IMPL(post) {
326  impl->shutdown();
327  if (m_transport->isConnected())
328  m_transport->close();
330 }
331 
335 template<typename NetPkt>
336 static void
337 extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket)
338 {
339  addTagFromField<lp::IncomingFaceIdTag, lp::IncomingFaceIdField>(netPacket, lpPacket);
340  addTagFromField<lp::CongestionMarkTag, lp::CongestionMarkField>(netPacket, lpPacket);
341 }
342 
343 void
344 Face::onReceiveElement(const Block& blockFromDaemon)
345 {
346  lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
347  // no need to distinguish
348 
349  Buffer::const_iterator begin, end;
350  std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
351  Block netPacket(&*begin, std::distance(begin, end));
352  switch (netPacket.type()) {
353  case tlv::Interest: {
354  auto interest = make_shared<Interest>(netPacket);
355  if (lpPacket.has<lp::NackField>()) {
356  auto nack = make_shared<lp::Nack>(std::move(*interest));
357  nack->setHeader(lpPacket.get<lp::NackField>());
358  extractLpLocalFields(*nack, lpPacket);
359  NDN_LOG_DEBUG(">N " << nack->getInterest() << '~' << nack->getHeader().getReason());
360  m_impl->nackPendingInterests(*nack);
361  }
362  else {
363  extractLpLocalFields(*interest, lpPacket);
364  NDN_LOG_DEBUG(">I " << *interest);
365  m_impl->processIncomingInterest(std::move(interest));
366  }
367  break;
368  }
369  case tlv::Data: {
370  auto data = make_shared<Data>(netPacket);
371  extractLpLocalFields(*data, lpPacket);
372  NDN_LOG_DEBUG(">D " << data->getName());
373  m_impl->satisfyPendingInterests(*data);
374  break;
375  }
376  }
377 }
378 
379 PendingInterestHandle::PendingInterestHandle(Face& face, const PendingInterestId* id)
380  : CancelHandle([&face, id] { face.cancelPendingInterest(id); })
381 {
382 }
383 
384 RegisteredPrefixHandle::RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id)
385  : CancelHandle([&face, id] { face.unregisterPrefixImpl(id, nullptr, nullptr); })
386  , m_face(&face)
387  , m_id(id)
388 {
389  // The lambda passed to CancelHandle constructor cannot call this->unregister,
390  // because base class destructor cannot access the member fields of this subclass.
391 }
392 
393 void
395  const UnregisterPrefixFailureCallback& onFailure)
396 {
397  if (m_id == nullptr) {
398  if (onFailure != nullptr) {
399  onFailure("RegisteredPrefixHandle is empty");
400  }
401  return;
402  }
403 
404  m_face->unregisterPrefixImpl(m_id, onSuccess, onFailure);
405  m_face = nullptr;
406  m_id = nullptr;
407 }
408 
409 InterestFilterHandle::InterestFilterHandle(Face& face, const InterestFilterId* id)
410  : CancelHandle([&face, id] { face.clearInterestFilter(id); })
411 {
412 }
413 
414 } // namespace ndn
#define NDN_THROW_NESTED(e)
Definition: exception.hpp:71
Definition: data.cpp:26
virtual void doProcessEvents(time::milliseconds timeout, bool keepThread)
Definition: face.cpp:288
The interface of signing key management.
Definition: key-chain.hpp:46
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:84
virtual ~Face()
std::string to_string(const T &val)
Definition: backports.hpp:102
void unregister(const UnregisterPrefixSuccessCallback &onSuccess=nullptr, const UnregisterPrefixFailureCallback &onFailure=nullptr)
Unregister the prefix.
Definition: face.cpp:394
const Name & getPrefix() const
declares the set of Interests a producer can serve, which starts with a name prefix, plus an optional regular expression
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
Represents an Interest packet.
Definition: interest.hpp:43
#define NDN_LOG_DEBUG(expression)
Log at DEBUG level.
Definition: logger.hpp:262
bool has() const
Definition: packet.hpp:74
static void extractLpLocalFields(NetPkt &netPacket, const lp::Packet &lpPacket)
extract local fields from NDNLPv2 packet and tag onto a network layer packet
Definition: face.cpp:337
Signing parameters passed to KeyChain.
static shared_ptr< UnixTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
represents a Network Nack
Definition: nack.hpp:38
#define NDN_THROW(e)
Definition: exception.hpp:61
Declare a field.
Definition: field-decl.hpp:179
#define IO_CAPTURE_WEAK_IMPL(OP)
Definition: face.cpp:34
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:191
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:96
RegisteredPrefixHandle registerPrefix(const Name &prefix, const RegisterPrefixSuccessCallback &onSuccess, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Register prefix with the connected NDN forwarder.
Definition: face.cpp:263
contains options for ControlCommand execution
A handle of pending Interest.
Definition: face.hpp:545
static shared_ptr< TcpTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
size_t getNPendingInterests() const
Get number of pending Interests.
Definition: face.cpp:199
void shutdown()
Shutdown face operations.
Definition: face.cpp:323
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:89
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:74
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:69
Represents an absolute name.
Definition: name.hpp:43
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
CommandOptions & setSigningInfo(const security::SigningInfo &signingInfo)
sets signing parameters
PendingInterestHandle expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express Interest.
Definition: face.cpp:165
function< void(const InterestFilter &, const Interest &)> InterestCallback
Callback invoked when incoming Interest matches the specified InterestFilter.
Definition: face.hpp:64
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:40
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:109
RegisteredPrefixHandle() noexcept
Definition: face.hpp:575
InterestFilterHandle() noexcept=default
System configuration file for NDN platform.
Definition: config-file.hpp:48
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:79
void put(Data data)
Publish data packet.
Definition: face.cpp:205
OversizedPacketError(char pktType, const Name &name, size_t wireSize)
Constructor.
Definition: face.cpp:47
A handle of registered Interest filter.
Definition: face.hpp:624
PendingInterestHandle() noexcept=default
function< void(const Interest &)> TimeoutCallback
Callback invoked when expressed Interest times out.
Definition: face.hpp:59
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:54
Represents a Data packet.
Definition: data.hpp:35
RegisteredPrefixHandle setInterestFilter(const InterestFilter &filter, const InterestCallback &onInterest, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Set InterestFilter to dispatch incoming matching interest to onInterest callback and register the fil...
Definition: face.cpp:221
const Parsed & getParsedConfiguration() const
Face(shared_ptr< Transport > transport=nullptr)
Create Face using given transport (or default transport if omitted)
Definition: face.cpp:57
const nullopt_t nullopt((nullopt_t::init()))
A handle of registered prefix.
Definition: face.hpp:572
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when expressed Interest gets satisfied with a Data packet.
Definition: face.hpp:44
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:41