blob: 5e1efed8a97c61d4b0a5be97048e85cf04748ec4 [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"
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080016#include <cstdlib>
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080017
18#include "management/ndnd-controller.hpp"
19#include "management/nfd-controller.hpp"
Jeff Thompsonb982b6d2013-07-15 18:15:45 -070020
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -070021namespace ndn {
Alexander Afanasyevb790d952014-01-24 12:07:53 -080022
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080023Face::Face()
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070024{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080025 construct(shared_ptr<Transport>(new UnixTransport()),
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080026 make_shared<boost::asio::io_service>());
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080027}
28
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080029Face::Face(const shared_ptr<boost::asio::io_service> &ioService)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080030{
31 construct(shared_ptr<Transport>(new UnixTransport()),
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080032 ioService);
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080033}
34
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080035Face::Face(const std::string &host, const std::string &port/* = "6363"*/)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080036{
37 construct(shared_ptr<Transport>(new TcpTransport(host, port)),
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080038 make_shared<boost::asio::io_service>());
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080039}
40
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080041Face::Face(const shared_ptr<Transport>& transport)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080042{
43 construct(transport,
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080044 make_shared<boost::asio::io_service>());
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080045}
46
47Face::Face(const shared_ptr<Transport>& transport,
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080048 const shared_ptr<boost::asio::io_service> &ioService)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080049{
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080050 construct(transport, ioService);
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080051}
52
53void
54Face::construct(const shared_ptr<Transport>& transport,
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080055 const shared_ptr<boost::asio::io_service> &ioService)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080056{
57 pitTimeoutCheckTimerActive_ = false;
58 transport_ = transport;
59 ioService_ = ioService;
60
61 pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
62 processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -080063
Alexander Afanasyevf7ca3202014-02-14 22:28:31 -080064 if (std::getenv("NFD") != 0)
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080065 m_fwController = make_shared<nfd::Controller>(boost::ref(*this));
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070066 else
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080067 m_fwController = make_shared<ndnd::Controller>(boost::ref(*this));
68}
69
70
71const PendingInterestId*
72Face::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
73{
74 if (!transport_->isConnected())
75 transport_->connect(*ioService_,
76 bind(&Face::onReceiveElement, this, _1));
77
78 shared_ptr<const Interest> interestToExpress(new Interest(interest));
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -080079
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080080 ioService_->post(bind(&Face::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -080081
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080082 return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
83}
84
85const PendingInterestId*
86Face::expressInterest(const Name& name,
87 const Interest &tmpl,
88 const OnData& onData, const OnTimeout& onTimeout/* = OnTimeout()*/)
89{
90 return expressInterest(Interest(name,
91 tmpl.getMinSuffixComponents(),
92 tmpl.getMaxSuffixComponents(),
93 tmpl.getExclude(),
94 tmpl.getChildSelector(),
95 tmpl.getMustBeFresh(),
96 tmpl.getScope(),
97 tmpl.getInterestLifetime()),
98 onData, onTimeout);
99}
100
101void
102Face::asyncExpressInterest(const shared_ptr<const Interest> &interest,
103 const OnData& onData, const OnTimeout& onTimeout)
104{
105 pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
106 (interest, onData, onTimeout)));
107
108 transport_->send(interest->wireEncode());
109
110 if (!pitTimeoutCheckTimerActive_) {
111 pitTimeoutCheckTimerActive_ = true;
112 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
113 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
114 }
115}
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800116
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800117void
118Face::put(const Data &data)
119{
120 if (!transport_->isConnected())
121 transport_->connect(*ioService_,
122 bind(&Face::onReceiveElement, this, _1));
123
124 transport_->send(data.wireEncode());
125}
126
127
128void
129Face::removePendingInterest(const PendingInterestId *pendingInterestId)
130{
131 ioService_->post(bind(&Face::asyncRemovePendingInterest, this, pendingInterestId));
132}
133
134
135void
136Face::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
137{
138 pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
139}
140
141const RegisteredPrefixId*
142Face::setInterestFilter(const Name& prefix,
143 const OnInterest& onInterest,
144 const OnSetInterestFilterFailed& onSetInterestFilterFailed)
145{
146 shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
147
148 m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
149 bind(&RegisteredPrefixTable::push_back, &registeredPrefixTable_, prefixToRegister),
150 bind(onSetInterestFilterFailed, prefixToRegister->getPrefix(), _1));
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800151
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800152 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
153}
154
155void
156Face::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
157{
158 ioService_->post(bind(&Face::asyncUnsetInterestFilter, this, registeredPrefixId));
159}
160
161void
162Face::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
163{
164 RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800165 MatchRegisteredPrefixId(registeredPrefixId));
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800166 if (i != registeredPrefixTable_.end())
167 {
168 m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
Alexander Afanasyev12dfbad2014-02-11 14:42:46 -0800169 bind(&Face::finalizeUnsertInterestFilter, this, i),
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800170 Controller::FailCallback());
171 }
172
173 // there cannot be two registered prefixes with the same id. if there are, then something is broken
174}
175
Alexander Afanasyev12dfbad2014-02-11 14:42:46 -0800176void
177Face::finalizeUnsertInterestFilter(RegisteredPrefixTable::iterator item)
178{
179 registeredPrefixTable_.erase(item);
180
181 if (!pitTimeoutCheckTimerActive_ && registeredPrefixTable_.empty())
182 {
183 transport_->close();
184 if (!ioServiceWork_) {
185 processEventsTimeoutTimer_->cancel();
186 }
187 }
188}
189
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800190void
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800191Face::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
192{
193 try
194 {
195 if (timeout < 0)
196 {
197 // do not block if timeout is negative, but process pending events
198 ioService_->poll();
199 return;
200 }
201
202 if (timeout > 0)
203 {
204 processEventsTimeoutTimer_->expires_from_now(boost::posix_time::milliseconds(timeout));
205 processEventsTimeoutTimer_->async_wait(&fireProcessEventsTimeout);
206 }
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800207
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800208 if (keepThread) {
209 // work will ensure that ioService_ is running until work object exists
210 ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
211 }
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800212
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800213 ioService_->run();
214 ioService_->reset(); // so it is possible to run processEvents again (if necessary)
215 }
216 catch(Face::ProcessEventsTimeout &)
217 {
218 // break
219 ioService_->reset();
220 }
221 catch(const std::exception &)
222 {
223 ioService_->reset();
224 pendingInterestTable_.clear();
225 registeredPrefixTable_.clear();
226 throw;
227 }
Jeff Thompsonfb29cda2013-08-24 10:26:54 -0700228}
229
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800230void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700231Face::shutdown()
Jeff Thompson517ffa82013-08-05 16:04:34 -0700232{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800233 pendingInterestTable_.clear();
234 registeredPrefixTable_.clear();
235
236 transport_->close();
237 pitTimeoutCheckTimer_->cancel();
238 processEventsTimeoutTimer_->cancel();
239 pitTimeoutCheckTimerActive_ = false;
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700240}
241
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800242void
243Face::fireProcessEventsTimeout(const boost::system::error_code& error)
244{
245 if (!error) // can fire for some other reason, e.g., cancelled
246 throw Face::ProcessEventsTimeout();
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700247}
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800248
249void
250Face::checkPitExpire()
251{
252 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
253 MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
254
255 PendingInterestTable::iterator i = pendingInterestTable_.begin();
256 while (i != pendingInterestTable_.end())
257 {
258 if ((*i)->isTimedOut(nowMilliseconds))
259 {
260 // Save the PendingInterest and remove it from the PIT. Then call the callback.
261 shared_ptr<PendingInterest> pendingInterest = *i;
262
263 i = pendingInterestTable_.erase(i);
264
265 pendingInterest->callTimeout();
266 }
267 else
268 ++i;
269 }
270
271 if (!pendingInterestTable_.empty()) {
272 pitTimeoutCheckTimerActive_ = true;
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800273
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800274 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
275 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
276 }
277 else {
278 pitTimeoutCheckTimerActive_ = false;
279
280 if (registeredPrefixTable_.empty()) {
281 transport_->close();
282 if (!ioServiceWork_) {
283 processEventsTimeoutTimer_->cancel();
284 }
285 }
286 }
287}
288
289
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800290void
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800291Face::onReceiveElement(const Block &block)
292{
293 if (block.type() == Tlv::Interest)
294 {
295 shared_ptr<Interest> interest(new Interest());
296 interest->wireDecode(block);
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800297
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800298 RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
299 if (entry != registeredPrefixTable_.end()) {
300 (*entry)->getOnInterest()((*entry)->getPrefix(), *interest);
301 }
302 }
303 else if (block.type() == Tlv::Data)
304 {
305 shared_ptr<Data> data(new Data());
306 data->wireDecode(block);
307
308 PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
309 if (entry != pendingInterestTable_.end()) {
310 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
311 const OnData onData = (*entry)->getOnData();
312 const shared_ptr<const Interest> interest = (*entry)->getInterest();
313 pendingInterestTable_.erase(entry);
314
315 if (onData) {
316 onData(*interest, *data);
317 }
318
319 if (pendingInterestTable_.empty()) {
320 pitTimeoutCheckTimer_->cancel(); // this will cause checkPitExpire invocation
321 }
322 }
323 }
324}
325
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800326Face::PendingInterestTable::iterator
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800327Face::getEntryIndexForExpressedInterest(const Name& name)
328{
329 for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
330 i != pendingInterestTable_.end(); ++i)
331 {
332 if ((*i)->getInterest()->matchesName(name))
333 {
334 return i;
335 }
336 }
337
338 return pendingInterestTable_.end();
339}
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800340
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800341Face::RegisteredPrefixTable::iterator
342Face::getEntryForRegisteredPrefix(const Name& name)
343{
344 RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
345
346 for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
347 i != registeredPrefixTable_.end();
348 ++i)
349 {
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800350 if ((*i)->getPrefix().isPrefixOf(name))
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800351 {
Alexander Afanasyeva68aa7f2014-02-11 15:42:33 -0800352
353 if (longestPrefix == registeredPrefixTable_.end() ||
354 (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
355 {
356 longestPrefix = i;
357 }
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800358 }
359 }
360 return longestPrefix;
361}
362
363} // namespace ndn