blob: 9ce4a69c1176d107ad4af54a29f44443d01de9af [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07002/**
Junxiao Shi446de3c2016-07-25 22:38:16 +00003 * Copyright (c) 2013-2016 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
25#include "../common.hpp"
26#include "../face.hpp"
27
28#include "registered-prefix.hpp"
29#include "pending-interest.hpp"
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080030#include "container-with-on-empty-signal.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070031
32#include "../util/scheduler.hpp"
33#include "../util/config-file.hpp"
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080034#include "../util/signal.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070035
Junxiao Shi0fa28452014-12-13 22:02:36 -070036#include "../transport/transport.hpp"
37#include "../transport/unix-transport.hpp"
38#include "../transport/tcp-transport.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070039
Junxiao Shi7357ef22016-09-07 02:39:37 +000040#include "../mgmt/nfd/controller.hpp"
41#include "../mgmt/nfd/command-options.hpp"
Eric Newberry83872fd2015-08-06 17:01:24 -070042
43#include "../lp/packet.hpp"
Junxiao Shi4b469982015-12-03 18:20:19 +000044#include "../lp/tags.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070045
46namespace ndn {
47
Junxiao Shi103d8ed2016-08-07 20:34:10 +000048/**
49 * @brief implementation detail of Face
50 */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070051class Face::Impl : noncopyable
52{
53public:
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080054 typedef ContainerWithOnEmptySignal<shared_ptr<PendingInterest>> PendingInterestTable;
Junxiao Shi103d8ed2016-08-07 20:34:10 +000055 typedef std::list<shared_ptr<InterestFilterRecord>> InterestFilterTable;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080056 typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070057
58 explicit
59 Impl(Face& face)
60 : m_face(face)
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080061 , m_scheduler(m_face.getIoService())
62 , m_processEventsTimeoutEvent(m_scheduler)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070063 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080064 auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
Junxiao Shi103d8ed2016-08-07 20:34:10 +000065 this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); });
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080066 // without this extra "post", transport can get paused (-async_read) and then resumed
67 // (+async_read) from within onInterest/onData callback. After onInterest/onData
68 // finishes, there is another +async_read with the same memory block. A few of such
69 // async_read duplications can cause various effects and result in segfault.
70 };
71
72 m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
73 m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070074 }
75
Junxiao Shi103d8ed2016-08-07 20:34:10 +000076public: // consumer
Junxiao Shia1ea5062014-12-27 22:33:39 -070077 void
Eric Newberry83872fd2015-08-06 17:01:24 -070078 asyncExpressInterest(shared_ptr<const Interest> interest,
79 const DataCallback& afterSatisfied,
80 const NackCallback& afterNacked,
81 const TimeoutCallback& afterTimeout)
Junxiao Shia1ea5062014-12-27 22:33:39 -070082 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080083 this->ensureConnected(true);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070084
Junxiao Shi103d8ed2016-08-07 20:34:10 +000085 auto entry = m_pendingInterestTable.insert(make_shared<PendingInterest>(
86 interest, afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080087 (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070088
Eric Newberry83872fd2015-08-06 17:01:24 -070089 lp::Packet packet;
90
Junxiao Shi4b469982015-12-03 18:20:19 +000091 shared_ptr<lp::NextHopFaceIdTag> nextHopFaceIdTag = interest->getTag<lp::NextHopFaceIdTag>();
92 if (nextHopFaceIdTag != nullptr) {
93 packet.add<lp::NextHopFaceIdField>(*nextHopFaceIdTag);
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080094 }
Eric Newberry83872fd2015-08-06 17:01:24 -070095
Eric Newberry4d261b62016-11-10 13:40:09 -070096 shared_ptr<lp::CongestionMarkTag> congestionMarkTag = interest->getTag<lp::CongestionMarkTag>();
97 if (congestionMarkTag != nullptr) {
98 packet.add<lp::CongestionMarkField>(*congestionMarkTag);
99 }
100
Eric Newberry83872fd2015-08-06 17:01:24 -0700101 packet.add<lp::FragmentField>(std::make_pair(interest->wireEncode().begin(),
102 interest->wireEncode().end()));
103
104 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700105 }
106
107 void
108 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
109 {
110 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
111 }
112
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700113 void
Ilya Moiseenko56b0bf82015-11-08 11:14:28 -0500114 asyncRemoveAllPendingInterests()
115 {
116 m_pendingInterestTable.clear();
117 }
118
119 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000120 satisfyPendingInterests(const Data& data)
121 {
122 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
123 if ((*entry)->getInterest()->matchesData(data)) {
124 shared_ptr<PendingInterest> matchedEntry = *entry;
125 entry = m_pendingInterestTable.erase(entry);
126 matchedEntry->invokeDataCallback(data);
127 }
128 else {
129 ++entry;
130 }
131 }
132 }
133
134 void
135 nackPendingInterests(const lp::Nack& nack)
136 {
137 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
138 const Interest& pendingInterest = *(*entry)->getInterest();
139 if (pendingInterest == nack.getInterest()) {
140 shared_ptr<PendingInterest> matchedEntry = *entry;
141 entry = m_pendingInterestTable.erase(entry);
142 matchedEntry->invokeNackCallback(nack);
143 }
144 else {
145 ++entry;
146 }
147 }
148 }
149
150public: // producer
151 void
152 asyncSetInterestFilter(shared_ptr<InterestFilterRecord> interestFilterRecord)
153 {
154 m_interestFilterTable.push_back(interestFilterRecord);
155 }
156
157 void
158 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
159 {
160 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
161 m_interestFilterTable.end(),
162 MatchInterestFilterId(interestFilterId));
163 if (i != m_interestFilterTable.end()) {
164 m_interestFilterTable.erase(i);
165 }
166 }
167
168 void
169 processInterestFilters(Interest& interest)
170 {
171 for (const auto& filter : m_interestFilterTable) {
172 if (filter->doesMatch(interest.getName())) {
173 filter->invokeInterestCallback(interest);
174 }
175 }
176 }
177
178 void
Junxiao Shie7bb6c82016-08-08 23:16:35 +0000179 asyncSend(const Block& wire)
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700180 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800181 this->ensureConnected(true);
Junxiao Shie7bb6c82016-08-08 23:16:35 +0000182 m_face.m_transport->send(wire);
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700183 }
184
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000185public: // prefix registration
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700186 const RegisteredPrefixId*
187 registerPrefix(const Name& prefix,
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000188 shared_ptr<InterestFilterRecord> filter,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700189 const RegisterPrefixSuccessCallback& onSuccess,
190 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700191 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700192 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700193 {
Junxiao Shie7c7f152016-08-20 22:36:22 +0000194 nfd::ControlParameters params;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400195 params.setName(prefix);
196 params.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700197
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400198 auto prefixToRegister = make_shared<RegisteredPrefix>(prefix, filter, options);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700199
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000200 m_face.m_nfdController->start<nfd::RibRegisterCommand>(
201 params,
Junxiao Shie7c7f152016-08-20 22:36:22 +0000202 [=] (const nfd::ControlParameters&) { this->afterPrefixRegistered(prefixToRegister, onSuccess); },
203 [=] (const nfd::ControlResponse& resp) { onFailure(prefixToRegister->getPrefix(), resp.getText()); },
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000204 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700205
206 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
207 }
208
209 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000210 afterPrefixRegistered(shared_ptr<RegisteredPrefix> registeredPrefix,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700211 const RegisterPrefixSuccessCallback& onSuccess)
212 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800213 m_registeredPrefixTable.insert(registeredPrefix);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700214
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000215 if (registeredPrefix->getFilter() != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700216 // it was a combined operation
217 m_interestFilterTable.push_back(registeredPrefix->getFilter());
218 }
219
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000220 if (onSuccess != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700221 onSuccess(registeredPrefix->getPrefix());
222 }
223 }
224
225 void
226 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
227 const UnregisterPrefixSuccessCallback& onSuccess,
228 const UnregisterPrefixFailureCallback& onFailure)
229 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400230 auto i = std::find_if(m_registeredPrefixTable.begin(),
231 m_registeredPrefixTable.end(),
232 MatchRegisteredPrefixId(registeredPrefixId));
233 if (i != m_registeredPrefixTable.end()) {
234 RegisteredPrefix& record = **i;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400235 const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
236
237 if (filter != nullptr) {
238 // it was a combined operation
239 m_interestFilterTable.remove(filter);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700240 }
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400241
Junxiao Shie7c7f152016-08-20 22:36:22 +0000242 nfd::ControlParameters params;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400243 params.setName(record.getPrefix());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000244 m_face.m_nfdController->start<nfd::RibUnregisterCommand>(
245 params,
Junxiao Shie7c7f152016-08-20 22:36:22 +0000246 [=] (const nfd::ControlParameters&) { this->finalizeUnregisterPrefix(i, onSuccess); },
247 [=] (const nfd::ControlResponse& resp) { onFailure(resp.getText()); },
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000248 record.getCommandOptions());
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400249 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400250 else {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400251 if (onFailure != nullptr) {
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400252 onFailure("Unrecognized PrefixId");
253 }
254 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700255
256 // there cannot be two registered prefixes with the same id
257 }
258
259 void
260 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
261 const UnregisterPrefixSuccessCallback& onSuccess)
262 {
263 m_registeredPrefixTable.erase(item);
264
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000265 if (onSuccess != nullptr) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700266 onSuccess();
267 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700268 }
269
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000270public: // IO routine
271 void
272 ensureConnected(bool wantResume)
273 {
274 if (!m_face.m_transport->isConnected())
275 m_face.m_transport->connect(m_face.m_ioService,
276 [=] (const Block& wire) { m_face.onReceiveElement(wire); });
277
278 if (wantResume && !m_face.m_transport->isReceiving()) {
279 m_face.m_transport->resume();
280 }
281 }
282
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700283 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800284 onEmptyPitOrNoRegisteredPrefixes()
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700285 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800286 if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
287 m_face.m_transport->pause();
288 if (!m_ioServiceWork) {
289 m_processEventsTimeoutEvent.cancel();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700290 }
291 }
292 }
293
294private:
295 Face& m_face;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800296 util::Scheduler m_scheduler;
297 util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700298
299 PendingInterestTable m_pendingInterestTable;
300 InterestFilterTable m_interestFilterTable;
301 RegisteredPrefixTable m_registeredPrefixTable;
302
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800303 unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700304
305 friend class Face;
306};
307
308} // namespace ndn
309
310#endif // NDN_DETAIL_FACE_IMPL_HPP