blob: cec382c351996c3f305ffd675a4224a34bfe9868 [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
Jeff Thompsonea141d72013-09-19 14:40:10 -07008#include <stdexcept>
Jeff Thompson9ae4d782013-10-17 10:25:54 -07009#include "c/util/time.h"
Alexander Afanasyev96d914f2014-01-02 22:24:29 -080010
Jeff Thompson25b4e612013-10-10 16:03:24 -070011#include <ndn-cpp/forwarding-entry.hpp>
Jeff Thompson25b4e612013-10-10 16:03:24 -070012#include <ndn-cpp/node.hpp>
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070013
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080014#include "util/ndnd-id-fetcher.hpp"
Alexander Afanasyev79100492014-01-03 15:35:38 -080015#include "security/signature/signature-sha256-with-rsa.hpp"
Alexander Afanasyev96d914f2014-01-02 22:24:29 -080016
Alexander Afanasyev18371872014-01-05 23:00:26 -080017#include "status-response.hpp"
18
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070019using namespace std;
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070020
21namespace ndn {
22
Jeff Thompson62992e42013-10-07 18:50:51 -070023uint64_t Node::PendingInterest::lastPendingInterestId_ = 0;
24uint64_t Node::RegisteredPrefix::lastRegisteredPrefixId_ = 0;
Jeff Thompson11095142013-10-01 16:20:28 -070025
Alexander Afanasyev0b688dc2013-12-18 16:43:37 -080026Node::Node(const ptr_lib::shared_ptr<Transport>& transport)
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080027 : timer_ (ioService_)
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080028 , processEventsTimeoutTimer_(ioService_)
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080029 , transport_(transport)
30 , ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
Jeff Thompson557b81e2013-08-21 15:13:51 -070031{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080032 timer_.expires_from_now(boost::posix_time::milliseconds(100));
33 timer_.async_wait(func_lib::bind(&Node::checkPitExpire, this));
Jeff Thompson557b81e2013-08-21 15:13:51 -070034}
35
Jeff Thompson62992e42013-10-07 18:50:51 -070036uint64_t
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080037Node::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070038{
Jeff Thompson86507bc2013-08-23 20:51:38 -070039 // TODO: Properly check if we are already connected to the expected host.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080040 if (!transport_->isConnected())
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080041 transport_->connect(ioService_,
42 ptr_lib::bind(&Node::onReceiveElement, this, _1),
43 ptr_lib::bind(&Node::onTransportError, this));
Jeff Thompson86507bc2013-08-23 20:51:38 -070044
Jeff Thompson62992e42013-10-07 18:50:51 -070045 uint64_t pendingInterestId = PendingInterest::getNextPendingInterestId();
Jeff Thompsonce115762013-12-18 14:59:56 -080046 pendingInterestTable_.push_back(ptr_lib::shared_ptr<PendingInterest>(new PendingInterest
47 (pendingInterestId, ptr_lib::shared_ptr<const Interest>(new Interest(interest)), onData, onTimeout)));
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080048
49 transport_->send(interest.wireEncode());
Jeff Thompson11095142013-10-01 16:20:28 -070050
51 return pendingInterestId;
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070052}
53
Jeff Thompson11095142013-10-01 16:20:28 -070054void
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080055Node::put(const Data &data)
56{
57 // TODO: Properly check if we are already connected to the expected host.
58 if (!transport_->isConnected())
59 transport_->connect(ioService_,
60 ptr_lib::bind(&Node::onReceiveElement, this, _1),
61 ptr_lib::bind(&Node::onTransportError, this));
62
63 transport_->send(data.wireEncode());
64}
65
66
67void
Jeff Thompson62992e42013-10-07 18:50:51 -070068Node::removePendingInterest(uint64_t pendingInterestId)
Jeff Thompson11095142013-10-01 16:20:28 -070069{
70 // Go backwards through the list so we can erase entries.
71 // Remove all entries even though pendingInterestId should be unique.
72 for (int i = (int)pendingInterestTable_.size() - 1; i >= 0; --i) {
73 if (pendingInterestTable_[i]->getPendingInterestId() == pendingInterestId)
74 pendingInterestTable_.erase(pendingInterestTable_.begin() + i);
75 }
76}
77
Jeff Thompson62992e42013-10-07 18:50:51 -070078uint64_t
Jeff Thompson590ec232013-09-18 15:55:56 -070079Node::registerPrefix
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080080 (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, const ForwardingFlags& flags)
Jeff Thompson86507bc2013-08-23 20:51:38 -070081{
Jeff Thompson11095142013-10-01 16:20:28 -070082 // Get the registeredPrefixId now so we can return it to the caller.
Jeff Thompson62992e42013-10-07 18:50:51 -070083 uint64_t registeredPrefixId = RegisteredPrefix::getNextRegisteredPrefixId();
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080084 ptr_lib::shared_ptr<const Name> prefixPtr = ptr_lib::make_shared<const Name>(prefix);
85
Jeff Thompson86507bc2013-08-23 20:51:38 -070086 if (ndndId_.size() == 0) {
87 // First fetch the ndndId of the connected hub.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080088 NdndIdFetcher fetcher(ndndId_,
89 func_lib::bind(&Node::registerPrefixHelper, this,
90 registeredPrefixId, prefixPtr, onInterest, onRegisterFailed, flags),
91 func_lib::bind(onRegisterFailed, prefixPtr));
92
93 // @todo: Check if this crash
Jeff Thompsonce115762013-12-18 14:59:56 -080094 // It is OK for func_lib::function make a copy of the function object because the Info is in a ptr_lib::shared_ptr.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080095 expressInterest(ndndIdFetcherInterest_, fetcher, fetcher);
Jeff Thompson86507bc2013-08-23 20:51:38 -070096 }
97 else
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080098 registerPrefixHelper(registeredPrefixId, prefixPtr, onInterest, onRegisterFailed, flags);
Jeff Thompson11095142013-10-01 16:20:28 -070099
100 return registeredPrefixId;
101}
102
103void
Jeff Thompson62992e42013-10-07 18:50:51 -0700104Node::removeRegisteredPrefix(uint64_t registeredPrefixId)
Jeff Thompson11095142013-10-01 16:20:28 -0700105{
106 // Go backwards through the list so we can erase entries.
107 // Remove all entries even though pendingInterestId should be unique.
108 for (int i = (int)registeredPrefixTable_.size() - 1; i >= 0; --i) {
109 if (registeredPrefixTable_[i]->getRegisteredPrefixId() == registeredPrefixId)
110 registeredPrefixTable_.erase(registeredPrefixTable_.begin() + i);
111 }
Jeff Thompson86507bc2013-08-23 20:51:38 -0700112}
113
Jeff Thompson0050abe2013-09-17 12:50:25 -0700114void
Alexander Afanasyev79100492014-01-03 15:35:38 -0800115Node::registerPrefixHelper(uint64_t registeredPrefixId,
116 const ptr_lib::shared_ptr<const Name>& prefix,
117 const OnInterest& onInterest,
118 const OnRegisterFailed& onRegisterFailed,
119 const ForwardingFlags& flags)
Jeff Thompson86507bc2013-08-23 20:51:38 -0700120{
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700121 // Create a ForwardingEntry.
Alexander Afanasyevfbdfa092013-12-28 20:44:49 -0800122
123 // AlexA: ndnd ignores any freshness that is larger than 3600 sec and sets 300 sec instead
124 // to register "forever" (=2000000000 sec), freshnessPeriod must be omitted
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800125 ForwardingEntry forwardingEntry("selfreg", *prefix, -1, flags, -1);
126 Block content = forwardingEntry.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700127
128 // Set the ForwardingEntry as the content of a Data packet and sign.
129 Data data;
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700130 data.setContent(content);
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700131
Alexander Afanasyev79100492014-01-03 15:35:38 -0800132 // Create an empty signature, since nobody going to verify it for now
133 // @todo In the future, we may require real signatures to do the registration
134 SignatureSha256WithRsa signature;
135 signature.setValue(Block(Tlv::SignatureValue, ptr_lib::make_shared<Buffer>()));
136 data.setSignature(signature);
137
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700138 // Create an interest where the name has the encoded Data packet.
139 Name interestName;
Alexander Afanasyev18371872014-01-05 23:00:26 -0800140 interestName.append("ndnx");
Jeff Thompson3a715632013-10-31 11:36:35 -0700141 interestName.append(ndndId_);
Alexander Afanasyev18371872014-01-05 23:00:26 -0800142 interestName.append("selfreg");
Alexander Afanasyev79100492014-01-03 15:35:38 -0800143 interestName.append(data.wireEncode());
Alexander Afanasyev18371872014-01-05 23:00:26 -0800144
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700145 Interest interest(interestName);
146 interest.setScope(1);
Alexander Afanasyev18371872014-01-05 23:00:26 -0800147 interest.setInterestLifetime(1000);
148
149 expressInterest(interest,
150 func_lib::bind(&Node::registerPrefixFinal, this,
151 registeredPrefixId, prefix, onInterest, onRegisterFailed, _1, _2),
152 func_lib::bind(onRegisterFailed, prefix));
153}
154
155void
156Node::registerPrefixFinal(uint64_t registeredPrefixId,
157 const ptr_lib::shared_ptr<const Name>& prefix,
158 const OnInterest& onInterest,
159 const OnRegisterFailed& onRegisterFailed,
160 const ptr_lib::shared_ptr<const Interest>&, const ptr_lib::shared_ptr<Data>&data)
161{
162 Block content = data->getContent();
163 content.parse();
164
165 if (content.getAll().empty())
166 {
167 onRegisterFailed(prefix);
168 return;
169 }
170
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800171 Block::element_iterator val = content.getAll().begin();
172
173 switch(val->type())
Alexander Afanasyev18371872014-01-05 23:00:26 -0800174 {
175 case Tlv::FaceManagement::ForwardingEntry:
176 {
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800177 ForwardingEntry entry;
178 entry.wireDecode(*val);
179
180 // Save the onInterest callback and send the registration interest.
181 registeredPrefixTable_.push_back(ptr_lib::make_shared<RegisteredPrefix>(registeredPrefixId, prefix, onInterest));
182
183 /// @todo Notify user about successful registration
184
Alexander Afanasyev18371872014-01-05 23:00:26 -0800185 // succeeded
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800186 return;
Alexander Afanasyev18371872014-01-05 23:00:26 -0800187 }
188 case Tlv::FaceManagement::StatusResponse:
189 {
190 // failed :(
191 StatusResponse resp;
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800192 resp.wireDecode(*val);
Alexander Afanasyev18371872014-01-05 23:00:26 -0800193
194 std::cerr << "StatusReponse: " << resp << std::endl;
195
196 onRegisterFailed(prefix);
197 return;
Alexander Afanasyev18371872014-01-05 23:00:26 -0800198 }
199 default:
200 {
201 // failed :(
202
203 onRegisterFailed(prefix);
204 return;
Alexander Afanasyev18371872014-01-05 23:00:26 -0800205 }
206 }
Jeff Thompson86507bc2013-08-23 20:51:38 -0700207}
208
Jeff Thompson0050abe2013-09-17 12:50:25 -0700209void
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800210Node::processEvents(Milliseconds timeout/* = 0 */)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700211{
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800212 if (timeout > 0)
213 {
214 processEventsTimeoutTimer_.expires_from_now(boost::posix_time::milliseconds(timeout));
215 processEventsTimeoutTimer_.async_wait(func_lib::bind(&Node::shutdown, this));
216 }
217 try
218 {
219 ioService_.run();
220 ioService_.reset();
221 }
222 catch(Node::Error &)
223 {
224 ioService_.reset(); // this needed in order to call ioService_.run() again in the future
225 throw;
226 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800227}
228
229void
230Node::checkPitExpire()
231{
Jeff Thompson48917f02013-08-21 17:12:45 -0700232 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
Jeff Thompson9a8e82f2013-10-17 14:13:43 -0700233 MillisecondsSince1970 nowMilliseconds = ndn_getNowMilliseconds();
Jeff Thompson11095142013-10-01 16:20:28 -0700234 for (int i = (int)pendingInterestTable_.size() - 1; i >= 0; --i) {
Jeff Thompson3b0ed532013-11-05 13:43:40 -0800235 if (pendingInterestTable_[i]->isTimedOut(nowMilliseconds)) {
236 // Save the PendingInterest and remove it from the PIT. Then call the callback.
Jeff Thompsonce115762013-12-18 14:59:56 -0800237 ptr_lib::shared_ptr<PendingInterest> pendingInterest = pendingInterestTable_[i];
Jeff Thompson11095142013-10-01 16:20:28 -0700238 pendingInterestTable_.erase(pendingInterestTable_.begin() + i);
Jeff Thompson3b0ed532013-11-05 13:43:40 -0800239 pendingInterest->callTimeout();
Jeff Thompson48917f02013-08-21 17:12:45 -0700240
241 // Refresh now since the timeout callback might have delayed.
Jeff Thompson9ae4d782013-10-17 10:25:54 -0700242 nowMilliseconds = ndn_getNowMilliseconds();
Jeff Thompson48917f02013-08-21 17:12:45 -0700243 }
244 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800245
246 timer_.expires_from_now(boost::posix_time::milliseconds(100));
247 timer_.async_wait(func_lib::bind(&Node::checkPitExpire, this));
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700248}
249
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800250
Jeff Thompson0050abe2013-09-17 12:50:25 -0700251void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800252Node::onReceiveElement(const Block &block)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700253{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800254 if (block.type() == Tlv::Interest)
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800255 {
256 ptr_lib::shared_ptr<Interest> interest(new Interest());
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800257 interest->wireDecode(block);
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700258
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800259 RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
260 if (entry != registeredPrefixTable_.end()) {
261 (*entry)->getOnInterest()((*entry)->getPrefix(), interest, *transport_, (*entry)->getRegisteredPrefixId());
262 }
Jeff Thompson557b81e2013-08-21 15:13:51 -0700263 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800264 else if (block.type() == Tlv::Data)
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800265 {
266 ptr_lib::shared_ptr<Data> data(new Data());
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800267 data->wireDecode(block);
268
269 PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
270 if (entry != pendingInterestTable_.end()) {
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800271 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800272 const OnData onData = (*entry)->getOnData();
273 const ptr_lib::shared_ptr<const Interest> interest = (*entry)->getInterest();
274 pendingInterestTable_.erase(entry);
Alexander Afanasyev96d914f2014-01-02 22:24:29 -0800275 onData(interest, data);
276 }
277 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700278}
279
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800280void
281Node::onTransportError()
282{
283 /// @todo Set some error code
284
285 ioService_.stop();
286 throw Error("TransportError");
287}
288
Jeff Thompson0050abe2013-09-17 12:50:25 -0700289void
290Node::shutdown()
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700291{
292 transport_->close();
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800293 ioService_.stop();
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700294}
295
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800296Node::PendingInterestTable::iterator
Jeff Thompson0050abe2013-09-17 12:50:25 -0700297Node::getEntryIndexForExpressedInterest(const Name& name)
Jeff Thompson557b81e2013-08-21 15:13:51 -0700298{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800299 for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
300 i != pendingInterestTable_.end(); ++i)
301 {
302 if ((*i)->getInterest()->matchesName(name))
303 {
304 return i;
305 }
Jeff Thompson557b81e2013-08-21 15:13:51 -0700306 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800307
308 return pendingInterestTable_.end();
Jeff Thompson557b81e2013-08-21 15:13:51 -0700309}
Jeff Thompson86507bc2013-08-23 20:51:38 -0700310
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800311Node::RegisteredPrefixTable::iterator
Jeff Thompson0050abe2013-09-17 12:50:25 -0700312Node::getEntryForRegisteredPrefix(const Name& name)
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700313{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800314 RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
315
316 for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
317 i != registeredPrefixTable_.end();
318 ++i)
319 {
320 if (longestPrefix == registeredPrefixTable_.end() ||
321 (*i)->getPrefix()->size() > (*longestPrefix)->getPrefix()->size())
322 {
323 longestPrefix = i;
324 }
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700325 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800326 return longestPrefix;
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700327}
328
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800329Node::PendingInterest::PendingInterest(uint64_t pendingInterestId,
330 const ptr_lib::shared_ptr<const Interest>& interest,
331 const OnData& onData, const OnTimeout& onTimeout)
332: pendingInterestId_(pendingInterestId),
333 interest_(interest),
334 onData_(onData), onTimeout_(onTimeout)
Jeff Thompson86507bc2013-08-23 20:51:38 -0700335{
336 // Set up timeoutTime_.
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800337 if (interest_->getInterestLifetime() >= 0)
338 timeoutTimeMilliseconds_ = ndn_getNowMilliseconds() + interest_->getInterestLifetime();
Jeff Thompson86507bc2013-08-23 20:51:38 -0700339 else
340 // No timeout.
Alexander Afanasyevb24a68a2013-12-28 16:53:21 -0800341 /**
342 * @todo Set more meaningful default timeout. This timeout MUST exist.
343 */
344 timeoutTimeMilliseconds_ = ndn_getNowMilliseconds() + 4000;
Jeff Thompson86507bc2013-08-23 20:51:38 -0700345}
346
Jeff Thompson3b0ed532013-11-05 13:43:40 -0800347void
348Node::PendingInterest::callTimeout()
Jeff Thompson86507bc2013-08-23 20:51:38 -0700349{
Jeff Thompson3b0ed532013-11-05 13:43:40 -0800350 if (onTimeout_) {
351 // Ignore all exceptions.
352 try {
353 onTimeout_(interest_);
Jeff Thompson86507bc2013-08-23 20:51:38 -0700354 }
Jeff Thompson3b0ed532013-11-05 13:43:40 -0800355 catch (...) { }
Jeff Thompson86507bc2013-08-23 20:51:38 -0700356 }
Jeff Thompson86507bc2013-08-23 20:51:38 -0700357}
Jeff Thompson557b81e2013-08-21 15:13:51 -0700358
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700359}