blob: fc064f1aba6ebec02c25dd2ee0c378f79c5d7f8f [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -07005 * See COPYING for copyright and distribution information.
6 */
7
Alexander Afanasyev0222fba2014-02-09 23:16:02 -08008#include "common.hpp"
9
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080010#include "face.hpp"
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -070011
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080012#include "security/signature-sha256-with-rsa.hpp"
13
14#include "util/time.hpp"
15#include "util/random.hpp"
16
17#include "management/ndnd-controller.hpp"
18#include "management/nfd-controller.hpp"
Jeff Thompsonb982b6d2013-07-15 18:15:45 -070019
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -070020namespace ndn {
Alexander Afanasyevb790d952014-01-24 12:07:53 -080021
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080022Face::Face(bool nfdMode/* = false*/)
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070023{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080024 construct(shared_ptr<Transport>(new UnixTransport()),
25 make_shared<boost::asio::io_service>(), nfdMode);
26}
27
28Face::Face(const shared_ptr<boost::asio::io_service> &ioService, bool nfdMode/* = false*/)
29{
30 construct(shared_ptr<Transport>(new UnixTransport()),
31 ioService, nfdMode);
32}
33
34Face::Face(const std::string &host, const std::string &port/* = "6363"*/, bool nfdMode/* = false*/)
35{
36 construct(shared_ptr<Transport>(new TcpTransport(host, port)),
37 make_shared<boost::asio::io_service>(), nfdMode);
38}
39
40Face::Face(const shared_ptr<Transport>& transport, bool nfdMode/* = false*/)
41{
42 construct(transport,
43 make_shared<boost::asio::io_service>(), nfdMode);
44}
45
46Face::Face(const shared_ptr<Transport>& transport,
47 const shared_ptr<boost::asio::io_service> &ioService,
48 bool nfdMode/* = false*/)
49{
50 construct(transport, ioService, nfdMode);
51}
52
53void
54Face::construct(const shared_ptr<Transport>& transport,
55 const shared_ptr<boost::asio::io_service> &ioService,
56 bool nfdMode)
57{
58 pitTimeoutCheckTimerActive_ = false;
59 transport_ = transport;
60 ioService_ = ioService;
61
62 pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
63 processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
64
65 if (nfdMode)
66 m_fwController = make_shared<nfd::Controller>(boost::ref(*this));
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070067 else
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080068 m_fwController = make_shared<ndnd::Controller>(boost::ref(*this));
69}
70
71
72const PendingInterestId*
73Face::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
74{
75 if (!transport_->isConnected())
76 transport_->connect(*ioService_,
77 bind(&Face::onReceiveElement, this, _1));
78
79 shared_ptr<const Interest> interestToExpress(new Interest(interest));
80
81 ioService_->post(bind(&Face::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
82
83 return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
84}
85
86const PendingInterestId*
87Face::expressInterest(const Name& name,
88 const Interest &tmpl,
89 const OnData& onData, const OnTimeout& onTimeout/* = OnTimeout()*/)
90{
91 return expressInterest(Interest(name,
92 tmpl.getMinSuffixComponents(),
93 tmpl.getMaxSuffixComponents(),
94 tmpl.getExclude(),
95 tmpl.getChildSelector(),
96 tmpl.getMustBeFresh(),
97 tmpl.getScope(),
98 tmpl.getInterestLifetime()),
99 onData, onTimeout);
100}
101
102void
103Face::asyncExpressInterest(const shared_ptr<const Interest> &interest,
104 const OnData& onData, const OnTimeout& onTimeout)
105{
106 pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
107 (interest, onData, onTimeout)));
108
109 transport_->send(interest->wireEncode());
110
111 if (!pitTimeoutCheckTimerActive_) {
112 pitTimeoutCheckTimerActive_ = true;
113 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
114 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
115 }
116}
117
118void
119Face::put(const Data &data)
120{
121 if (!transport_->isConnected())
122 transport_->connect(*ioService_,
123 bind(&Face::onReceiveElement, this, _1));
124
125 transport_->send(data.wireEncode());
126}
127
128
129void
130Face::removePendingInterest(const PendingInterestId *pendingInterestId)
131{
132 ioService_->post(bind(&Face::asyncRemovePendingInterest, this, pendingInterestId));
133}
134
135
136void
137Face::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
138{
139 pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
140}
141
142const RegisteredPrefixId*
143Face::setInterestFilter(const Name& prefix,
144 const OnInterest& onInterest,
145 const OnSetInterestFilterFailed& onSetInterestFilterFailed)
146{
147 shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
148
149 m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
150 bind(&RegisteredPrefixTable::push_back, &registeredPrefixTable_, prefixToRegister),
151 bind(onSetInterestFilterFailed, prefixToRegister->getPrefix(), _1));
152
153 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
154}
155
156void
157Face::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
158{
159 ioService_->post(bind(&Face::asyncUnsetInterestFilter, this, registeredPrefixId));
160}
161
162void
163Face::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
164{
165 RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
166 MatchRegisteredPrefixId(registeredPrefixId));
167 if (i != registeredPrefixTable_.end())
168 {
169 m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
Alexander Afanasyev12dfbad2014-02-11 14:42:46 -0800170 bind(&Face::finalizeUnsertInterestFilter, this, i),
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800171 Controller::FailCallback());
172 }
173
174 // there cannot be two registered prefixes with the same id. if there are, then something is broken
175}
176
Alexander Afanasyev12dfbad2014-02-11 14:42:46 -0800177void
178Face::finalizeUnsertInterestFilter(RegisteredPrefixTable::iterator item)
179{
180 registeredPrefixTable_.erase(item);
181
182 if (!pitTimeoutCheckTimerActive_ && registeredPrefixTable_.empty())
183 {
184 transport_->close();
185 if (!ioServiceWork_) {
186 processEventsTimeoutTimer_->cancel();
187 }
188 }
189}
190
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800191void
192Face::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
193{
194 try
195 {
196 if (timeout < 0)
197 {
198 // do not block if timeout is negative, but process pending events
199 ioService_->poll();
200 return;
201 }
202
203 if (timeout > 0)
204 {
205 processEventsTimeoutTimer_->expires_from_now(boost::posix_time::milliseconds(timeout));
206 processEventsTimeoutTimer_->async_wait(&fireProcessEventsTimeout);
207 }
208
209 if (keepThread) {
210 // work will ensure that ioService_ is running until work object exists
211 ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
212 }
213
214 ioService_->run();
215 ioService_->reset(); // so it is possible to run processEvents again (if necessary)
216 }
217 catch(Face::ProcessEventsTimeout &)
218 {
219 // break
220 ioService_->reset();
221 }
222 catch(const std::exception &)
223 {
224 ioService_->reset();
225 pendingInterestTable_.clear();
226 registeredPrefixTable_.clear();
227 throw;
228 }
Jeff Thompsonfb29cda2013-08-24 10:26:54 -0700229}
230
Jeff Thompson0050abe2013-09-17 12:50:25 -0700231void
232Face::shutdown()
Jeff Thompson517ffa82013-08-05 16:04:34 -0700233{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800234 pendingInterestTable_.clear();
235 registeredPrefixTable_.clear();
236
237 transport_->close();
238 pitTimeoutCheckTimer_->cancel();
239 processEventsTimeoutTimer_->cancel();
240 pitTimeoutCheckTimerActive_ = false;
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700241}
242
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800243void
244Face::fireProcessEventsTimeout(const boost::system::error_code& error)
245{
246 if (!error) // can fire for some other reason, e.g., cancelled
247 throw Face::ProcessEventsTimeout();
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700248}
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800249
250void
251Face::checkPitExpire()
252{
253 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
254 MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
255
256 PendingInterestTable::iterator i = pendingInterestTable_.begin();
257 while (i != pendingInterestTable_.end())
258 {
259 if ((*i)->isTimedOut(nowMilliseconds))
260 {
261 // Save the PendingInterest and remove it from the PIT. Then call the callback.
262 shared_ptr<PendingInterest> pendingInterest = *i;
263
264 i = pendingInterestTable_.erase(i);
265
266 pendingInterest->callTimeout();
267 }
268 else
269 ++i;
270 }
271
272 if (!pendingInterestTable_.empty()) {
273 pitTimeoutCheckTimerActive_ = true;
274
275 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
276 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
277 }
278 else {
279 pitTimeoutCheckTimerActive_ = false;
280
281 if (registeredPrefixTable_.empty()) {
282 transport_->close();
283 if (!ioServiceWork_) {
284 processEventsTimeoutTimer_->cancel();
285 }
286 }
287 }
288}
289
290
291void
292Face::onReceiveElement(const Block &block)
293{
294 if (block.type() == Tlv::Interest)
295 {
296 shared_ptr<Interest> interest(new Interest());
297 interest->wireDecode(block);
298
299 RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
300 if (entry != registeredPrefixTable_.end()) {
301 (*entry)->getOnInterest()((*entry)->getPrefix(), *interest);
302 }
303 }
304 else if (block.type() == Tlv::Data)
305 {
306 shared_ptr<Data> data(new Data());
307 data->wireDecode(block);
308
309 PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
310 if (entry != pendingInterestTable_.end()) {
311 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
312 const OnData onData = (*entry)->getOnData();
313 const shared_ptr<const Interest> interest = (*entry)->getInterest();
314 pendingInterestTable_.erase(entry);
315
316 if (onData) {
317 onData(*interest, *data);
318 }
319
320 if (pendingInterestTable_.empty()) {
321 pitTimeoutCheckTimer_->cancel(); // this will cause checkPitExpire invocation
322 }
323 }
324 }
325}
326
327Face::PendingInterestTable::iterator
328Face::getEntryIndexForExpressedInterest(const Name& name)
329{
330 for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
331 i != pendingInterestTable_.end(); ++i)
332 {
333 if ((*i)->getInterest()->matchesName(name))
334 {
335 return i;
336 }
337 }
338
339 return pendingInterestTable_.end();
340}
341
342Face::RegisteredPrefixTable::iterator
343Face::getEntryForRegisteredPrefix(const Name& name)
344{
345 RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
346
347 for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
348 i != registeredPrefixTable_.end();
349 ++i)
350 {
351 if (longestPrefix == registeredPrefixTable_.end() ||
352 (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
353 {
354 longestPrefix = i;
355 }
356 }
357 return longestPrefix;
358}
359
360} // namespace ndn