blob: 52f9dd3bf43a68b9b4cee693e4296296ec1cfdb9 [file] [log] [blame]
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 */
12
13#ifndef NDN_DETAIL_FACE_IMPL_HPP
14#define NDN_DETAIL_FACE_IMPL_HPP
15
16#include "../common.hpp"
17#include "../face.hpp"
18
19#include "registered-prefix.hpp"
20#include "pending-interest.hpp"
21
22#include "../util/scheduler.hpp"
23#include "../util/config-file.hpp"
24
25#include "transport/transport.hpp"
26#include "transport/unix-transport.hpp"
27#include "transport/tcp-transport.hpp"
28
29#include "management/nfd-controller.hpp"
30
31namespace ndn {
32
33class Face::Impl : noncopyable
34{
35public:
36 typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
37 typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
38 typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
39
40 explicit
41 Impl(Face& face)
42 : m_face(face)
43 {
44 }
45
46 /////////////////////////////////////////////////////////////////////////////////////////////////
47 /////////////////////////////////////////////////////////////////////////////////////////////////
48
49 void
50 satisfyPendingInterests(Data& data)
51 {
52 for (PendingInterestTable::iterator i = m_pendingInterestTable.begin();
53 i != m_pendingInterestTable.end();
54 )
55 {
56 if ((*i)->getInterest()->matchesData(data))
57 {
58 // Copy pointers to the objects and remove the PIT entry before calling the callback.
59 OnData onData = (*i)->getOnData();
60 shared_ptr<const Interest> interest = (*i)->getInterest();
61
62 PendingInterestTable::iterator next = i;
63 ++next;
64 m_pendingInterestTable.erase(i);
65 i = next;
66
67 if (static_cast<bool>(onData)) {
68 onData(*interest, data);
69 }
70 }
71 else
72 ++i;
73 }
74 }
75
76 void
77 processInterestFilters(Interest& interest)
78 {
79 for (InterestFilterTable::iterator i = m_interestFilterTable.begin();
80 i != m_interestFilterTable.end();
81 ++i)
82 {
83 if ((*i)->doesMatch(interest.getName()))
84 {
85 (**i)(interest);
86 }
87 }
88 }
89
90 /////////////////////////////////////////////////////////////////////////////////////////////////
91 /////////////////////////////////////////////////////////////////////////////////////////////////
92
93 void
94 asyncExpressInterest(const shared_ptr<const Interest>& interest,
95 const OnData& onData, const OnTimeout& onTimeout)
96 {
97 if (!m_face.m_transport->isExpectingData())
98 m_face.m_transport->resume();
99
100 m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
101
102 if (!interest->getLocalControlHeader().empty(false, true))
103 {
104 // encode only NextHopFaceId towards the forwarder
105 m_face.m_transport->send(interest->getLocalControlHeader()
106 .wireEncode(*interest, false, true),
107 interest->wireEncode());
108 }
109 else
110 {
111 m_face.m_transport->send(interest->wireEncode());
112 }
113
114 if (!m_pitTimeoutCheckTimerActive) {
115 m_pitTimeoutCheckTimerActive = true;
116 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
117 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
118 }
119 }
120
121 void
122 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
123 {
124 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
125 }
126
127 /////////////////////////////////////////////////////////////////////////////////////////////////
128 /////////////////////////////////////////////////////////////////////////////////////////////////
129
130 void
131 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
132 {
133 m_interestFilterTable.push_back(interestFilterRecord);
134 }
135
136 void
137 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
138 {
139 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
140 m_interestFilterTable.end(),
141 MatchInterestFilterId(interestFilterId));
142 if (i != m_interestFilterTable.end())
143 {
144 m_interestFilterTable.erase(i);
145 }
146 }
147
148 /////////////////////////////////////////////////////////////////////////////////////////////////
149 /////////////////////////////////////////////////////////////////////////////////////////////////
150
151 template<class SignatureGenerator>
152 const RegisteredPrefixId*
153 registerPrefix(const Name& prefix,
154 const shared_ptr<InterestFilterRecord>& filter,
155 const RegisterPrefixSuccessCallback& onSuccess,
156 const RegisterPrefixFailureCallback& onFailure,
157 const SignatureGenerator& signatureGenerator)
158 {
159 using namespace nfd;
160
161 typedef void (nfd::Controller::*Registrator)
162 (const nfd::ControlParameters&,
163 const nfd::Controller::CommandSucceedCallback&,
164 const nfd::Controller::CommandFailCallback&,
165 const SignatureGenerator&,
166 const time::milliseconds&);
167
168 Registrator registrator, unregistrator;
169 if (!m_face.m_isDirectNfdFibManagementRequested) {
170 registrator = static_cast<Registrator>(&Controller::start<RibRegisterCommand>);
171 unregistrator = static_cast<Registrator>(&Controller::start<RibUnregisterCommand>);
172 }
173 else {
174 registrator = static_cast<Registrator>(&Controller::start<FibAddNextHopCommand>);
175 unregistrator = static_cast<Registrator>(&Controller::start<FibRemoveNextHopCommand>);
176 }
177
178 ControlParameters parameters;
179 parameters.setName(prefix);
180
181 RegisteredPrefix::Unregistrator bindedUnregistrator =
182 bind(unregistrator, m_face.m_nfdController, parameters, _1, _2,
183 signatureGenerator,
184 m_face.m_nfdController->getDefaultCommandTimeout());
185
186 shared_ptr<RegisteredPrefix> prefixToRegister =
187 ndn::make_shared<RegisteredPrefix>(prefix, filter, bindedUnregistrator);
188
189 ((*m_face.m_nfdController).*registrator)(parameters,
190 bind(&Impl::afterPrefixRegistered, this,
191 prefixToRegister, onSuccess),
192 bind(onFailure, prefixToRegister->getPrefix(), _2),
193 signatureGenerator,
194 m_face.m_nfdController->getDefaultCommandTimeout());
195
196 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
197 }
198
199 void
200 afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
201 const RegisterPrefixSuccessCallback& onSuccess)
202 {
203 m_registeredPrefixTable.push_back(registeredPrefix);
204
205 if (static_cast<bool>(registeredPrefix->getFilter())) {
206 // it was a combined operation
207 m_interestFilterTable.push_back(registeredPrefix->getFilter());
208 }
209
210 if (static_cast<bool>(onSuccess)) {
211 onSuccess(registeredPrefix->getPrefix());
212 }
213 }
214
215 void
216 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
217 const UnregisterPrefixSuccessCallback& onSuccess,
218 const UnregisterPrefixFailureCallback& onFailure)
219 {
220 RegisteredPrefixTable::iterator i = std::find_if(m_registeredPrefixTable.begin(),
221 m_registeredPrefixTable.end(),
222 MatchRegisteredPrefixId(registeredPrefixId));
223 if (i != m_registeredPrefixTable.end())
224 {
225 const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
226 if (static_cast<bool>(filter))
227 {
228 // it was a combined operation
229 m_interestFilterTable.remove(filter);
230 }
231
232 (*i)->unregister(bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
233 bind(onFailure, _2));
234 }
235 else
236 onFailure("Unrecognized PrefixId");
237
238 // there cannot be two registered prefixes with the same id
239 }
240
241 void
242 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
243 const UnregisterPrefixSuccessCallback& onSuccess)
244 {
245 m_registeredPrefixTable.erase(item);
246
247 if (!m_pitTimeoutCheckTimerActive && m_registeredPrefixTable.empty())
248 {
249 m_face.m_transport->pause();
250 if (!m_ioServiceWork) {
251 m_processEventsTimeoutTimer->cancel();
252 }
253 }
254 onSuccess();
255 }
256
257 /////////////////////////////////////////////////////////////////////////////////////////////////
258 /////////////////////////////////////////////////////////////////////////////////////////////////
259
260 void
261 checkPitExpire()
262 {
263 // Check for PIT entry timeouts.
264 time::steady_clock::TimePoint now = time::steady_clock::now();
265
266 PendingInterestTable::iterator i = m_pendingInterestTable.begin();
267 while (i != m_pendingInterestTable.end())
268 {
269 if ((*i)->isTimedOut(now))
270 {
271 // Save the PendingInterest and remove it from the PIT. Then call the callback.
272 shared_ptr<PendingInterest> pendingInterest = *i;
273
274 i = m_pendingInterestTable.erase(i);
275
276 pendingInterest->callTimeout();
277 }
278 else
279 ++i;
280 }
281
282 if (!m_pendingInterestTable.empty()) {
283 m_pitTimeoutCheckTimerActive = true;
284
285 m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
286 m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
287 }
288 else {
289 m_pitTimeoutCheckTimerActive = false;
290
291 if (m_registeredPrefixTable.empty()) {
292 m_face.m_transport->pause();
293 if (!m_ioServiceWork) {
294 m_processEventsTimeoutTimer->cancel();
295 }
296 }
297 }
298 }
299
300private:
301 Face& m_face;
302
303 PendingInterestTable m_pendingInterestTable;
304 InterestFilterTable m_interestFilterTable;
305 RegisteredPrefixTable m_registeredPrefixTable;
306
307 ConfigFile m_config;
308
309 shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
310 shared_ptr<monotonic_deadline_timer> m_pitTimeoutCheckTimer;
311 bool m_pitTimeoutCheckTimerActive;
312 shared_ptr<monotonic_deadline_timer> m_processEventsTimeoutTimer;
313
314 friend class Face;
315};
316
317} // namespace ndn
318
319#endif // NDN_DETAIL_FACE_IMPL_HPP