blob: 027ae2679c2f3fd255a2fcecab838837acb06124 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi4460e822017-08-07 22:02:45 +00002/*
Alexander Afanasyev1013fd02017-01-03 13:19:03 -08003 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070020 */
21
22#ifndef NDN_DETAIL_FACE_IMPL_HPP
23#define NDN_DETAIL_FACE_IMPL_HPP
24
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070025#include "../face.hpp"
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080026#include "container-with-on-empty-signal.hpp"
Junxiao Shi4460e822017-08-07 22:02:45 +000027#include "pending-interest.hpp"
28#include "registered-prefix.hpp"
Eric Newberry83872fd2015-08-06 17:01:24 -070029#include "../lp/packet.hpp"
Junxiao Shi4b469982015-12-03 18:20:19 +000030#include "../lp/tags.hpp"
Junxiao Shi4460e822017-08-07 22:02:45 +000031#include "../mgmt/nfd/command-options.hpp"
32#include "../mgmt/nfd/controller.hpp"
33#include "../transport/tcp-transport.hpp"
34#include "../transport/unix-transport.hpp"
35#include "../util/config-file.hpp"
36#include "../util/logger.hpp"
37#include "../util/scheduler.hpp"
38#include "../util/signal.hpp"
39
40NDN_LOG_INIT(ndn.Face);
41// INFO level: prefix registration, etc.
42//
43// DEBUG level: packet logging.
44// Each log entry starts with a direction symbol ('<' denotes an outgoing packet, '>' denotes an
45// incoming packet) and a packet type symbol ('I' denotes an Interest, 'D' denotes a Data, 'N'
46// denotes a Nack). Interest is printed as its string representation, Data is printed as name only,
47// Nack is printed as the Interest followed by the Nack reason and delimited by a '~' symbol. A
48// log line about an incoming packet may be followed by zero or more lines about Interest matching
49// InterestFilter, Data satisfying Interest, or Nack rejecting Interest, which are also written at
50// DEBUG level.
51//
52// TRACE level: more detailed unstructured messages.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070053
54namespace ndn {
55
Junxiao Shi103d8ed2016-08-07 20:34:10 +000056/**
57 * @brief implementation detail of Face
58 */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070059class Face::Impl : noncopyable
60{
61public:
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080062 typedef ContainerWithOnEmptySignal<shared_ptr<PendingInterest>> PendingInterestTable;
Junxiao Shi103d8ed2016-08-07 20:34:10 +000063 typedef std::list<shared_ptr<InterestFilterRecord>> InterestFilterTable;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080064 typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070065
66 explicit
67 Impl(Face& face)
68 : m_face(face)
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080069 , m_scheduler(m_face.getIoService())
70 , m_processEventsTimeoutEvent(m_scheduler)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070071 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080072 auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
Junxiao Shi103d8ed2016-08-07 20:34:10 +000073 this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); });
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080074 // without this extra "post", transport can get paused (-async_read) and then resumed
75 // (+async_read) from within onInterest/onData callback. After onInterest/onData
76 // finishes, there is another +async_read with the same memory block. A few of such
77 // async_read duplications can cause various effects and result in segfault.
78 };
79
80 m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
81 m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070082 }
83
Junxiao Shi103d8ed2016-08-07 20:34:10 +000084public: // consumer
Junxiao Shia1ea5062014-12-27 22:33:39 -070085 void
Eric Newberry83872fd2015-08-06 17:01:24 -070086 asyncExpressInterest(shared_ptr<const Interest> interest,
87 const DataCallback& afterSatisfied,
88 const NackCallback& afterNacked,
89 const TimeoutCallback& afterTimeout)
Junxiao Shia1ea5062014-12-27 22:33:39 -070090 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080091 this->ensureConnected(true);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070092
Junxiao Shi103d8ed2016-08-07 20:34:10 +000093 auto entry = m_pendingInterestTable.insert(make_shared<PendingInterest>(
94 interest, afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080095 (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070096
Eric Newberry83872fd2015-08-06 17:01:24 -070097 lp::Packet packet;
98
Junxiao Shi4b469982015-12-03 18:20:19 +000099 shared_ptr<lp::NextHopFaceIdTag> nextHopFaceIdTag = interest->getTag<lp::NextHopFaceIdTag>();
100 if (nextHopFaceIdTag != nullptr) {
101 packet.add<lp::NextHopFaceIdField>(*nextHopFaceIdTag);
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800102 }
Eric Newberry83872fd2015-08-06 17:01:24 -0700103
Eric Newberry4d261b62016-11-10 13:40:09 -0700104 shared_ptr<lp::CongestionMarkTag> congestionMarkTag = interest->getTag<lp::CongestionMarkTag>();
105 if (congestionMarkTag != nullptr) {
106 packet.add<lp::CongestionMarkField>(*congestionMarkTag);
107 }
108
Eric Newberry83872fd2015-08-06 17:01:24 -0700109 packet.add<lp::FragmentField>(std::make_pair(interest->wireEncode().begin(),
110 interest->wireEncode().end()));
111
112 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700113 }
114
115 void
116 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
117 {
118 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
119 }
120
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700121 void
Ilya Moiseenko56b0bf82015-11-08 11:14:28 -0500122 asyncRemoveAllPendingInterests()
123 {
124 m_pendingInterestTable.clear();
125 }
126
127 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000128 satisfyPendingInterests(const Data& data)
129 {
130 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
131 if ((*entry)->getInterest()->matchesData(data)) {
132 shared_ptr<PendingInterest> matchedEntry = *entry;
Junxiao Shi4460e822017-08-07 22:02:45 +0000133 NDN_LOG_DEBUG(" satisfying " << *matchedEntry->getInterest());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000134 entry = m_pendingInterestTable.erase(entry);
135 matchedEntry->invokeDataCallback(data);
136 }
137 else {
138 ++entry;
139 }
140 }
141 }
142
143 void
144 nackPendingInterests(const lp::Nack& nack)
145 {
146 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
147 const Interest& pendingInterest = *(*entry)->getInterest();
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800148 if (nack.getInterest().matchesInterest(pendingInterest)) {
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000149 shared_ptr<PendingInterest> matchedEntry = *entry;
Junxiao Shi4460e822017-08-07 22:02:45 +0000150 NDN_LOG_DEBUG(" nacking " << *matchedEntry->getInterest());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000151 entry = m_pendingInterestTable.erase(entry);
152 matchedEntry->invokeNackCallback(nack);
153 }
154 else {
155 ++entry;
156 }
157 }
158 }
159
160public: // producer
161 void
162 asyncSetInterestFilter(shared_ptr<InterestFilterRecord> interestFilterRecord)
163 {
Junxiao Shi4460e822017-08-07 22:02:45 +0000164 NDN_LOG_INFO("setting InterestFilter: " << interestFilterRecord->getFilter());
165 m_interestFilterTable.push_back(std::move(interestFilterRecord));
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000166 }
167
168 void
169 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
170 {
171 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
172 m_interestFilterTable.end(),
173 MatchInterestFilterId(interestFilterId));
174 if (i != m_interestFilterTable.end()) {
Junxiao Shi4460e822017-08-07 22:02:45 +0000175 NDN_LOG_INFO("unsetting InterestFilter: " << (*i)->getFilter());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000176 m_interestFilterTable.erase(i);
177 }
178 }
179
180 void
Junxiao Shi4460e822017-08-07 22:02:45 +0000181 processInterestFilters(const Interest& interest)
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000182 {
183 for (const auto& filter : m_interestFilterTable) {
184 if (filter->doesMatch(interest.getName())) {
Junxiao Shi4460e822017-08-07 22:02:45 +0000185 NDN_LOG_DEBUG(" matches " << filter->getFilter());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000186 filter->invokeInterestCallback(interest);
187 }
188 }
189 }
190
191 void
Junxiao Shie7bb6c82016-08-08 23:16:35 +0000192 asyncSend(const Block& wire)
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700193 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800194 this->ensureConnected(true);
Junxiao Shie7bb6c82016-08-08 23:16:35 +0000195 m_face.m_transport->send(wire);
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700196 }
197
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000198public: // prefix registration
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700199 const RegisteredPrefixId*
200 registerPrefix(const Name& prefix,
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000201 shared_ptr<InterestFilterRecord> filter,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700202 const RegisterPrefixSuccessCallback& onSuccess,
203 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700204 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700205 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700206 {
Junxiao Shi4460e822017-08-07 22:02:45 +0000207 NDN_LOG_INFO("registering prefix: " << prefix);
208 auto record = make_shared<RegisteredPrefix>(prefix, filter, options);
209
Junxiao Shie7c7f152016-08-20 22:36:22 +0000210 nfd::ControlParameters params;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400211 params.setName(prefix);
212 params.setFlags(flags);
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000213 m_face.m_nfdController->start<nfd::RibRegisterCommand>(
214 params,
Junxiao Shi4460e822017-08-07 22:02:45 +0000215 [=] (const nfd::ControlParameters&) { this->afterPrefixRegistered(record, onSuccess); },
216 [=] (const nfd::ControlResponse& resp) {
217 NDN_LOG_INFO("register prefix failed: " << record->getPrefix());
218 onFailure(record->getPrefix(), resp.getText());
219 },
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000220 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700221
Junxiao Shi4460e822017-08-07 22:02:45 +0000222 return reinterpret_cast<const RegisteredPrefixId*>(record.get());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700223 }
224
225 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000226 afterPrefixRegistered(shared_ptr<RegisteredPrefix> registeredPrefix,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227 const RegisterPrefixSuccessCallback& onSuccess)
228 {
Junxiao Shi4460e822017-08-07 22:02:45 +0000229 NDN_LOG_INFO("registered prefix: " << registeredPrefix->getPrefix());
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800230 m_registeredPrefixTable.insert(registeredPrefix);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700231
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000232 if (registeredPrefix->getFilter() != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700233 // it was a combined operation
234 m_interestFilterTable.push_back(registeredPrefix->getFilter());
235 }
236
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000237 if (onSuccess != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700238 onSuccess(registeredPrefix->getPrefix());
239 }
240 }
241
242 void
243 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
244 const UnregisterPrefixSuccessCallback& onSuccess,
245 const UnregisterPrefixFailureCallback& onFailure)
246 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400247 auto i = std::find_if(m_registeredPrefixTable.begin(),
248 m_registeredPrefixTable.end(),
249 MatchRegisteredPrefixId(registeredPrefixId));
250 if (i != m_registeredPrefixTable.end()) {
251 RegisteredPrefix& record = **i;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400252 const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
253
254 if (filter != nullptr) {
255 // it was a combined operation
256 m_interestFilterTable.remove(filter);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700257 }
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400258
Junxiao Shi4460e822017-08-07 22:02:45 +0000259 NDN_LOG_INFO("unregistering prefix: " << record.getPrefix());
260
Junxiao Shie7c7f152016-08-20 22:36:22 +0000261 nfd::ControlParameters params;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400262 params.setName(record.getPrefix());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000263 m_face.m_nfdController->start<nfd::RibUnregisterCommand>(
264 params,
Junxiao Shie7c7f152016-08-20 22:36:22 +0000265 [=] (const nfd::ControlParameters&) { this->finalizeUnregisterPrefix(i, onSuccess); },
Junxiao Shi4460e822017-08-07 22:02:45 +0000266 [=] (const nfd::ControlResponse& resp) {
267 NDN_LOG_INFO("unregister prefix failed: " << params.getName());
268 onFailure(resp.getText());
269 },
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000270 record.getCommandOptions());
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400271 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400272 else {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400273 if (onFailure != nullptr) {
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400274 onFailure("Unrecognized PrefixId");
275 }
276 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700277
278 // there cannot be two registered prefixes with the same id
279 }
280
281 void
282 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
283 const UnregisterPrefixSuccessCallback& onSuccess)
284 {
Junxiao Shi4460e822017-08-07 22:02:45 +0000285 NDN_LOG_INFO("unregistered prefix: " << (*item)->getPrefix());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700286 m_registeredPrefixTable.erase(item);
287
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000288 if (onSuccess != nullptr) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700289 onSuccess();
290 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700291 }
292
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000293public: // IO routine
294 void
295 ensureConnected(bool wantResume)
296 {
297 if (!m_face.m_transport->isConnected())
298 m_face.m_transport->connect(m_face.m_ioService,
299 [=] (const Block& wire) { m_face.onReceiveElement(wire); });
300
301 if (wantResume && !m_face.m_transport->isReceiving()) {
302 m_face.m_transport->resume();
303 }
304 }
305
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700306 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800307 onEmptyPitOrNoRegisteredPrefixes()
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700308 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800309 if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
310 m_face.m_transport->pause();
311 if (!m_ioServiceWork) {
312 m_processEventsTimeoutEvent.cancel();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700313 }
314 }
315 }
316
317private:
318 Face& m_face;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800319 util::Scheduler m_scheduler;
320 util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700321
322 PendingInterestTable m_pendingInterestTable;
323 InterestFilterTable m_interestFilterTable;
324 RegisteredPrefixTable m_registeredPrefixTable;
325
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800326 unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700327
328 friend class Face;
329};
330
331} // namespace ndn
332
333#endif // NDN_DETAIL_FACE_IMPL_HPP