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/random.hpp"
28 #include "ndn-cxx/util/time.hpp"
29 
30 // NDN_LOG_INIT(ndn.Face) is declared in face-impl.hpp
31 
32 // A callback scheduled through io.post and io.dispatch may be invoked after the face is destructed.
33 // To prevent this situation, use these macros to capture Face::m_impl as weak_ptr and skip callback
34 // execution if the face has been destructed.
35 #define IO_CAPTURE_WEAK_IMPL(OP) \
36  { \
37  weak_ptr<Impl> implWeak(m_impl); \
38  m_ioService.OP([=] { \
39  auto impl = implWeak.lock(); \
40  if (impl != nullptr) {
41 #define IO_CAPTURE_WEAK_IMPL_END \
42  } \
43  }); \
44  }
45 
46 namespace ndn {
47 
48 Face::OversizedPacketError::OversizedPacketError(char pktType, const Name& name, size_t wireSize)
49  : Error((pktType == 'I' ? "Interest " : pktType == 'D' ? "Data " : "Nack ") +
50  name.toUri() + " encodes into " + to_string(wireSize) + " octets, "
51  "exceeding the implementation limit of " + to_string(MAX_NDN_PACKET_SIZE) + " octets")
52  , pktType(pktType)
53  , name(name)
54  , wireSize(wireSize)
55 {
56 }
57 
58 Face::Face(shared_ptr<Transport> transport)
59  : m_internalIoService(make_unique<boost::asio::io_service>())
60  , m_ioService(*m_internalIoService)
61  , m_internalKeyChain(make_unique<KeyChain>())
62  , m_impl(make_shared<Impl>(*this))
63 {
64  construct(std::move(transport), *m_internalKeyChain);
65 }
66 
67 Face::Face(boost::asio::io_service& ioService)
68  : m_ioService(ioService)
69  , m_internalKeyChain(make_unique<KeyChain>())
70  , m_impl(make_shared<Impl>(*this))
71 {
72  construct(nullptr, *m_internalKeyChain);
73 }
74 
75 Face::Face(const std::string& host, const std::string& port)
76  : m_internalIoService(make_unique<boost::asio::io_service>())
77  , m_ioService(*m_internalIoService)
78  , m_internalKeyChain(make_unique<KeyChain>())
79  , m_impl(make_shared<Impl>(*this))
80 {
81  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
82 }
83 
84 Face::Face(shared_ptr<Transport> transport, KeyChain& keyChain)
85  : m_internalIoService(make_unique<boost::asio::io_service>())
86  , m_ioService(*m_internalIoService)
87  , m_impl(make_shared<Impl>(*this))
88 {
89  construct(std::move(transport), keyChain);
90 }
91 
92 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService)
93  : m_ioService(ioService)
94  , m_internalKeyChain(make_unique<KeyChain>())
95  , m_impl(make_shared<Impl>(*this))
96 {
97  construct(std::move(transport), *m_internalKeyChain);
98 }
99 
100 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService, KeyChain& keyChain)
101  : m_ioService(ioService)
102  , m_impl(make_shared<Impl>(*this))
103 {
104  construct(std::move(transport), keyChain);
105 }
106 
107 shared_ptr<Transport>
108 Face::makeDefaultTransport()
109 {
110  // transport=unix:///var/run/nfd.sock
111  // transport=tcp://localhost:6363
112 
113  std::string transportUri;
114 
115  const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT");
116  if (transportEnviron != nullptr) {
117  transportUri = transportEnviron;
118  }
119  else {
120  ConfigFile config;
121  transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
122  }
123 
124  if (transportUri.empty()) {
125  // transport not specified, use default Unix transport.
126  return UnixTransport::create("");
127  }
128 
129  std::string protocol;
130  try {
131  FaceUri uri(transportUri);
132  protocol = uri.getScheme();
133 
134  if (protocol == "unix") {
135  return UnixTransport::create(transportUri);
136  }
137  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
138  return TcpTransport::create(transportUri);
139  }
140  else {
141  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
142  }
143  }
144  catch (const Transport::Error& error) {
145  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
146  }
147  catch (const FaceUri::Error& error) {
148  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
149  }
150 }
151 
152 void
153 Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
154 {
155  if (transport == nullptr) {
156  transport = makeDefaultTransport();
157  }
158  BOOST_ASSERT(transport != nullptr);
159  m_transport = std::move(transport);
160 
161  m_nfdController = make_unique<nfd::Controller>(*this, keyChain);
162 
163  IO_CAPTURE_WEAK_IMPL(post) {
164  impl->ensureConnected(false);
166 }
167 
168 Face::~Face() = default;
169 
170 shared_ptr<Transport>
172 {
173  return m_transport;
174 }
175 
178  const DataCallback& afterSatisfied,
179  const NackCallback& afterNacked,
180  const TimeoutCallback& afterTimeout)
181 {
182  auto interest2 = make_shared<Interest>(interest);
183  interest2->getNonce();
184 
185  IO_CAPTURE_WEAK_IMPL(post) {
186  impl->asyncExpressInterest(interest2, afterSatisfied, afterNacked, afterTimeout);
188 
189  return PendingInterestHandle(*this, reinterpret_cast<const PendingInterestId*>(interest2.get()));
190 }
191 
192 void
193 Face::removePendingInterest(const PendingInterestId* pendingInterestId)
194 {
195  IO_CAPTURE_WEAK_IMPL(post) {
196  impl->asyncRemovePendingInterest(pendingInterestId);
198 }
199 
200 void
202 {
203  IO_CAPTURE_WEAK_IMPL(post) {
204  impl->asyncRemoveAllPendingInterests();
206 }
207 
208 size_t
210 {
211  return m_impl->m_pendingInterestTable.size();
212 }
213 
214 void
216 {
217  IO_CAPTURE_WEAK_IMPL(post) {
218  impl->asyncPutData(data);
220 }
221 
222 void
224 {
225  IO_CAPTURE_WEAK_IMPL(post) {
226  impl->asyncPutNack(nack);
228 }
229 
232  const InterestCallback& onInterest,
233  const RegisterPrefixFailureCallback& onFailure,
234  const security::SigningInfo& signingInfo,
235  uint64_t flags)
236 {
237  return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags);
238 }
239 
242  const InterestCallback& onInterest,
243  const RegisterPrefixSuccessCallback& onSuccess,
244  const RegisterPrefixFailureCallback& onFailure,
245  const security::SigningInfo& signingInfo,
246  uint64_t flags)
247 {
248  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
249 
250  nfd::CommandOptions options;
251  options.setSigningInfo(signingInfo);
252 
253  auto id = m_impl->registerPrefix(interestFilter.getPrefix(), filter,
254  onSuccess, onFailure, flags, options);
255  return RegisteredPrefixHandle(*this, id);
256 }
257 
260  const InterestCallback& onInterest)
261 {
262  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
263 
264  IO_CAPTURE_WEAK_IMPL(post) {
265  impl->asyncSetInterestFilter(filter);
267 
268  auto id = reinterpret_cast<const InterestFilterId*>(filter.get());
269  return InterestFilterHandle(*this, id);
270 }
271 
274  const RegisterPrefixSuccessCallback& onSuccess,
275  const RegisterPrefixFailureCallback& onFailure,
276  const security::SigningInfo& signingInfo,
277  uint64_t flags)
278 {
279  nfd::CommandOptions options;
280  options.setSigningInfo(signingInfo);
281 
282  auto id = m_impl->registerPrefix(prefix, nullptr, onSuccess, onFailure, flags, options);
283  return RegisteredPrefixHandle(*this, id);
284 }
285 
286 void
287 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
288 {
289  IO_CAPTURE_WEAK_IMPL(post) {
290  impl->asyncUnregisterPrefix(registeredPrefixId, nullptr, nullptr);
292 }
293 
294 void
295 Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
296 {
297  IO_CAPTURE_WEAK_IMPL(post) {
298  impl->asyncUnsetInterestFilter(interestFilterId);
300 }
301 
302 void
303 Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
304  const UnregisterPrefixSuccessCallback& onSuccess,
305  const UnregisterPrefixFailureCallback& onFailure)
306 {
307  IO_CAPTURE_WEAK_IMPL(post) {
308  impl->asyncUnregisterPrefix(registeredPrefixId, onSuccess, onFailure);
310 }
311 
312 void
313 Face::doProcessEvents(time::milliseconds timeout, bool keepThread)
314 {
315  if (m_ioService.stopped()) {
316  m_ioService.reset(); // ensure that run()/poll() will do some work
317  }
318 
319  try {
320  if (timeout < time::milliseconds::zero()) {
321  // do not block if timeout is negative, but process pending events
322  m_ioService.poll();
323  return;
324  }
325 
326  if (timeout > time::milliseconds::zero()) {
327  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.scheduleEvent(timeout,
328  [&io = m_ioService, &work = m_impl->m_ioServiceWork] {
329  io.stop();
330  work.reset();
331  });
332  }
333 
334  if (keepThread) {
335  // work will ensure that m_ioService is running until work object exists
336  m_impl->m_ioServiceWork = make_unique<boost::asio::io_service::work>(m_ioService);
337  }
338 
339  m_ioService.run();
340  }
341  catch (...) {
342  m_impl->m_ioServiceWork.reset();
343  m_impl->m_pendingInterestTable.clear();
344  m_impl->m_registeredPrefixTable.clear();
345  throw;
346  }
347 }
348 
349 void
351 {
352  IO_CAPTURE_WEAK_IMPL(post) {
353  this->asyncShutdown();
355 }
356 
357 void
358 Face::asyncShutdown()
359 {
360  m_impl->m_pendingInterestTable.clear();
361  m_impl->m_registeredPrefixTable.clear();
362 
363  if (m_transport->isConnected())
364  m_transport->close();
365 
366  m_impl->m_ioServiceWork.reset();
367 }
368 
372 template<typename NetPkt>
373 static void
374 extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket)
375 {
376  addTagFromField<lp::IncomingFaceIdTag, lp::IncomingFaceIdField>(netPacket, lpPacket);
377  addTagFromField<lp::CongestionMarkTag, lp::CongestionMarkField>(netPacket, lpPacket);
378 }
379 
380 void
381 Face::onReceiveElement(const Block& blockFromDaemon)
382 {
383  lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
384  // no need to distinguish
385 
386  Buffer::const_iterator begin, end;
387  std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
388  Block netPacket(&*begin, std::distance(begin, end));
389  switch (netPacket.type()) {
390  case tlv::Interest: {
391  auto interest = make_shared<Interest>(netPacket);
392  if (lpPacket.has<lp::NackField>()) {
393  auto nack = make_shared<lp::Nack>(std::move(*interest));
394  nack->setHeader(lpPacket.get<lp::NackField>());
395  extractLpLocalFields(*nack, lpPacket);
396  NDN_LOG_DEBUG(">N " << nack->getInterest() << '~' << nack->getHeader().getReason());
397  m_impl->nackPendingInterests(*nack);
398  }
399  else {
400  extractLpLocalFields(*interest, lpPacket);
401  NDN_LOG_DEBUG(">I " << *interest);
402  m_impl->processIncomingInterest(std::move(interest));
403  }
404  break;
405  }
406  case tlv::Data: {
407  auto data = make_shared<Data>(netPacket);
408  extractLpLocalFields(*data, lpPacket);
409  NDN_LOG_DEBUG(">D " << data->getName());
410  m_impl->satisfyPendingInterests(*data);
411  break;
412  }
413  }
414 }
415 
416 PendingInterestHandle::PendingInterestHandle(Face& face, const PendingInterestId* id)
417  : CancelHandle([&face, id] { face.removePendingInterest(id); })
418  , m_id(id)
419 {
420 }
421 
422 RegisteredPrefixHandle::RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id)
423  : CancelHandle([&face, id] { face.unregisterPrefix(id, nullptr, nullptr); })
424  , m_face(&face)
425  , m_id(id)
426 {
427  // The lambda passed to CancelHandle constructor cannot call this->unregister,
428  // because base class destructor cannot access the member fields of this subclass.
429 }
430 
431 void
433  const UnregisterPrefixFailureCallback& onFailure)
434 {
435  if (m_id == nullptr) {
436  if (onFailure != nullptr) {
437  onFailure("RegisteredPrefixHandle is empty");
438  }
439  return;
440  }
441 
442  m_face->unregisterPrefix(m_id, onSuccess, onFailure);
443  m_face = nullptr;
444  m_id = nullptr;
445 }
446 
447 InterestFilterHandle::InterestFilterHandle(Face& face, const InterestFilterId* id)
448  : CancelHandle([&face, id] { face.unsetInterestFilter(id); })
449  , m_id(id)
450 {
451 }
452 
453 } // namespace ndn
Definition: data.cpp:26
virtual void doProcessEvents(time::milliseconds timeout, bool keepThread)
Definition: face.cpp:313
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:88
virtual ~Face()
void unregister(const UnregisterPrefixSuccessCallback &onSuccess=nullptr, const UnregisterPrefixFailureCallback &onFailure=nullptr)
Unregister the prefix.
Definition: face.cpp:432
declares the set of Interests a producer can serve, which starts with a name prefix, plus an optional regular expression
const Parsed & getParsedConfiguration() const
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
Represents an Interest packet.
Definition: interest.hpp:44
#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:374
Signing parameters passed to KeyChain.
void unregisterPrefix(const RegisteredPrefixId *registeredPrefixId, const UnregisterPrefixSuccessCallback &onSuccess, const UnregisterPrefixFailureCallback &onFailure)
Unregister prefix from RIB.
Definition: face.cpp:303
static shared_ptr< UnixTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
represents a Network Nack
Definition: nack.hpp:38
Declare a field.
Definition: field-decl.hpp:181
#define IO_CAPTURE_WEAK_IMPL(OP)
Definition: face.cpp:35
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:201
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:97
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:273
contains options for ControlCommand execution
A handle of pending Interest.
Definition: face.hpp:550
shared_ptr< Transport > getTransport()
Definition: face.cpp:171
static shared_ptr< TcpTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
void shutdown()
Shutdown face operations.
Definition: face.cpp:350
CancelHandle() noexcept=default
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:93
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:78
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:73
Represents an absolute name.
Definition: name.hpp:43
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
void unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
Remove the registered prefix entry with the registeredPrefixId.
Definition: face.cpp:287
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:177
function< void(const InterestFilter &, const Interest &)> InterestCallback
Callback invoked when incoming Interest matches the specified InterestFilter.
Definition: face.hpp:68
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:41
RegisteredPrefixHandle() noexcept
Definition: face.hpp:590
InterestFilterHandle() noexcept=default
System configuration file for NDN platform.
Definition: config-file.hpp:48
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:113
size_t getNPendingInterests() const
Get number of pending Interests.
Definition: face.cpp:209
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:83
void put(Data data)
Publish data packet.
Definition: face.cpp:215
OversizedPacketError(char pktType, const Name &name, size_t wireSize)
Constructor.
Definition: face.cpp:48
std::string to_string(const V &v)
Definition: backports.hpp:67
A handle of registered Interest filter.
Definition: face.hpp:652
PendingInterestHandle() noexcept=default
function< void(const Interest &)> TimeoutCallback
Callback invoked when expressed Interest times out.
Definition: face.hpp:63
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:58
Represents a Data packet.
Definition: data.hpp:35
RegisteredPrefixHandle setInterestFilter(const InterestFilter &interestFilter, 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:231
Face(shared_ptr< Transport > transport=nullptr)
Create Face using given transport (or default transport if omitted)
Definition: face.cpp:58
A handle of registered prefix.
Definition: face.hpp:587
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when expressed Interest gets satisfied with a Data packet.
Definition: face.hpp:53
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:193
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:41