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-2020 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/scope.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 {
63  construct(std::move(transport), *m_internalKeyChain);
64 }
65 
66 Face::Face(boost::asio::io_service& ioService)
67  : m_ioService(ioService)
68  , m_internalKeyChain(make_unique<KeyChain>())
69 {
70  construct(nullptr, *m_internalKeyChain);
71 }
72 
73 Face::Face(const std::string& host, const std::string& port)
74  : m_internalIoService(make_unique<boost::asio::io_service>())
75  , m_ioService(*m_internalIoService)
76  , m_internalKeyChain(make_unique<KeyChain>())
77 {
78  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
79 }
80 
81 Face::Face(shared_ptr<Transport> transport, KeyChain& keyChain)
82  : m_internalIoService(make_unique<boost::asio::io_service>())
83  , m_ioService(*m_internalIoService)
84 {
85  construct(std::move(transport), keyChain);
86 }
87 
88 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService)
89  : m_ioService(ioService)
90  , m_internalKeyChain(make_unique<KeyChain>())
91 {
92  construct(std::move(transport), *m_internalKeyChain);
93 }
94 
95 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService, KeyChain& keyChain)
96  : m_ioService(ioService)
97 {
98  construct(std::move(transport), keyChain);
99 }
100 
101 shared_ptr<Transport>
102 Face::makeDefaultTransport()
103 {
104  std::string transportUri;
105 
106  const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT");
107  if (transportEnviron != nullptr) {
108  transportUri = transportEnviron;
109  }
110  else {
111  ConfigFile config;
112  transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
113  }
114 
115  if (transportUri.empty()) {
116  // transport not specified, use default Unix transport.
117  return UnixTransport::create("");
118  }
119 
120  std::string protocol;
121  try {
122  FaceUri uri(transportUri);
123  protocol = uri.getScheme();
124 
125  if (protocol == "unix") {
126  return UnixTransport::create(transportUri);
127  }
128  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
129  return TcpTransport::create(transportUri);
130  }
131  else {
132  NDN_THROW(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
133  }
134  }
135  catch (const Transport::Error&) {
136  NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
137  }
138  catch (const FaceUri::Error&) {
139  NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
140  }
141 }
142 
143 void
144 Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
145 {
146  BOOST_ASSERT(m_impl == nullptr);
147  m_impl = make_shared<Impl>(*this, keyChain);
148 
149  if (transport == nullptr) {
150  transport = makeDefaultTransport();
151  BOOST_ASSERT(transport != nullptr);
152  }
153  m_transport = std::move(transport);
154 
155  IO_CAPTURE_WEAK_IMPL(post) {
156  impl->ensureConnected(false);
158 }
159 
160 Face::~Face() = default;
161 
164  const DataCallback& afterSatisfied,
165  const NackCallback& afterNacked,
166  const TimeoutCallback& afterTimeout)
167 {
168  auto id = m_impl->m_pendingInterestTable.allocateId();
169 
170  auto interest2 = make_shared<Interest>(interest);
171  interest2->getNonce();
172 
173  IO_CAPTURE_WEAK_IMPL(post) {
174  impl->expressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout);
176 
177  return PendingInterestHandle(m_impl, id);
178 }
179 
180 void
182 {
183  IO_CAPTURE_WEAK_IMPL(post) {
184  impl->removeAllPendingInterests();
186 }
187 
188 size_t
190 {
191  return m_impl->m_pendingInterestTable.size();
192 }
193 
194 void
196 {
197  IO_CAPTURE_WEAK_IMPL(post) {
198  impl->putData(data);
200 }
201 
202 void
204 {
205  IO_CAPTURE_WEAK_IMPL(post) {
206  impl->putNack(nack);
208 }
209 
211 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest,
212  const RegisterPrefixFailureCallback& onFailure,
213  const security::SigningInfo& signingInfo, uint64_t flags)
214 {
215  return setInterestFilter(filter, onInterest, nullptr, onFailure, signingInfo, flags);
216 }
217 
219 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest,
220  const RegisterPrefixSuccessCallback& onSuccess,
221  const RegisterPrefixFailureCallback& onFailure,
222  const security::SigningInfo& signingInfo, uint64_t flags)
223 {
224  nfd::CommandOptions options;
225  options.setSigningInfo(signingInfo);
226 
227  auto id = m_impl->registerPrefix(filter.getPrefix(), onSuccess, onFailure, flags, options,
228  filter, onInterest);
229  return RegisteredPrefixHandle(m_impl, id);
230 }
231 
233 Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest)
234 {
235  auto id = m_impl->m_interestFilterTable.allocateId();
236 
237  IO_CAPTURE_WEAK_IMPL(post) {
238  impl->setInterestFilter(id, filter, onInterest);
240 
241  return InterestFilterHandle(m_impl, id);
242 }
243 
246  const RegisterPrefixSuccessCallback& onSuccess,
247  const RegisterPrefixFailureCallback& onFailure,
248  const security::SigningInfo& signingInfo,
249  uint64_t flags)
250 {
251  nfd::CommandOptions options;
252  options.setSigningInfo(signingInfo);
253 
254  auto id = m_impl->registerPrefix(prefix, onSuccess, onFailure, flags, options, nullopt, nullptr);
255  return RegisteredPrefixHandle(m_impl, id);
256 }
257 
258 void
259 Face::doProcessEvents(time::milliseconds timeout, bool keepThread)
260 {
261  if (m_ioService.stopped()) {
262  m_ioService.reset(); // ensure that run()/poll() will do some work
263  }
264 
265  auto onThrow = make_scope_fail([this] { m_impl->shutdown(); });
266 
267  if (timeout < 0_ms) {
268  // do not block if timeout is negative, but process pending events
269  m_ioService.poll();
270  return;
271  }
272 
273  if (timeout > 0_ms) {
274  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.schedule(timeout,
275  [&io = m_ioService, &work = m_impl->m_ioServiceWork] {
276  io.stop();
277  work.reset();
278  });
279  }
280 
281  if (keepThread) {
282  // work will ensure that m_ioService is running until work object exists
283  m_impl->m_ioServiceWork = make_unique<boost::asio::io_service::work>(m_ioService);
284  }
285 
286  m_ioService.run();
287 }
288 
289 void
291 {
292  IO_CAPTURE_WEAK_IMPL(post) {
293  impl->shutdown();
294  if (m_transport->isConnected())
295  m_transport->close();
297 }
298 
302 template<typename NetPkt>
303 static void
304 extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket)
305 {
306  addTagFromField<lp::IncomingFaceIdTag, lp::IncomingFaceIdField>(netPacket, lpPacket);
307  addTagFromField<lp::CongestionMarkTag, lp::CongestionMarkField>(netPacket, lpPacket);
308 }
309 
310 void
311 Face::onReceiveElement(const Block& blockFromDaemon)
312 {
313  lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
314  // no need to distinguish
315 
316  Buffer::const_iterator begin, end;
317  std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
318  Block netPacket(&*begin, std::distance(begin, end));
319  switch (netPacket.type()) {
320  case tlv::Interest: {
321  auto interest = make_shared<Interest>(netPacket);
322  if (lpPacket.has<lp::NackField>()) {
323  auto nack = make_shared<lp::Nack>(std::move(*interest));
324  nack->setHeader(lpPacket.get<lp::NackField>());
325  extractLpLocalFields(*nack, lpPacket);
326  NDN_LOG_DEBUG(">N " << nack->getInterest() << '~' << nack->getHeader().getReason());
327  m_impl->nackPendingInterests(*nack);
328  }
329  else {
330  extractLpLocalFields(*interest, lpPacket);
331  NDN_LOG_DEBUG(">I " << *interest);
332  m_impl->processIncomingInterest(std::move(interest));
333  }
334  break;
335  }
336  case tlv::Data: {
337  auto data = make_shared<Data>(netPacket);
338  extractLpLocalFields(*data, lpPacket);
339  NDN_LOG_DEBUG(">D " << data->getName());
340  m_impl->satisfyPendingInterests(*data);
341  break;
342  }
343  }
344 }
345 
346 PendingInterestHandle::PendingInterestHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
347  : CancelHandle([w = std::move(weakImpl), id] {
348  auto impl = w.lock();
349  if (impl != nullptr) {
350  impl->asyncRemovePendingInterest(id);
351  }
352  })
353 {
354 }
355 
356 RegisteredPrefixHandle::RegisteredPrefixHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
357  : CancelHandle([=] { unregister(weakImpl, id, nullptr, nullptr); })
358  , m_weakImpl(std::move(weakImpl))
359  , m_id(id)
360 {
361  // The lambda passed to CancelHandle constructor cannot call the non-static unregister(),
362  // because the base class destructor cannot access the member fields of this subclass.
363 }
364 
365 void
367  const UnregisterPrefixFailureCallback& onFailure)
368 {
369  if (m_id == 0) {
370  if (onFailure) {
371  onFailure("RegisteredPrefixHandle is empty");
372  }
373  return;
374  }
375 
376  unregister(m_weakImpl, m_id, onSuccess, onFailure);
377  *this = {};
378 }
379 
380 void
381 RegisteredPrefixHandle::unregister(const weak_ptr<Face::Impl>& weakImpl, detail::RecordId id,
382  const UnregisterPrefixSuccessCallback& onSuccess,
383  const UnregisterPrefixFailureCallback& onFailure)
384 {
385  auto impl = weakImpl.lock();
386  if (impl != nullptr) {
387  impl->asyncUnregisterPrefix(id, onSuccess, onFailure);
388  }
389  else if (onFailure) {
390  onFailure("Face already closed");
391  }
392 }
393 
394 InterestFilterHandle::InterestFilterHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
395  : CancelHandle([w = std::move(weakImpl), id] {
396  auto impl = w.lock();
397  if (impl != nullptr) {
398  impl->asyncUnsetInterestFilter(id);
399  }
400  })
401 {
402 }
403 
404 } // 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:259
The interface of signing key management.
Definition: key-chain.hpp:45
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregistering a prefix fails.
Definition: face.hpp:85
virtual ~Face()
std::string to_string(const T &val)
Definition: backports.hpp:101
void unregister(const UnregisterPrefixSuccessCallback &onSuccess=nullptr, const UnregisterPrefixFailureCallback &onFailure=nullptr)
Unregister the prefix.
Definition: face.cpp:366
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 the NDN packet format.
Definition: block.hpp:42
Represents an Interest packet.
Definition: interest.hpp:50
#define NDN_LOG_DEBUG(expression)
Log at DEBUG level.
Definition: logger.hpp:254
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:304
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:35
uint64_t RecordId
Definition: face.hpp:44
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:181
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:245
contains options for ControlCommand execution
Handle for a pending Interest.
Definition: face.hpp:490
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:189
void shutdown()
Shutdown face operations.
Definition: face.cpp:290
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:75
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:70
Represents an absolute name.
Definition: name.hpp:44
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:163
function< void(const InterestFilter &, const Interest &)> InterestCallback
Callback invoked when an incoming Interest matches the specified InterestFilter.
Definition: face.hpp:65
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:41
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:109
RegisteredPrefixHandle() noexcept
Definition: face.hpp:520
InterestFilterHandle() noexcept=default
System configuration file for NDN platform.
Definition: config-file.hpp:48
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregistering a prefix succeeds.
Definition: face.hpp:80
void put(Data data)
Publish data packet.
Definition: face.cpp:195
OversizedPacketError(char pktType, const Name &name, size_t wireSize)
Constructor.
Definition: face.cpp:48
Handle for a registered Interest filter.
Definition: face.hpp:569
PendingInterestHandle() noexcept=default
function< void(const Interest &)> TimeoutCallback
Callback invoked when an expressed Interest times out.
Definition: face.hpp:60
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when a Nack is received in response to an expressed Interest.
Definition: face.hpp:55
Represents a Data packet.
Definition: data.hpp:39
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:211
const Parsed & getParsedConfiguration() const
Face(shared_ptr< Transport > transport=nullptr)
Create Face using given transport (or default transport if omitted)
Definition: face.cpp:58
Handle for a registered prefix.
Definition: face.hpp:517
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when an expressed Interest is satisfied by a Data packet.
Definition: face.hpp:50
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:40