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  NDN_LOG_DEBUG("<I " << *interest2);
186 
187  IO_CAPTURE_WEAK_IMPL(dispatch) {
188  impl->asyncExpressInterest(interest2, afterSatisfied, afterNacked, afterTimeout);
190 
191  return reinterpret_cast<const PendingInterestId*>(interest2.get());
192 }
193 
194 void
195 Face::removePendingInterest(const PendingInterestId* pendingInterestId)
196 {
197  IO_CAPTURE_WEAK_IMPL(post) {
198  impl->asyncRemovePendingInterest(pendingInterestId);
200 }
201 
202 void
204 {
205  IO_CAPTURE_WEAK_IMPL(post) {
206  impl->asyncRemoveAllPendingInterests();
208 }
209 
210 size_t
212 {
213  return m_impl->m_pendingInterestTable.size();
214 }
215 
216 void
218 {
219  NDN_LOG_DEBUG("<D " << data.getName());
220  IO_CAPTURE_WEAK_IMPL(dispatch) {
221  impl->asyncPutData(data);
223 }
224 
225 void
227 {
228  NDN_LOG_DEBUG("<N " << nack.getInterest() << '~' << nack.getHeader().getReason());
229  IO_CAPTURE_WEAK_IMPL(dispatch) {
230  impl->asyncPutNack(nack);
232 }
233 
234 const RegisteredPrefixId*
236  const InterestCallback& onInterest,
237  const RegisterPrefixFailureCallback& onFailure,
238  const security::SigningInfo& signingInfo,
239  uint64_t flags)
240 {
241  return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags);
242 }
243 
244 const RegisteredPrefixId*
246  const InterestCallback& onInterest,
247  const RegisterPrefixSuccessCallback& onSuccess,
248  const RegisterPrefixFailureCallback& onFailure,
249  const security::SigningInfo& signingInfo,
250  uint64_t flags)
251 {
252  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
253 
254  nfd::CommandOptions options;
255  options.setSigningInfo(signingInfo);
256 
257  return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
258  onSuccess, onFailure, flags, options);
259 }
260 
261 const InterestFilterId*
263  const InterestCallback& onInterest)
264 {
265  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
266 
267  IO_CAPTURE_WEAK_IMPL(post) {
268  impl->asyncSetInterestFilter(filter);
270 
271  return reinterpret_cast<const InterestFilterId*>(filter.get());
272 }
273 
274 const RegisteredPrefixId*
276  const RegisterPrefixSuccessCallback& onSuccess,
277  const RegisterPrefixFailureCallback& onFailure,
278  const security::SigningInfo& signingInfo,
279  uint64_t flags)
280 {
281  nfd::CommandOptions options;
282  options.setSigningInfo(signingInfo);
283 
284  return m_impl->registerPrefix(prefix, nullptr, onSuccess, onFailure, flags, options);
285 }
286 
287 void
288 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
289 {
290  IO_CAPTURE_WEAK_IMPL(post) {
291  impl->asyncUnregisterPrefix(registeredPrefixId, nullptr, nullptr);
293 }
294 
295 void
296 Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
297 {
298  IO_CAPTURE_WEAK_IMPL(post) {
299  impl->asyncUnsetInterestFilter(interestFilterId);
301 }
302 
303 void
304 Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
305  const UnregisterPrefixSuccessCallback& onSuccess,
306  const UnregisterPrefixFailureCallback& onFailure)
307 {
308  IO_CAPTURE_WEAK_IMPL(post) {
309  impl->asyncUnregisterPrefix(registeredPrefixId, onSuccess, onFailure);
311 }
312 
313 void
314 Face::doProcessEvents(time::milliseconds timeout, bool keepThread)
315 {
316  if (m_ioService.stopped()) {
317  m_ioService.reset(); // ensure that run()/poll() will do some work
318  }
319 
320  try {
321  if (timeout < time::milliseconds::zero()) {
322  // do not block if timeout is negative, but process pending events
323  m_ioService.poll();
324  return;
325  }
326 
327  if (timeout > time::milliseconds::zero()) {
328  boost::asio::io_service& ioService = m_ioService;
329  unique_ptr<boost::asio::io_service::work>& work = m_impl->m_ioServiceWork;
330  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.scheduleEvent(timeout,
331  [&ioService, &work] {
332  ioService.stop();
333  work.reset();
334  });
335  }
336 
337  if (keepThread) {
338  // work will ensure that m_ioService is running until work object exists
339  m_impl->m_ioServiceWork.reset(new boost::asio::io_service::work(m_ioService));
340  }
341 
342  m_ioService.run();
343  }
344  catch (...) {
345  m_impl->m_ioServiceWork.reset();
346  m_impl->m_pendingInterestTable.clear();
347  m_impl->m_registeredPrefixTable.clear();
348  throw;
349  }
350 }
351 
352 void
354 {
355  IO_CAPTURE_WEAK_IMPL(post) {
356  this->asyncShutdown();
358 }
359 
360 void
361 Face::asyncShutdown()
362 {
363  m_impl->m_pendingInterestTable.clear();
364  m_impl->m_registeredPrefixTable.clear();
365 
366  if (m_transport->isConnected())
367  m_transport->close();
368 
369  m_impl->m_ioServiceWork.reset();
370 }
371 
375 template<typename NetPkt>
376 static void
377 extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket)
378 {
379  addTagFromField<lp::IncomingFaceIdTag, lp::IncomingFaceIdField>(netPacket, lpPacket);
380  addTagFromField<lp::CongestionMarkTag, lp::CongestionMarkField>(netPacket, lpPacket);
381 }
382 
383 void
384 Face::onReceiveElement(const Block& blockFromDaemon)
385 {
386  lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
387  // no need to distinguish
388 
389  Buffer::const_iterator begin, end;
390  std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
391  Block netPacket(&*begin, std::distance(begin, end));
392  switch (netPacket.type()) {
393  case tlv::Interest: {
394  auto interest = make_shared<Interest>(netPacket);
395  if (lpPacket.has<lp::NackField>()) {
396  auto nack = make_shared<lp::Nack>(std::move(*interest));
397  nack->setHeader(lpPacket.get<lp::NackField>());
398  extractLpLocalFields(*nack, lpPacket);
399  NDN_LOG_DEBUG(">N " << nack->getInterest() << '~' << nack->getHeader().getReason());
400  m_impl->nackPendingInterests(*nack);
401  }
402  else {
403  extractLpLocalFields(*interest, lpPacket);
404  NDN_LOG_DEBUG(">I " << *interest);
405  m_impl->processIncomingInterest(std::move(interest));
406  }
407  break;
408  }
409  case tlv::Data: {
410  auto data = make_shared<Data>(netPacket);
411  extractLpLocalFields(*data, lpPacket);
412  NDN_LOG_DEBUG(">D " << data->getName());
413  m_impl->satisfyPendingInterests(*data);
414  break;
415  }
416  }
417 }
418 
419 } // 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:314
const NackHeader & getHeader() const
Definition: nack.hpp:65
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:90
virtual ~Face()
Copyright (c) 2013-2017 Regents of the University of California.
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:235
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:73
const Parsed & getParsedConfiguration() const
const Interest & getInterest() const
Definition: nack.hpp:53
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:150
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:377
Signing parameters passed to KeyChain.
void unregisterPrefix(const RegisteredPrefixId *registeredPrefixId, const UnregisterPrefixSuccessCallback &onSuccess, const UnregisterPrefixFailureCallback &onFailure)
Unregister prefix from RIB.
Definition: face.cpp:304
static shared_ptr< UnixTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
represents a Network Nack
Definition: nack.hpp:40
#define IO_CAPTURE_WEAK_IMPL(OP)
Definition: face.cpp:36
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:203
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:353
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:80
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:75
Represents an absolute name.
Definition: name.hpp:42
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:43
void unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
Remove the registered prefix entry with the registeredPrefixId.
Definition: face.cpp:288
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:70
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:42
const Name & getName() const
Get name.
Definition: data.hpp:121
NackReason getReason() const
System configuration file for NDN platform.
Definition: config-file.hpp:48
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:112
size_t getNPendingInterests() const
Get number of pending Interests.
Definition: face.cpp:211
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:85
void put(Data data)
Publish data packet.
Definition: face.cpp:217
OversizedPacketError(char pktType, const Name &name, size_t wireSize)
Constructor.
Definition: face.cpp:49
std::string to_string(const V &v)
Definition: backports.hpp:84
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:65
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:60
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:275
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:55
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:195
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size