blob: cd1b3d8cfccbb1e507798e033dcf76fbe81e7eec [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"
39
40namespace ndn {
41
42class Face::Impl : noncopyable
43{
44public:
45 typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
46 typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
47 typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
48
49 explicit
50 Impl(Face& face)
51 : m_face(face)
52 {
53 }
54
55 /////////////////////////////////////////////////////////////////////////////////////////////////
56 /////////////////////////////////////////////////////////////////////////////////////////////////
57
58 void
59 satisfyPendingInterests(Data& data)
60 {
61 for (PendingInterestTable::iterator i = m_pendingInterestTable.begin();
62 i != m_pendingInterestTable.end();
63 )
64 {
65 if ((*i)->getInterest()->matchesData(data))
66 {
67 // Copy pointers to the objects and remove the PIT entry before calling the callback.
68 OnData onData = (*i)->getOnData();
69 shared_ptr<const Interest> interest = (*i)->getInterest();
70
71 PendingInterestTable::iterator next = i;
72 ++next;
73 m_pendingInterestTable.erase(i);
74 i = next;
75
76 if (static_cast<bool>(onData)) {
77 onData(*interest, data);
78 }
79 }
80 else
81 ++i;
82 }
83 }
84
85 void
86 processInterestFilters(Interest& interest)
87 {
88 for (InterestFilterTable::iterator i = m_interestFilterTable.begin();
89 i != m_interestFilterTable.end();
90 ++i)
91 {
92 if ((*i)->doesMatch(interest.getName()))
93 {
94 (**i)(interest);
95 }
96 }
97 }
98
99 /////////////////////////////////////////////////////////////////////////////////////////////////
100 /////////////////////////////////////////////////////////////////////////////////////////////////
101
102 void
103 asyncExpressInterest(const shared_ptr<const Interest>& interest,
104 const OnData& onData, const OnTimeout& onTimeout)
105 {
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700106 if (!m_face.m_transport->isConnected())
107 m_face.m_transport->connect(*m_face.m_ioService,
108 bind(&Face::onReceiveElement, &m_face, _1));
109
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700110 if (!m_face.m_transport->isExpectingData())
111 m_face.m_transport->resume();
112
113 m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
114
115 if (!interest->getLocalControlHeader().empty(false, true))
116 {
117 // encode only NextHopFaceId towards the forwarder
118 m_face.m_transport->send(interest->getLocalControlHeader()
119 .wireEncode(*interest, false, true),
120 interest->wireEncode());
121 }
122 else
123 {
124 m_face.m_transport->send(interest->wireEncode());
125 }
126
127 if (!m_pitTimeoutCheckTimerActive) {
128 m_pitTimeoutCheckTimerActive = true;
129 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
130 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
131 }
132 }
133
134 void
135 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
136 {
137 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
138 }
139
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700140 void
141 asyncPutData(const shared_ptr<const Data>& data)
142 {
143 if (!m_face.m_transport->isConnected())
144 m_face.m_transport->connect(*m_face.m_ioService,
145 bind(&Face::onReceiveElement, &m_face, _1));
146
147 if (!m_face.m_transport->isExpectingData())
148 m_face.m_transport->resume();
149
150 if (!data->getLocalControlHeader().empty(false, true))
151 {
152 m_face.m_transport->send(data->getLocalControlHeader().wireEncode(*data, false, true),
153 data->wireEncode());
154 }
155 else
156 {
157 m_face.m_transport->send(data->wireEncode());
158 }
159 }
160
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700161 /////////////////////////////////////////////////////////////////////////////////////////////////
162 /////////////////////////////////////////////////////////////////////////////////////////////////
163
164 void
165 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
166 {
167 m_interestFilterTable.push_back(interestFilterRecord);
168 }
169
170 void
171 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
172 {
173 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
174 m_interestFilterTable.end(),
175 MatchInterestFilterId(interestFilterId));
176 if (i != m_interestFilterTable.end())
177 {
178 m_interestFilterTable.erase(i);
179 }
180 }
181
182 /////////////////////////////////////////////////////////////////////////////////////////////////
183 /////////////////////////////////////////////////////////////////////////////////////////////////
184
185 template<class SignatureGenerator>
186 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,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700192 const SignatureGenerator& signatureGenerator)
193 {
194 using namespace nfd;
195
196 typedef void (nfd::Controller::*Registrator)
197 (const nfd::ControlParameters&,
198 const nfd::Controller::CommandSucceedCallback&,
199 const nfd::Controller::CommandFailCallback&,
200 const SignatureGenerator&,
201 const time::milliseconds&);
202
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700203 ControlParameters registerParameters, unregisterParameters;
204 registerParameters.setName(prefix);
205 unregisterParameters.setName(prefix);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700206
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700207 Registrator registrator, unregistrator;
208 if (!m_face.m_isDirectNfdFibManagementRequested) {
209 registrator = static_cast<Registrator>(&Controller::start<RibRegisterCommand>);
210 unregistrator = static_cast<Registrator>(&Controller::start<RibUnregisterCommand>);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700211
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700212 registerParameters.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700213 }
214 else {
215 registrator = static_cast<Registrator>(&Controller::start<FibAddNextHopCommand>);
216 unregistrator = static_cast<Registrator>(&Controller::start<FibRemoveNextHopCommand>);
217 }
218
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700219 RegisteredPrefix::Unregistrator bindedUnregistrator =
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700220 bind(unregistrator, m_face.m_nfdController, unregisterParameters, _1, _2,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700221 signatureGenerator,
222 m_face.m_nfdController->getDefaultCommandTimeout());
223
224 shared_ptr<RegisteredPrefix> prefixToRegister =
225 ndn::make_shared<RegisteredPrefix>(prefix, filter, bindedUnregistrator);
226
Alexander Afanasyev4a9b6bb2014-08-28 21:35:22 -0700227 ((*m_face.m_nfdController).*registrator)(registerParameters,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700228 bind(&Impl::afterPrefixRegistered, this,
229 prefixToRegister, onSuccess),
230 bind(onFailure, prefixToRegister->getPrefix(), _2),
231 signatureGenerator,
232 m_face.m_nfdController->getDefaultCommandTimeout());
233
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 }
269
270 (*i)->unregister(bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
271 bind(onFailure, _2));
272 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400273 else {
274 if (static_cast<bool>(onFailure)) {
275 onFailure("Unrecognized PrefixId");
276 }
277 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700278
279 // there cannot be two registered prefixes with the same id
280 }
281
282 void
283 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
284 const UnregisterPrefixSuccessCallback& onSuccess)
285 {
286 m_registeredPrefixTable.erase(item);
287
288 if (!m_pitTimeoutCheckTimerActive && m_registeredPrefixTable.empty())
289 {
290 m_face.m_transport->pause();
291 if (!m_ioServiceWork) {
292 m_processEventsTimeoutTimer->cancel();
293 }
294 }
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700295
296 if (static_cast<bool>(onSuccess)) {
297 onSuccess();
298 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700299 }
300
301 /////////////////////////////////////////////////////////////////////////////////////////////////
302 /////////////////////////////////////////////////////////////////////////////////////////////////
303
304 void
305 checkPitExpire()
306 {
307 // Check for PIT entry timeouts.
308 time::steady_clock::TimePoint now = time::steady_clock::now();
309
310 PendingInterestTable::iterator i = m_pendingInterestTable.begin();
311 while (i != m_pendingInterestTable.end())
312 {
313 if ((*i)->isTimedOut(now))
314 {
315 // Save the PendingInterest and remove it from the PIT. Then call the callback.
316 shared_ptr<PendingInterest> pendingInterest = *i;
317
318 i = m_pendingInterestTable.erase(i);
319
320 pendingInterest->callTimeout();
321 }
322 else
323 ++i;
324 }
325
326 if (!m_pendingInterestTable.empty()) {
327 m_pitTimeoutCheckTimerActive = true;
328
329 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
330 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
331 }
332 else {
333 m_pitTimeoutCheckTimerActive = false;
334
335 if (m_registeredPrefixTable.empty()) {
336 m_face.m_transport->pause();
337 if (!m_ioServiceWork) {
338 m_processEventsTimeoutTimer->cancel();
339 }
340 }
341 }
342 }
343
344private:
345 Face& m_face;
346
347 PendingInterestTable m_pendingInterestTable;
348 InterestFilterTable m_interestFilterTable;
349 RegisteredPrefixTable m_registeredPrefixTable;
350
351 ConfigFile m_config;
352
353 shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
354 shared_ptr<monotonic_deadline_timer> m_pitTimeoutCheckTimer;
355 bool m_pitTimeoutCheckTimerActive;
356 shared_ptr<monotonic_deadline_timer> m_processEventsTimeoutTimer;
357
358 friend class Face;
359};
360
361} // namespace ndn
362
363#endif // NDN_DETAIL_FACE_IMPL_HPP