blob: c13906afc5df8406766f7baa296c2a725089cbd3 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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"
30
31#include "../util/scheduler.hpp"
32#include "../util/config-file.hpp"
33
Junxiao Shi0fa28452014-12-13 22:02:36 -070034#include "../transport/transport.hpp"
35#include "../transport/unix-transport.hpp"
36#include "../transport/tcp-transport.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070037
Junxiao Shi0fa28452014-12-13 22:02:36 -070038#include "../management/nfd-controller.hpp"
39#include "../management/nfd-command-options.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070040
41namespace ndn {
42
43class Face::Impl : noncopyable
44{
45public:
46 typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
47 typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
48 typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
49
50 explicit
51 Impl(Face& face)
52 : m_face(face)
53 {
54 }
55
56 /////////////////////////////////////////////////////////////////////////////////////////////////
57 /////////////////////////////////////////////////////////////////////////////////////////////////
58
59 void
60 satisfyPendingInterests(Data& data)
61 {
62 for (PendingInterestTable::iterator i = m_pendingInterestTable.begin();
63 i != m_pendingInterestTable.end();
64 )
65 {
66 if ((*i)->getInterest()->matchesData(data))
67 {
68 // Copy pointers to the objects and remove the PIT entry before calling the callback.
69 OnData onData = (*i)->getOnData();
70 shared_ptr<const Interest> interest = (*i)->getInterest();
71
72 PendingInterestTable::iterator next = i;
73 ++next;
74 m_pendingInterestTable.erase(i);
75 i = next;
76
77 if (static_cast<bool>(onData)) {
78 onData(*interest, data);
79 }
80 }
81 else
82 ++i;
83 }
84 }
85
86 void
87 processInterestFilters(Interest& interest)
88 {
89 for (InterestFilterTable::iterator i = m_interestFilterTable.begin();
90 i != m_interestFilterTable.end();
91 ++i)
92 {
93 if ((*i)->doesMatch(interest.getName()))
94 {
95 (**i)(interest);
96 }
97 }
98 }
99
100 /////////////////////////////////////////////////////////////////////////////////////////////////
101 /////////////////////////////////////////////////////////////////////////////////////////////////
102
103 void
Junxiao Shia1ea5062014-12-27 22:33:39 -0700104 ensureConnected(bool wantResume = true)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700105 {
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700106 if (!m_face.m_transport->isConnected())
Junxiao Shi2cced062014-11-02 21:27:38 -0700107 m_face.m_transport->connect(m_face.m_ioService,
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700108 bind(&Face::onReceiveElement, &m_face, _1));
109
Junxiao Shia1ea5062014-12-27 22:33:39 -0700110 if (wantResume && !m_face.m_transport->isExpectingData())
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700111 m_face.m_transport->resume();
Junxiao Shia1ea5062014-12-27 22:33:39 -0700112 }
113
114 void
115 asyncExpressInterest(const shared_ptr<const Interest>& interest,
116 const OnData& onData, const OnTimeout& onTimeout)
117 {
118 this->ensureConnected();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700119
120 m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
121
Jiewen Tanc759a202015-01-29 23:31:09 -0800122 if (!interest->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_NEXT_HOP))
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700123 {
124 // encode only NextHopFaceId towards the forwarder
125 m_face.m_transport->send(interest->getLocalControlHeader()
Jiewen Tanc759a202015-01-29 23:31:09 -0800126 .wireEncode(*interest, nfd::LocalControlHeader::ENCODE_NEXT_HOP),
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700127 interest->wireEncode());
128 }
129 else
130 {
131 m_face.m_transport->send(interest->wireEncode());
132 }
133
134 if (!m_pitTimeoutCheckTimerActive) {
135 m_pitTimeoutCheckTimerActive = true;
136 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
137 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
138 }
139 }
140
141 void
142 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
143 {
144 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
145 }
146
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700147 void
148 asyncPutData(const shared_ptr<const Data>& data)
149 {
Junxiao Shia1ea5062014-12-27 22:33:39 -0700150 this->ensureConnected();
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700151
Jiewen Tanc759a202015-01-29 23:31:09 -0800152 if (!data->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_CACHING_POLICY))
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700153 {
Jiewen Tanc759a202015-01-29 23:31:09 -0800154 m_face.m_transport->send(
155 data->getLocalControlHeader().wireEncode(*data,
156 nfd::LocalControlHeader::ENCODE_CACHING_POLICY),
157 data->wireEncode());
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700158 }
159 else
160 {
161 m_face.m_transport->send(data->wireEncode());
162 }
163 }
164
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700165 /////////////////////////////////////////////////////////////////////////////////////////////////
166 /////////////////////////////////////////////////////////////////////////////////////////////////
167
168 void
169 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
170 {
171 m_interestFilterTable.push_back(interestFilterRecord);
172 }
173
174 void
175 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
176 {
177 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
178 m_interestFilterTable.end(),
179 MatchInterestFilterId(interestFilterId));
180 if (i != m_interestFilterTable.end())
181 {
182 m_interestFilterTable.erase(i);
183 }
184 }
185
186 /////////////////////////////////////////////////////////////////////////////////////////////////
187 /////////////////////////////////////////////////////////////////////////////////////////////////
188
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700189 const RegisteredPrefixId*
190 registerPrefix(const Name& prefix,
191 const shared_ptr<InterestFilterRecord>& filter,
192 const RegisterPrefixSuccessCallback& onSuccess,
193 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700194 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700195 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700196 {
197 using namespace nfd;
198
Junxiao Shi388ec252014-11-02 15:19:57 -0700199 typedef void (Controller::*Registrator)
200 (const ControlParameters&,
201 const Controller::CommandSucceedCallback&,
202 const Controller::CommandFailCallback&,
203 const CommandOptions&);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700204
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700205 ControlParameters registerParameters, unregisterParameters;
206 registerParameters.setName(prefix);
207 unregisterParameters.setName(prefix);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700208
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700209 Registrator registrator, unregistrator;
210 if (!m_face.m_isDirectNfdFibManagementRequested) {
211 registrator = static_cast<Registrator>(&Controller::start<RibRegisterCommand>);
212 unregistrator = static_cast<Registrator>(&Controller::start<RibUnregisterCommand>);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700213
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700214 registerParameters.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700215 }
216 else {
217 registrator = static_cast<Registrator>(&Controller::start<FibAddNextHopCommand>);
218 unregistrator = static_cast<Registrator>(&Controller::start<FibRemoveNextHopCommand>);
219 }
220
Joao Pereira68c0d882015-05-19 14:27:55 -0400221 RegisteredPrefix::Unregistrator boundUnregistrator =
222 bind(unregistrator, m_face.m_nfdController.get(), unregisterParameters, _1, _2,
Junxiao Shi388ec252014-11-02 15:19:57 -0700223 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700224
225 shared_ptr<RegisteredPrefix> prefixToRegister =
Joao Pereira68c0d882015-05-19 14:27:55 -0400226 make_shared<RegisteredPrefix>(prefix, filter, boundUnregistrator);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700228 ((*m_face.m_nfdController).*registrator)(registerParameters,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700229 bind(&Impl::afterPrefixRegistered, this,
230 prefixToRegister, onSuccess),
231 bind(onFailure, prefixToRegister->getPrefix(), _2),
Junxiao Shi388ec252014-11-02 15:19:57 -0700232 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700233
234 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
235 }
236
237 void
238 afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
239 const RegisterPrefixSuccessCallback& onSuccess)
240 {
241 m_registeredPrefixTable.push_back(registeredPrefix);
242
243 if (static_cast<bool>(registeredPrefix->getFilter())) {
244 // it was a combined operation
245 m_interestFilterTable.push_back(registeredPrefix->getFilter());
246 }
247
248 if (static_cast<bool>(onSuccess)) {
249 onSuccess(registeredPrefix->getPrefix());
250 }
251 }
252
253 void
254 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
255 const UnregisterPrefixSuccessCallback& onSuccess,
256 const UnregisterPrefixFailureCallback& onFailure)
257 {
258 RegisteredPrefixTable::iterator i = std::find_if(m_registeredPrefixTable.begin(),
259 m_registeredPrefixTable.end(),
260 MatchRegisteredPrefixId(registeredPrefixId));
261 if (i != m_registeredPrefixTable.end())
262 {
263 const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
264 if (static_cast<bool>(filter))
265 {
266 // it was a combined operation
267 m_interestFilterTable.remove(filter);
268 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700269 (*i)->unregister(bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
270 bind(onFailure, _2));
271 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400272 else {
273 if (static_cast<bool>(onFailure)) {
274 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
287 if (!m_pitTimeoutCheckTimerActive && m_registeredPrefixTable.empty())
288 {
289 m_face.m_transport->pause();
290 if (!m_ioServiceWork) {
291 m_processEventsTimeoutTimer->cancel();
292 }
293 }
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700294
295 if (static_cast<bool>(onSuccess)) {
296 onSuccess();
297 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700298 }
299
300 /////////////////////////////////////////////////////////////////////////////////////////////////
301 /////////////////////////////////////////////////////////////////////////////////////////////////
302
303 void
304 checkPitExpire()
305 {
306 // Check for PIT entry timeouts.
307 time::steady_clock::TimePoint now = time::steady_clock::now();
308
309 PendingInterestTable::iterator i = m_pendingInterestTable.begin();
310 while (i != m_pendingInterestTable.end())
311 {
312 if ((*i)->isTimedOut(now))
313 {
314 // Save the PendingInterest and remove it from the PIT. Then call the callback.
315 shared_ptr<PendingInterest> pendingInterest = *i;
316
317 i = m_pendingInterestTable.erase(i);
318
319 pendingInterest->callTimeout();
320 }
321 else
322 ++i;
323 }
324
325 if (!m_pendingInterestTable.empty()) {
326 m_pitTimeoutCheckTimerActive = true;
327
328 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
329 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
330 }
331 else {
332 m_pitTimeoutCheckTimerActive = false;
333
334 if (m_registeredPrefixTable.empty()) {
335 m_face.m_transport->pause();
336 if (!m_ioServiceWork) {
337 m_processEventsTimeoutTimer->cancel();
338 }
339 }
340 }
341 }
342
343private:
344 Face& m_face;
345
346 PendingInterestTable m_pendingInterestTable;
347 InterestFilterTable m_interestFilterTable;
348 RegisteredPrefixTable m_registeredPrefixTable;
349
350 ConfigFile m_config;
351
352 shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
353 shared_ptr<monotonic_deadline_timer> m_pitTimeoutCheckTimer;
354 bool m_pitTimeoutCheckTimerActive;
355 shared_ptr<monotonic_deadline_timer> m_processEventsTimeoutTimer;
356
357 friend class Face;
358};
359
360} // namespace ndn
361
362#endif // NDN_DETAIL_FACE_IMPL_HPP