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-2017 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 "face.hpp"
23 #include "detail/face-impl.hpp"
24 
25 #include "encoding/tlv.hpp"
26 #include "net/face-uri.hpp"
28 #include "util/random.hpp"
29 #include "util/time.hpp"
30 
31 // NDN_LOG_INIT(ndn.Face) is declared in face-impl.hpp
32 
33 // A callback scheduled through io.post and io.dispatch may be invoked after the face is destructed.
34 // To prevent this situation, use these macros to capture Face::m_impl as weak_ptr and skip callback
35 // execution if the face has been destructed.
36 #define IO_CAPTURE_WEAK_IMPL(OP) \
37  { \
38  weak_ptr<Impl> implWeak(m_impl); \
39  m_ioService.OP([=] { \
40  auto impl = implWeak.lock(); \
41  if (impl != nullptr) {
42 #define IO_CAPTURE_WEAK_IMPL_END \
43  } \
44  }); \
45  }
46 
47 namespace ndn {
48 
49 Face::OversizedPacketError::OversizedPacketError(char pktType, const Name& name, size_t wireSize)
50  : Error((pktType == 'I' ? "Interest " : pktType == 'D' ? "Data " : "Nack ") +
51  name.toUri() + " encodes into " + to_string(wireSize) + " octets, "
52  "exceeding the implementation limit of " + to_string(MAX_NDN_PACKET_SIZE) + " octets")
53  , pktType(pktType)
54  , name(name)
55  , wireSize(wireSize)
56 {
57 }
58 
59 Face::Face(shared_ptr<Transport> transport)
60  : m_internalIoService(make_unique<boost::asio::io_service>())
61  , m_ioService(*m_internalIoService)
62  , m_internalKeyChain(make_unique<KeyChain>())
63  , m_impl(make_shared<Impl>(*this))
64 {
65  construct(std::move(transport), *m_internalKeyChain);
66 }
67 
68 Face::Face(boost::asio::io_service& ioService)
69  : m_ioService(ioService)
70  , m_internalKeyChain(make_unique<KeyChain>())
71  , m_impl(make_shared<Impl>(*this))
72 {
73  construct(nullptr, *m_internalKeyChain);
74 }
75 
76 Face::Face(const std::string& host, const std::string& port)
77  : m_internalIoService(make_unique<boost::asio::io_service>())
78  , m_ioService(*m_internalIoService)
79  , m_internalKeyChain(make_unique<KeyChain>())
80  , m_impl(make_shared<Impl>(*this))
81 {
82  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
83 }
84 
85 Face::Face(shared_ptr<Transport> transport, KeyChain& keyChain)
86  : m_internalIoService(make_unique<boost::asio::io_service>())
87  , m_ioService(*m_internalIoService)
88  , m_impl(make_shared<Impl>(*this))
89 {
90  construct(std::move(transport), keyChain);
91 }
92 
93 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService)
94  : m_ioService(ioService)
95  , m_internalKeyChain(make_unique<KeyChain>())
96  , m_impl(make_shared<Impl>(*this))
97 {
98  construct(std::move(transport), *m_internalKeyChain);
99 }
100 
101 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService, KeyChain& keyChain)
102  : m_ioService(ioService)
103  , m_impl(make_shared<Impl>(*this))
104 {
105  construct(std::move(transport), keyChain);
106 }
107 
108 shared_ptr<Transport>
109 Face::makeDefaultTransport()
110 {
111  // transport=unix:///var/run/nfd.sock
112  // transport=tcp://localhost:6363
113 
114  std::string transportUri;
115 
116  const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT");
117  if (transportEnviron != nullptr) {
118  transportUri = transportEnviron;
119  }
120  else {
121  ConfigFile config;
122  transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
123  }
124 
125  if (transportUri.empty()) {
126  // transport not specified, use default Unix transport.
127  return UnixTransport::create("");
128  }
129 
130  std::string protocol;
131  try {
132  FaceUri uri(transportUri);
133  protocol = uri.getScheme();
134 
135  if (protocol == "unix") {
136  return UnixTransport::create(transportUri);
137  }
138  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
139  return TcpTransport::create(transportUri);
140  }
141  else {
142  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
143  }
144  }
145  catch (const Transport::Error& error) {
146  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
147  }
148  catch (const FaceUri::Error& error) {
149  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
150  }
151 }
152 
153 void
154 Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
155 {
156  if (transport == nullptr) {
157  transport = makeDefaultTransport();
158  }
159  BOOST_ASSERT(transport != nullptr);
160  m_transport = std::move(transport);
161 
162  m_nfdController = make_unique<nfd::Controller>(*this, keyChain);
163 
164  IO_CAPTURE_WEAK_IMPL(post) {
165  impl->ensureConnected(false);
167 }
168 
169 Face::~Face() = default;
170 
171 shared_ptr<Transport>
173 {
174  return m_transport;
175 }
176 
177 const PendingInterestId*
179  const DataCallback& afterSatisfied,
180  const NackCallback& afterNacked,
181  const TimeoutCallback& afterTimeout)
182 {
183  shared_ptr<Interest> interest2 = make_shared<Interest>(interest);
184  interest2->getNonce();
185 
186  IO_CAPTURE_WEAK_IMPL(dispatch) {
187  impl->asyncExpressInterest(interest2, afterSatisfied, afterNacked, afterTimeout);
189 
190  return reinterpret_cast<const PendingInterestId*>(interest2.get());
191 }
192 
193 void
194 Face::removePendingInterest(const PendingInterestId* pendingInterestId)
195 {
196  IO_CAPTURE_WEAK_IMPL(post) {
197  impl->asyncRemovePendingInterest(pendingInterestId);
199 }
200 
201 void
203 {
204  IO_CAPTURE_WEAK_IMPL(post) {
205  impl->asyncRemoveAllPendingInterests();
207 }
208 
209 size_t
211 {
212  return m_impl->m_pendingInterestTable.size();
213 }
214 
215 void
217 {
218  IO_CAPTURE_WEAK_IMPL(dispatch) {
219  impl->asyncPutData(data);
221 }
222 
223 void
225 {
226  IO_CAPTURE_WEAK_IMPL(dispatch) {
227  impl->asyncPutNack(nack);
229 }
230 
231 const RegisteredPrefixId*
233  const InterestCallback& onInterest,
234  const RegisterPrefixFailureCallback& onFailure,
235  const security::SigningInfo& signingInfo,
236  uint64_t flags)
237 {
238  return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags);
239 }
240 
241 const RegisteredPrefixId*
243  const InterestCallback& onInterest,
244  const RegisterPrefixSuccessCallback& onSuccess,
245  const RegisterPrefixFailureCallback& onFailure,
246  const security::SigningInfo& signingInfo,
247  uint64_t flags)
248 {
249  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
250 
251  nfd::CommandOptions options;
252  options.setSigningInfo(signingInfo);
253 
254  return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
255  onSuccess, onFailure, flags, options);
256 }
257 
258 const InterestFilterId*
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  return reinterpret_cast<const InterestFilterId*>(filter.get());
269 }
270 
271 const RegisteredPrefixId*
273  const RegisterPrefixSuccessCallback& onSuccess,
274  const RegisterPrefixFailureCallback& onFailure,
275  const security::SigningInfo& signingInfo,
276  uint64_t flags)
277 {
278  nfd::CommandOptions options;
279  options.setSigningInfo(signingInfo);
280 
281  return m_impl->registerPrefix(prefix, nullptr, onSuccess, onFailure, flags, options);
282 }
283 
284 void
285 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
286 {
287  IO_CAPTURE_WEAK_IMPL(post) {
288  impl->asyncUnregisterPrefix(registeredPrefixId, nullptr, nullptr);
290 }
291 
292 void
293 Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
294 {
295  IO_CAPTURE_WEAK_IMPL(post) {
296  impl->asyncUnsetInterestFilter(interestFilterId);
298 }
299 
300 void
301 Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
302  const UnregisterPrefixSuccessCallback& onSuccess,
303  const UnregisterPrefixFailureCallback& onFailure)
304 {
305  IO_CAPTURE_WEAK_IMPL(post) {
306  impl->asyncUnregisterPrefix(registeredPrefixId, onSuccess, onFailure);
308 }
309 
310 void
311 Face::doProcessEvents(time::milliseconds timeout, bool keepThread)
312 {
313  if (m_ioService.stopped()) {
314  m_ioService.reset(); // ensure that run()/poll() will do some work
315  }
316 
317  try {
318  if (timeout < time::milliseconds::zero()) {
319  // do not block if timeout is negative, but process pending events
320  m_ioService.poll();
321  return;
322  }
323 
324  if (timeout > time::milliseconds::zero()) {
325  boost::asio::io_service& ioService = m_ioService;
326  unique_ptr<boost::asio::io_service::work>& work = m_impl->m_ioServiceWork;
327  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.scheduleEvent(timeout,
328  [&ioService, &work] {
329  ioService.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.reset(new 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 } // namespace ndn
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
virtual void doProcessEvents(time::milliseconds timeout, bool keepThread)
Definition: face.cpp:311
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:85
virtual ~Face()
Definition: block.hpp:31
const RegisteredPrefixId * 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:232
declares the set of Interests a producer can serve, which starts with a name prefix, plus an optional regular expression
unique_ptr< T > make_unique(Args &&...args)
Definition: backports.hpp:96
const Parsed & getParsedConfiguration() const
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
Represents an Interest packet.
Definition: interest.hpp:42
#define NDN_LOG_DEBUG(expression)
Log at DEBUG level.
Definition: logger.hpp:262
bool has() const
Definition: packet.hpp:78
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:301
static shared_ptr< UnixTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
represents a Network Nack
Definition: nack.hpp:40
Declare a field.
Definition: field-decl.hpp:178
#define IO_CAPTURE_WEAK_IMPL(OP)
Definition: face.cpp:36
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:202
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:101
contains options for ControlCommand execution
shared_ptr< Transport > getTransport()
Definition: face.cpp:172
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
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:42
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:285
CommandOptions & setSigningInfo(const security::SigningInfo &signingInfo)
sets signing parameters
function< void(const InterestFilter &, const Interest &)> InterestCallback
Callback invoked when incoming Interest matches the specified InterestFilter.
Definition: face.hpp:65
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:42
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:210
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:80
void put(Data data)
Publish data packet.
Definition: face.cpp:216
OversizedPacketError(char pktType, const Name &name, size_t wireSize)
Constructor.
Definition: face.cpp:49
std::string to_string(const V &v)
Definition: backports.hpp:107
const PendingInterestId * expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express Interest.
Definition: face.cpp:178
function< void(const Interest &)> TimeoutCallback
Callback invoked when expressed Interest times out.
Definition: face.hpp:60
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:55
Represents a Data packet.
Definition: data.hpp:35
const RegisteredPrefixId * 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:272
Face(shared_ptr< Transport > transport=nullptr)
Create Face using given transport (or default transport if omitted)
Definition: face.cpp:59
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when expressed Interest gets satisfied with a Data packet.
Definition: face.hpp:50
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:194
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size