blob: 808355f8af7163a3bad065e2196259d6bdc8f290 [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/**
Alexander Afanasyev9d158f02015-02-17 21:30:19 -08003 * Copyright (c) 2013-2015 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#include "../management/nfd-local-control-header.hpp"
43
44#include "../lp/packet.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070045
46namespace ndn {
47
48class Face::Impl : noncopyable
49{
50public:
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080051 typedef ContainerWithOnEmptySignal<shared_ptr<PendingInterest>> PendingInterestTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070052 typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080053 typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070054
55 explicit
56 Impl(Face& face)
57 : m_face(face)
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080058 , m_scheduler(m_face.getIoService())
59 , m_processEventsTimeoutEvent(m_scheduler)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070060 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080061 auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
62 this->m_face.getIoService().post(bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this));
63 // without this extra "post", transport can get paused (-async_read) and then resumed
64 // (+async_read) from within onInterest/onData callback. After onInterest/onData
65 // finishes, there is another +async_read with the same memory block. A few of such
66 // async_read duplications can cause various effects and result in segfault.
67 };
68
69 m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
70 m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070071 }
72
73 /////////////////////////////////////////////////////////////////////////////////////////////////
74 /////////////////////////////////////////////////////////////////////////////////////////////////
75
76 void
77 satisfyPendingInterests(Data& data)
78 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080079 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
Eric Newberry83872fd2015-08-06 17:01:24 -070080 if ((*entry)->getInterest()->matchesData(data)) {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080081 shared_ptr<PendingInterest> matchedEntry = *entry;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070082
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080083 entry = m_pendingInterestTable.erase(entry);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070084
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080085 matchedEntry->invokeDataCallback(data);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070086 }
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080087 else
88 ++entry;
89 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070090 }
91
92 void
Eric Newberry83872fd2015-08-06 17:01:24 -070093 nackPendingInterests(const lp::Nack& nack)
94 {
95 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
96 const Interest& pendingInterest = *(*entry)->getInterest();
97 if (pendingInterest == nack.getInterest()) {
98 shared_ptr<PendingInterest> matchedEntry = *entry;
99
100 entry = m_pendingInterestTable.erase(entry);
101
102 matchedEntry->invokeNackCallback(nack);
103 }
104 else {
105 ++entry;
106 }
107 }
108 }
109
110 void
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700111 processInterestFilters(Interest& interest)
112 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800113 for (const auto& filter : m_interestFilterTable) {
114 if (filter->doesMatch(interest.getName())) {
115 filter->invokeInterestCallback(interest);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700116 }
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800117 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700118 }
119
120 /////////////////////////////////////////////////////////////////////////////////////////////////
121 /////////////////////////////////////////////////////////////////////////////////////////////////
122
123 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800124 ensureConnected(bool wantResume)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700125 {
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700126 if (!m_face.m_transport->isConnected())
Junxiao Shi2cced062014-11-02 21:27:38 -0700127 m_face.m_transport->connect(m_face.m_ioService,
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700128 bind(&Face::onReceiveElement, &m_face, _1));
129
Junxiao Shia1ea5062014-12-27 22:33:39 -0700130 if (wantResume && !m_face.m_transport->isExpectingData())
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700131 m_face.m_transport->resume();
Junxiao Shia1ea5062014-12-27 22:33:39 -0700132 }
133
134 void
Eric Newberry83872fd2015-08-06 17:01:24 -0700135 asyncExpressInterest(shared_ptr<const Interest> interest,
136 const DataCallback& afterSatisfied,
137 const NackCallback& afterNacked,
138 const TimeoutCallback& afterTimeout)
Junxiao Shia1ea5062014-12-27 22:33:39 -0700139 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800140 this->ensureConnected(true);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700141
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800142 auto entry =
143 m_pendingInterestTable.insert(make_shared<PendingInterest>(interest,
Eric Newberry83872fd2015-08-06 17:01:24 -0700144 afterSatisfied,
145 afterNacked,
146 afterTimeout,
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800147 ref(m_scheduler))).first;
148 (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700149
Eric Newberry83872fd2015-08-06 17:01:24 -0700150 lp::Packet packet;
151
152 nfd::LocalControlHeader localControlHeader = interest->getLocalControlHeader();
153 if (localControlHeader.hasNextHopFaceId()) {
154 packet.add<lp::NextHopFaceIdField>(localControlHeader.getNextHopFaceId());
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800155 }
Eric Newberry83872fd2015-08-06 17:01:24 -0700156
157 packet.add<lp::FragmentField>(std::make_pair(interest->wireEncode().begin(),
158 interest->wireEncode().end()));
159
160 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700161 }
162
163 void
164 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
165 {
166 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
167 }
168
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700169 void
Ilya Moiseenko56b0bf82015-11-08 11:14:28 -0500170 asyncRemoveAllPendingInterests()
171 {
172 m_pendingInterestTable.clear();
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
182 nfd::LocalControlHeader localControlHeader = data->getLocalControlHeader();
183 if (localControlHeader.hasCachingPolicy()) {
184 switch (localControlHeader.getCachingPolicy()) {
185 case nfd::LocalControlHeader::CachingPolicy::NO_CACHE: {
186 lp::CachePolicy cachePolicy;
187 cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
188 packet.add<lp::CachePolicyField>(cachePolicy);
189 break;
190 }
191 default:
192 break;
193 }
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800194 }
Eric Newberry83872fd2015-08-06 17:01:24 -0700195
196 packet.add<lp::FragmentField>(std::make_pair(data->wireEncode().begin(),
197 data->wireEncode().end()));
198
199 m_face.m_transport->send(packet.wireEncode());
200 }
201
202 void
203 asyncPutNack(shared_ptr<const lp::Nack> nack)
204 {
205 this->ensureConnected(true);
206
207 lp::Packet packet;
208 packet.add<lp::NackField>(nack->getHeader());
209
210 Block interest = nack->getInterest().wireEncode();
211 packet.add<lp::FragmentField>(std::make_pair(interest.begin(), interest.end()));
212
213 m_face.m_transport->send(packet.wireEncode());
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700214 }
215
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700216 /////////////////////////////////////////////////////////////////////////////////////////////////
217 /////////////////////////////////////////////////////////////////////////////////////////////////
218
219 void
220 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
221 {
222 m_interestFilterTable.push_back(interestFilterRecord);
223 }
224
225 void
226 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
227 {
228 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
229 m_interestFilterTable.end(),
230 MatchInterestFilterId(interestFilterId));
231 if (i != m_interestFilterTable.end())
232 {
233 m_interestFilterTable.erase(i);
234 }
235 }
236
237 /////////////////////////////////////////////////////////////////////////////////////////////////
238 /////////////////////////////////////////////////////////////////////////////////////////////////
239
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700240 const RegisteredPrefixId*
241 registerPrefix(const Name& prefix,
242 const shared_ptr<InterestFilterRecord>& filter,
243 const RegisterPrefixSuccessCallback& onSuccess,
244 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700245 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700246 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700247 {
248 using namespace nfd;
249
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400250 ControlParameters params;
251 params.setName(prefix);
252 params.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700253
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400254 auto prefixToRegister = make_shared<RegisteredPrefix>(prefix, filter, options);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700255
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400256 m_face.m_nfdController->start<RibRegisterCommand>(params,
257 bind(&Impl::afterPrefixRegistered, this,
258 prefixToRegister, onSuccess),
259 bind(onFailure, prefixToRegister->getPrefix(), _2),
260 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700261
262 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
263 }
264
265 void
266 afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
267 const RegisterPrefixSuccessCallback& onSuccess)
268 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800269 m_registeredPrefixTable.insert(registeredPrefix);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700270
271 if (static_cast<bool>(registeredPrefix->getFilter())) {
272 // it was a combined operation
273 m_interestFilterTable.push_back(registeredPrefix->getFilter());
274 }
275
276 if (static_cast<bool>(onSuccess)) {
277 onSuccess(registeredPrefix->getPrefix());
278 }
279 }
280
281 void
282 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
283 const UnregisterPrefixSuccessCallback& onSuccess,
284 const UnregisterPrefixFailureCallback& onFailure)
285 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400286 using namespace nfd;
287 auto i = std::find_if(m_registeredPrefixTable.begin(),
288 m_registeredPrefixTable.end(),
289 MatchRegisteredPrefixId(registeredPrefixId));
290 if (i != m_registeredPrefixTable.end()) {
291 RegisteredPrefix& record = **i;
292
293 const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
294
295 if (filter != nullptr) {
296 // it was a combined operation
297 m_interestFilterTable.remove(filter);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700298 }
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400299
300 ControlParameters params;
301 params.setName(record.getPrefix());
302 m_face.m_nfdController->start<RibUnregisterCommand>(params,
303 bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
304 bind(onFailure, _2),
305 record.getCommandOptions());
306 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400307 else {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400308 if (onFailure != nullptr) {
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400309 onFailure("Unrecognized PrefixId");
310 }
311 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700312
313 // there cannot be two registered prefixes with the same id
314 }
315
316 void
317 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
318 const UnregisterPrefixSuccessCallback& onSuccess)
319 {
320 m_registeredPrefixTable.erase(item);
321
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700322 if (static_cast<bool>(onSuccess)) {
323 onSuccess();
324 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700325 }
326
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700327 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800328 onEmptyPitOrNoRegisteredPrefixes()
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700329 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800330 if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
331 m_face.m_transport->pause();
332 if (!m_ioServiceWork) {
333 m_processEventsTimeoutEvent.cancel();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700334 }
335 }
336 }
337
338private:
339 Face& m_face;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800340 util::Scheduler m_scheduler;
341 util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700342
343 PendingInterestTable m_pendingInterestTable;
344 InterestFilterTable m_interestFilterTable;
345 RegisteredPrefixTable m_registeredPrefixTable;
346
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800347 unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700348
349 friend class Face;
350};
351
352} // namespace ndn
353
354#endif // NDN_DETAIL_FACE_IMPL_HPP