blob: 5e3558b2e85b8a50dd51d7b917aced7a0e14f55d [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
34#include "transport/transport.hpp"
35#include "transport/unix-transport.hpp"
36#include "transport/tcp-transport.hpp"
37
38#include "management/nfd-controller.hpp"
Junxiao Shi388ec252014-11-02 15:19:57 -070039#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
104 asyncExpressInterest(const shared_ptr<const Interest>& interest,
105 const OnData& onData, const OnTimeout& onTimeout)
106 {
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700107 if (!m_face.m_transport->isConnected())
108 m_face.m_transport->connect(*m_face.m_ioService,
109 bind(&Face::onReceiveElement, &m_face, _1));
110
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700111 if (!m_face.m_transport->isExpectingData())
112 m_face.m_transport->resume();
113
114 m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
115
116 if (!interest->getLocalControlHeader().empty(false, true))
117 {
118 // encode only NextHopFaceId towards the forwarder
119 m_face.m_transport->send(interest->getLocalControlHeader()
120 .wireEncode(*interest, false, true),
121 interest->wireEncode());
122 }
123 else
124 {
125 m_face.m_transport->send(interest->wireEncode());
126 }
127
128 if (!m_pitTimeoutCheckTimerActive) {
129 m_pitTimeoutCheckTimerActive = true;
130 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
131 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
132 }
133 }
134
135 void
136 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
137 {
138 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
139 }
140
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700141 void
142 asyncPutData(const shared_ptr<const Data>& data)
143 {
144 if (!m_face.m_transport->isConnected())
145 m_face.m_transport->connect(*m_face.m_ioService,
146 bind(&Face::onReceiveElement, &m_face, _1));
147
148 if (!m_face.m_transport->isExpectingData())
149 m_face.m_transport->resume();
150
151 if (!data->getLocalControlHeader().empty(false, true))
152 {
153 m_face.m_transport->send(data->getLocalControlHeader().wireEncode(*data, false, true),
154 data->wireEncode());
155 }
156 else
157 {
158 m_face.m_transport->send(data->wireEncode());
159 }
160 }
161
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700162 /////////////////////////////////////////////////////////////////////////////////////////////////
163 /////////////////////////////////////////////////////////////////////////////////////////////////
164
165 void
166 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
167 {
168 m_interestFilterTable.push_back(interestFilterRecord);
169 }
170
171 void
172 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
173 {
174 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
175 m_interestFilterTable.end(),
176 MatchInterestFilterId(interestFilterId));
177 if (i != m_interestFilterTable.end())
178 {
179 m_interestFilterTable.erase(i);
180 }
181 }
182
183 /////////////////////////////////////////////////////////////////////////////////////////////////
184 /////////////////////////////////////////////////////////////////////////////////////////////////
185
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700186 const RegisteredPrefixId*
187 registerPrefix(const Name& prefix,
188 const shared_ptr<InterestFilterRecord>& filter,
189 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 {
194 using namespace nfd;
195
Junxiao Shi388ec252014-11-02 15:19:57 -0700196 typedef void (Controller::*Registrator)
197 (const ControlParameters&,
198 const Controller::CommandSucceedCallback&,
199 const Controller::CommandFailCallback&,
200 const CommandOptions&);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700201
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700202 ControlParameters registerParameters, unregisterParameters;
203 registerParameters.setName(prefix);
204 unregisterParameters.setName(prefix);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700205
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700206 Registrator registrator, unregistrator;
207 if (!m_face.m_isDirectNfdFibManagementRequested) {
208 registrator = static_cast<Registrator>(&Controller::start<RibRegisterCommand>);
209 unregistrator = static_cast<Registrator>(&Controller::start<RibUnregisterCommand>);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700210
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700211 registerParameters.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700212 }
213 else {
214 registrator = static_cast<Registrator>(&Controller::start<FibAddNextHopCommand>);
215 unregistrator = static_cast<Registrator>(&Controller::start<FibRemoveNextHopCommand>);
216 }
217
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700218 RegisteredPrefix::Unregistrator bindedUnregistrator =
Junxiao Shi388ec252014-11-02 15:19:57 -0700219 std::bind(unregistrator, m_face.m_nfdController, unregisterParameters, _1, _2,
220 options);
221 // @todo get rid of "std::" after #2109
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700222
223 shared_ptr<RegisteredPrefix> prefixToRegister =
Davide Pesaventodfe9c6b2014-08-25 21:17:10 +0200224 make_shared<RegisteredPrefix>(prefix, filter, bindedUnregistrator);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700225
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700226 ((*m_face.m_nfdController).*registrator)(registerParameters,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227 bind(&Impl::afterPrefixRegistered, this,
228 prefixToRegister, onSuccess),
229 bind(onFailure, prefixToRegister->getPrefix(), _2),
Junxiao Shi388ec252014-11-02 15:19:57 -0700230 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700231
232 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
233 }
234
235 void
236 afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
237 const RegisterPrefixSuccessCallback& onSuccess)
238 {
239 m_registeredPrefixTable.push_back(registeredPrefix);
240
241 if (static_cast<bool>(registeredPrefix->getFilter())) {
242 // it was a combined operation
243 m_interestFilterTable.push_back(registeredPrefix->getFilter());
244 }
245
246 if (static_cast<bool>(onSuccess)) {
247 onSuccess(registeredPrefix->getPrefix());
248 }
249 }
250
251 void
252 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
253 const UnregisterPrefixSuccessCallback& onSuccess,
254 const UnregisterPrefixFailureCallback& onFailure)
255 {
256 RegisteredPrefixTable::iterator i = std::find_if(m_registeredPrefixTable.begin(),
257 m_registeredPrefixTable.end(),
258 MatchRegisteredPrefixId(registeredPrefixId));
259 if (i != m_registeredPrefixTable.end())
260 {
261 const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
262 if (static_cast<bool>(filter))
263 {
264 // it was a combined operation
265 m_interestFilterTable.remove(filter);
266 }
267
268 (*i)->unregister(bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
269 bind(onFailure, _2));
270 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400271 else {
272 if (static_cast<bool>(onFailure)) {
273 onFailure("Unrecognized PrefixId");
274 }
275 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700276
277 // there cannot be two registered prefixes with the same id
278 }
279
280 void
281 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
282 const UnregisterPrefixSuccessCallback& onSuccess)
283 {
284 m_registeredPrefixTable.erase(item);
285
286 if (!m_pitTimeoutCheckTimerActive && m_registeredPrefixTable.empty())
287 {
288 m_face.m_transport->pause();
289 if (!m_ioServiceWork) {
290 m_processEventsTimeoutTimer->cancel();
291 }
292 }
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700293
294 if (static_cast<bool>(onSuccess)) {
295 onSuccess();
296 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700297 }
298
299 /////////////////////////////////////////////////////////////////////////////////////////////////
300 /////////////////////////////////////////////////////////////////////////////////////////////////
301
302 void
303 checkPitExpire()
304 {
305 // Check for PIT entry timeouts.
306 time::steady_clock::TimePoint now = time::steady_clock::now();
307
308 PendingInterestTable::iterator i = m_pendingInterestTable.begin();
309 while (i != m_pendingInterestTable.end())
310 {
311 if ((*i)->isTimedOut(now))
312 {
313 // Save the PendingInterest and remove it from the PIT. Then call the callback.
314 shared_ptr<PendingInterest> pendingInterest = *i;
315
316 i = m_pendingInterestTable.erase(i);
317
318 pendingInterest->callTimeout();
319 }
320 else
321 ++i;
322 }
323
324 if (!m_pendingInterestTable.empty()) {
325 m_pitTimeoutCheckTimerActive = true;
326
327 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
328 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
329 }
330 else {
331 m_pitTimeoutCheckTimerActive = false;
332
333 if (m_registeredPrefixTable.empty()) {
334 m_face.m_transport->pause();
335 if (!m_ioServiceWork) {
336 m_processEventsTimeoutTimer->cancel();
337 }
338 }
339 }
340 }
341
342private:
343 Face& m_face;
344
345 PendingInterestTable m_pendingInterestTable;
346 InterestFilterTable m_interestFilterTable;
347 RegisteredPrefixTable m_registeredPrefixTable;
348
349 ConfigFile m_config;
350
351 shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
352 shared_ptr<monotonic_deadline_timer> m_pitTimeoutCheckTimer;
353 bool m_pitTimeoutCheckTimerActive;
354 shared_ptr<monotonic_deadline_timer> m_processEventsTimeoutTimer;
355
356 friend class Face;
357};
358
359} // namespace ndn
360
361#endif // NDN_DETAIL_FACE_IMPL_HPP