blob: 513c40f69b9bcf2625ac3fbbcf81a54808de1e96 [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -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 Thompsonbf50a1a2013-08-20 18:01:01 -07005 * See COPYING for copyright and distribution information.
6 */
7
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -08008#include "common.hpp"
9
Alexander Afanasyeve9fdb802014-02-05 17:36:51 -080010#include "node.hpp"
Alexander Afanasyev96d914f2014-01-02 22:24:29 -080011
Alexander Afanasyeve9fdb802014-02-05 17:36:51 -080012#include "security/signature-sha256-with-rsa.hpp"
13
14#include "util/time.hpp"
15#include "util/random.hpp"
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070016
17namespace ndn {
18
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080019Node::Node(const shared_ptr<Transport>& transport)
Alexander Afanasyevbf082112014-01-09 14:27:55 -080020 : pitTimeoutCheckTimerActive_(false)
21 , transport_(transport)
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080022 , m_fwController(*this)
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -080023{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080024 ioService_ = make_shared<boost::asio::io_service>();
25 pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
26 processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -080027}
28
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080029Node::Node(const shared_ptr<Transport>& transport, const shared_ptr<boost::asio::io_service> &ioService)
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -080030 : ioService_(ioService)
Alexander Afanasyevbf082112014-01-09 14:27:55 -080031 , pitTimeoutCheckTimerActive_(false)
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080032 , transport_(transport)
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080033 , m_fwController(*this)
Jeff Thompson557b81e2013-08-21 15:13:51 -070034{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080035 pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
36 processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
Jeff Thompson557b81e2013-08-21 15:13:51 -070037}
38
Alexander Afanasyevb790d952014-01-24 12:07:53 -080039const PendingInterestId*
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080040Node::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070041{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080042 if (!transport_->isConnected())
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -080043 transport_->connect(*ioService_,
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080044 bind(&Node::onReceiveElement, this, _1));
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080045
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080046 shared_ptr<const Interest> interestToExpress(new Interest(interest));
Alexander Afanasyevb790d952014-01-24 12:07:53 -080047
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080048 ioService_->post(bind(&Node::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
Alexander Afanasyevb790d952014-01-24 12:07:53 -080049
50 return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
51}
52
53void
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080054Node::asyncExpressInterest(const shared_ptr<const Interest> &interest,
55 const OnData& onData, const OnTimeout& onTimeout)
Alexander Afanasyevb790d952014-01-24 12:07:53 -080056{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080057 pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
58 (interest, onData, onTimeout)));
Alexander Afanasyevb790d952014-01-24 12:07:53 -080059
60 transport_->send(interest->wireEncode());
Alexander Afanasyevbf082112014-01-09 14:27:55 -080061
62 if (!pitTimeoutCheckTimerActive_) {
63 pitTimeoutCheckTimerActive_ = true;
64 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080065 pitTimeoutCheckTimer_->async_wait(bind(&Node::checkPitExpire, this));
Alexander Afanasyevbf082112014-01-09 14:27:55 -080066 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070067}
Alexander Afanasyevb790d952014-01-24 12:07:53 -080068
Jeff Thompson11095142013-10-01 16:20:28 -070069void
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080070Node::put(const Data &data)
71{
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080072 if (!transport_->isConnected())
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -080073 transport_->connect(*ioService_,
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080074 bind(&Node::onReceiveElement, this, _1));
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080075
76 transport_->send(data.wireEncode());
77}
78
79
80void
Alexander Afanasyevb790d952014-01-24 12:07:53 -080081Node::removePendingInterest(const PendingInterestId *pendingInterestId)
Jeff Thompson11095142013-10-01 16:20:28 -070082{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080083 ioService_->post(bind(&Node::asyncRemovePendingInterest, this, pendingInterestId));
Jeff Thompson11095142013-10-01 16:20:28 -070084}
85
Alexander Afanasyevb790d952014-01-24 12:07:53 -080086
87void
88Node::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
89{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080090 pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
Alexander Afanasyevb790d952014-01-24 12:07:53 -080091}
92
93const RegisteredPrefixId*
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080094Node::setInterestFilter(const Name& prefix,
95 const OnInterest& onInterest,
96 const OnSetInterestFilterFailed& onSetInterestFilterFailed)
Jeff Thompson86507bc2013-08-23 20:51:38 -070097{
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -080098 shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080099
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800100 m_fwController.selfRegisterPrefix(prefixToRegister->getPrefix(),
101 bind(&RegisteredPrefixTable::push_back, &registeredPrefixTable_, prefixToRegister),
102 bind(onSetInterestFilterFailed, prefixToRegister->getPrefix().shared_from_this()));
Jeff Thompson11095142013-10-01 16:20:28 -0700103
Alexander Afanasyevb790d952014-01-24 12:07:53 -0800104 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
Jeff Thompson11095142013-10-01 16:20:28 -0700105}
106
107void
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800108Node::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
109{
110 ioService_->post(bind(&Node::asyncUnsetInterestFilter, this, registeredPrefixId));
111}
112
113void
114Node::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
Jeff Thompson11095142013-10-01 16:20:28 -0700115{
Alexander Afanasyevb790d952014-01-24 12:07:53 -0800116 RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
117 MatchRegisteredPrefixId(registeredPrefixId));
118 if (i != registeredPrefixTable_.end())
Alexander Afanasyevbc343ef2014-01-09 22:36:20 -0800119 {
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800120 m_fwController.selfDeregisterPrefix((*i)->getPrefix(),
121 bind(&RegisteredPrefixTable::erase, &registeredPrefixTable_, i),
122 ndnd::Control::FailCallback());
Alexander Afanasyevbc343ef2014-01-09 22:36:20 -0800123 }
Alexander Afanasyevb790d952014-01-24 12:07:53 -0800124
125 // there cannot be two registered prefixes with the same id. if there are, then something is broken
Jeff Thompson86507bc2013-08-23 20:51:38 -0700126}
127
Jeff Thompson0050abe2013-09-17 12:50:25 -0700128void
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800129Node::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700130{
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800131 try
132 {
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800133 if (timeout < 0)
134 {
135 // do not block if timeout is negative, but process pending events
136 ioService_->poll();
137 return;
138 }
139
140 if (timeout > 0)
141 {
142 processEventsTimeoutTimer_->expires_from_now(boost::posix_time::milliseconds(timeout));
Jeff Thompson6e9fc182014-01-23 13:04:08 -0800143 processEventsTimeoutTimer_->async_wait(&fireProcessEventsTimeout);
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800144 }
145
146 if (keepThread) {
147 // work will ensure that ioService_ is running until work object exists
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800148 ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800149 }
150
Alexander Afanasyeve1b7a5d2013-12-29 16:23:52 -0800151 ioService_->run();
Alexander Afanasyev8995f542014-01-17 15:33:44 -0800152 ioService_->reset(); // so it is possible to run processEvents again (if necessary)
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800153 }
Alexander Afanasyev3ae2da22013-12-29 15:50:04 -0800154 catch(Node::ProcessEventsTimeout &)
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800155 {
Alexander Afanasyev3ae2da22013-12-29 15:50:04 -0800156 // break
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800157 ioService_->reset();
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800158 }
Alexander Afanasyev8995f542014-01-17 15:33:44 -0800159 catch(const std::exception &)
160 {
161 ioService_->reset();
162 pendingInterestTable_.clear();
163 registeredPrefixTable_.clear();
164 throw;
165 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800166}
167
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800168void
169Node::shutdown()
170{
171 pendingInterestTable_.clear();
172 registeredPrefixTable_.clear();
173
174 transport_->close();
175 pitTimeoutCheckTimer_->cancel();
176 processEventsTimeoutTimer_->cancel();
177 pitTimeoutCheckTimerActive_ = false;
178}
179
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800180void
Alexander Afanasyev3ae2da22013-12-29 15:50:04 -0800181Node::fireProcessEventsTimeout(const boost::system::error_code& error)
182{
183 if (!error) // can fire for some other reason, e.g., cancelled
184 throw Node::ProcessEventsTimeout();
185}
186
187void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800188Node::checkPitExpire()
189{
Jeff Thompson48917f02013-08-21 17:12:45 -0700190 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800191 MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
192
193 PendingInterestTable::iterator i = pendingInterestTable_.begin();
194 while (i != pendingInterestTable_.end())
195 {
196 if ((*i)->isTimedOut(nowMilliseconds))
197 {
198 // Save the PendingInterest and remove it from the PIT. Then call the callback.
199 shared_ptr<PendingInterest> pendingInterest = *i;
200
201 i = pendingInterestTable_.erase(i);
202
203 pendingInterest->callTimeout();
204 }
205 else
206 ++i;
Jeff Thompson48917f02013-08-21 17:12:45 -0700207 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800208
Alexander Afanasyevbf082112014-01-09 14:27:55 -0800209 if (!pendingInterestTable_.empty()) {
Alexander Afanasyevbc343ef2014-01-09 22:36:20 -0800210 pitTimeoutCheckTimerActive_ = true;
211
Alexander Afanasyevbf082112014-01-09 14:27:55 -0800212 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800213 pitTimeoutCheckTimer_->async_wait(bind(&Node::checkPitExpire, this));
Alexander Afanasyevbf082112014-01-09 14:27:55 -0800214 }
215 else {
216 pitTimeoutCheckTimerActive_ = false;
217
218 if (registeredPrefixTable_.empty()) {
219 transport_->close();
Alexander Afanasyevf75a0aa2014-01-09 14:29:22 -0800220 if (!ioServiceWork_) {
221 processEventsTimeoutTimer_->cancel();
222 }
Alexander Afanasyevbf082112014-01-09 14:27:55 -0800223 }
224 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700225}
226
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800227
Jeff Thompson0050abe2013-09-17 12:50:25 -0700228void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800229Node::onReceiveElement(const Block &block)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700230{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800231 if (block.type() == Tlv::Interest)
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800232 {
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800233 shared_ptr<Interest> interest(new Interest());
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800234 interest->wireDecode(block);
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700235
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800236 RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
237 if (entry != registeredPrefixTable_.end()) {
Alexander Afanasyevb790d952014-01-24 12:07:53 -0800238 (*entry)->getOnInterest()((*entry)->getPrefix().shared_from_this(), interest);
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800239 }
Jeff Thompson557b81e2013-08-21 15:13:51 -0700240 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800241 else if (block.type() == Tlv::Data)
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800242 {
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800243 shared_ptr<Data> data(new Data());
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800244 data->wireDecode(block);
245
246 PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
247 if (entry != pendingInterestTable_.end()) {
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800248 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800249 const OnData onData = (*entry)->getOnData();
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800250 const shared_ptr<const Interest> interest = (*entry)->getInterest();
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800251 pendingInterestTable_.erase(entry);
Alexander Afanasyevbc343ef2014-01-09 22:36:20 -0800252
253 if (onData) {
254 onData(interest, data);
255 }
256
257 if (pendingInterestTable_.empty()) {
258 pitTimeoutCheckTimer_->cancel(); // this will cause checkPitExpire invocation
259 }
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800260 }
261 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700262}
263
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800264Node::PendingInterestTable::iterator
Jeff Thompson0050abe2013-09-17 12:50:25 -0700265Node::getEntryIndexForExpressedInterest(const Name& name)
Jeff Thompson557b81e2013-08-21 15:13:51 -0700266{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800267 for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
268 i != pendingInterestTable_.end(); ++i)
269 {
270 if ((*i)->getInterest()->matchesName(name))
271 {
272 return i;
273 }
Jeff Thompson557b81e2013-08-21 15:13:51 -0700274 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800275
276 return pendingInterestTable_.end();
Jeff Thompson557b81e2013-08-21 15:13:51 -0700277}
Jeff Thompson86507bc2013-08-23 20:51:38 -0700278
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800279Node::RegisteredPrefixTable::iterator
Jeff Thompson0050abe2013-09-17 12:50:25 -0700280Node::getEntryForRegisteredPrefix(const Name& name)
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700281{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800282 RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
283
284 for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
285 i != registeredPrefixTable_.end();
286 ++i)
287 {
288 if (longestPrefix == registeredPrefixTable_.end() ||
Alexander Afanasyevb790d952014-01-24 12:07:53 -0800289 (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800290 {
291 longestPrefix = i;
292 }
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700293 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800294 return longestPrefix;
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700295}
296
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800297} // namespace ndn