blob: fa5f989224da7e63252903561497317e156d410d [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 Shi0fa28452014-12-13 22:02:36 -070040#include "../management/nfd-controller.hpp"
41#include "../management/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 +000048using ndn::nfd::ControlParameters;
49
50/**
51 * @brief implementation detail of Face
52 */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070053class Face::Impl : noncopyable
54{
55public:
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080056 typedef ContainerWithOnEmptySignal<shared_ptr<PendingInterest>> PendingInterestTable;
Junxiao Shi103d8ed2016-08-07 20:34:10 +000057 typedef std::list<shared_ptr<InterestFilterRecord>> InterestFilterTable;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080058 typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070059
60 explicit
61 Impl(Face& face)
62 : m_face(face)
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080063 , m_scheduler(m_face.getIoService())
64 , m_processEventsTimeoutEvent(m_scheduler)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070065 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080066 auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
Junxiao Shi103d8ed2016-08-07 20:34:10 +000067 this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); });
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080068 // without this extra "post", transport can get paused (-async_read) and then resumed
69 // (+async_read) from within onInterest/onData callback. After onInterest/onData
70 // finishes, there is another +async_read with the same memory block. A few of such
71 // async_read duplications can cause various effects and result in segfault.
72 };
73
74 m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
75 m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070076 }
77
Junxiao Shi103d8ed2016-08-07 20:34:10 +000078public: // consumer
Junxiao Shia1ea5062014-12-27 22:33:39 -070079 void
Eric Newberry83872fd2015-08-06 17:01:24 -070080 asyncExpressInterest(shared_ptr<const Interest> interest,
81 const DataCallback& afterSatisfied,
82 const NackCallback& afterNacked,
83 const TimeoutCallback& afterTimeout)
Junxiao Shia1ea5062014-12-27 22:33:39 -070084 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080085 this->ensureConnected(true);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070086
Junxiao Shi103d8ed2016-08-07 20:34:10 +000087 auto entry = m_pendingInterestTable.insert(make_shared<PendingInterest>(
88 interest, afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080089 (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070090
Eric Newberry83872fd2015-08-06 17:01:24 -070091 lp::Packet packet;
92
Junxiao Shi4b469982015-12-03 18:20:19 +000093 shared_ptr<lp::NextHopFaceIdTag> nextHopFaceIdTag = interest->getTag<lp::NextHopFaceIdTag>();
94 if (nextHopFaceIdTag != nullptr) {
95 packet.add<lp::NextHopFaceIdField>(*nextHopFaceIdTag);
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080096 }
Eric Newberry83872fd2015-08-06 17:01:24 -070097
98 packet.add<lp::FragmentField>(std::make_pair(interest->wireEncode().begin(),
99 interest->wireEncode().end()));
100
101 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700102 }
103
104 void
105 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
106 {
107 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
108 }
109
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700110 void
Ilya Moiseenko56b0bf82015-11-08 11:14:28 -0500111 asyncRemoveAllPendingInterests()
112 {
113 m_pendingInterestTable.clear();
114 }
115
116 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000117 satisfyPendingInterests(const Data& data)
118 {
119 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
120 if ((*entry)->getInterest()->matchesData(data)) {
121 shared_ptr<PendingInterest> matchedEntry = *entry;
122 entry = m_pendingInterestTable.erase(entry);
123 matchedEntry->invokeDataCallback(data);
124 }
125 else {
126 ++entry;
127 }
128 }
129 }
130
131 void
132 nackPendingInterests(const lp::Nack& nack)
133 {
134 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
135 const Interest& pendingInterest = *(*entry)->getInterest();
136 if (pendingInterest == nack.getInterest()) {
137 shared_ptr<PendingInterest> matchedEntry = *entry;
138 entry = m_pendingInterestTable.erase(entry);
139 matchedEntry->invokeNackCallback(nack);
140 }
141 else {
142 ++entry;
143 }
144 }
145 }
146
147public: // producer
148 void
149 asyncSetInterestFilter(shared_ptr<InterestFilterRecord> interestFilterRecord)
150 {
151 m_interestFilterTable.push_back(interestFilterRecord);
152 }
153
154 void
155 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
156 {
157 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
158 m_interestFilterTable.end(),
159 MatchInterestFilterId(interestFilterId));
160 if (i != m_interestFilterTable.end()) {
161 m_interestFilterTable.erase(i);
162 }
163 }
164
165 void
166 processInterestFilters(Interest& interest)
167 {
168 for (const auto& filter : m_interestFilterTable) {
169 if (filter->doesMatch(interest.getName())) {
170 filter->invokeInterestCallback(interest);
171 }
172 }
173 }
174
175 void
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700176 asyncPutData(const shared_ptr<const Data>& data)
177 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800178 this->ensureConnected(true);
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700179
Eric Newberry83872fd2015-08-06 17:01:24 -0700180 lp::Packet packet;
181
Junxiao Shi4b469982015-12-03 18:20:19 +0000182 shared_ptr<lp::CachePolicyTag> cachePolicyTag = data->getTag<lp::CachePolicyTag>();
183 if (cachePolicyTag != nullptr) {
184 packet.add<lp::CachePolicyField>(*cachePolicyTag);
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800185 }
Eric Newberry83872fd2015-08-06 17:01:24 -0700186
187 packet.add<lp::FragmentField>(std::make_pair(data->wireEncode().begin(),
188 data->wireEncode().end()));
189
190 m_face.m_transport->send(packet.wireEncode());
191 }
192
193 void
194 asyncPutNack(shared_ptr<const lp::Nack> nack)
195 {
196 this->ensureConnected(true);
197
198 lp::Packet packet;
199 packet.add<lp::NackField>(nack->getHeader());
200
201 Block interest = nack->getInterest().wireEncode();
202 packet.add<lp::FragmentField>(std::make_pair(interest.begin(), interest.end()));
203
204 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700205 }
206
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000207public: // prefix registration
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700208 const RegisteredPrefixId*
209 registerPrefix(const Name& prefix,
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000210 shared_ptr<InterestFilterRecord> filter,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700211 const RegisterPrefixSuccessCallback& onSuccess,
212 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700213 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700214 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700215 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400216 ControlParameters params;
217 params.setName(prefix);
218 params.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700219
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400220 auto prefixToRegister = make_shared<RegisteredPrefix>(prefix, filter, options);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700221
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000222 m_face.m_nfdController->start<nfd::RibRegisterCommand>(
223 params,
224 [=] (const ControlParameters&) { this->afterPrefixRegistered(prefixToRegister, onSuccess); },
225 [=] (uint32_t code, const std::string& reason) { onFailure(prefixToRegister->getPrefix(), reason); },
226 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227
228 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
229 }
230
231 void
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000232 afterPrefixRegistered(shared_ptr<RegisteredPrefix> registeredPrefix,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700233 const RegisterPrefixSuccessCallback& onSuccess)
234 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800235 m_registeredPrefixTable.insert(registeredPrefix);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700236
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000237 if (registeredPrefix->getFilter() != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700238 // it was a combined operation
239 m_interestFilterTable.push_back(registeredPrefix->getFilter());
240 }
241
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000242 if (onSuccess != nullptr) {
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700243 onSuccess(registeredPrefix->getPrefix());
244 }
245 }
246
247 void
248 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
249 const UnregisterPrefixSuccessCallback& onSuccess,
250 const UnregisterPrefixFailureCallback& onFailure)
251 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400252 auto i = std::find_if(m_registeredPrefixTable.begin(),
253 m_registeredPrefixTable.end(),
254 MatchRegisteredPrefixId(registeredPrefixId));
255 if (i != m_registeredPrefixTable.end()) {
256 RegisteredPrefix& record = **i;
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400257 const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
258
259 if (filter != nullptr) {
260 // it was a combined operation
261 m_interestFilterTable.remove(filter);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700262 }
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400263
264 ControlParameters params;
265 params.setName(record.getPrefix());
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000266 m_face.m_nfdController->start<nfd::RibUnregisterCommand>(
267 params,
268 [=] (const ControlParameters&) { this->finalizeUnregisterPrefix(i, onSuccess); },
269 [=] (uint32_t code, const std::string& reason) { onFailure(reason); },
270 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 {
285 m_registeredPrefixTable.erase(item);
286
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000287 if (onSuccess != nullptr) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700288 onSuccess();
289 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700290 }
291
Junxiao Shi103d8ed2016-08-07 20:34:10 +0000292public: // IO routine
293 void
294 ensureConnected(bool wantResume)
295 {
296 if (!m_face.m_transport->isConnected())
297 m_face.m_transport->connect(m_face.m_ioService,
298 [=] (const Block& wire) { m_face.onReceiveElement(wire); });
299
300 if (wantResume && !m_face.m_transport->isReceiving()) {
301 m_face.m_transport->resume();
302 }
303 }
304
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700305 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800306 onEmptyPitOrNoRegisteredPrefixes()
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700307 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800308 if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
309 m_face.m_transport->pause();
310 if (!m_ioServiceWork) {
311 m_processEventsTimeoutEvent.cancel();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700312 }
313 }
314 }
315
316private:
317 Face& m_face;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800318 util::Scheduler m_scheduler;
319 util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700320
321 PendingInterestTable m_pendingInterestTable;
322 InterestFilterTable m_interestFilterTable;
323 RegisteredPrefixTable m_registeredPrefixTable;
324
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800325 unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700326
327 friend class Face;
328};
329
330} // namespace ndn
331
332#endif // NDN_DETAIL_FACE_IMPL_HPP