blob: 4e34ec8c700a85cd18e956def588567bbcd7b39c [file] [log] [blame]
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -07001/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07002 * Copyright (C) 2013 Regents of the University of California.
3 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -07004 * See COPYING for copyright and distribution information.
5 */
6
Jeff Thompson48917f02013-08-21 17:12:45 -07007#include <sys/time.h>
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -07008#include "encoding/binary-xml-decoder.hpp"
9#include "c/encoding/binary-xml.h"
Jeff Thompson9cc4be42013-08-27 18:12:41 -070010#include "forwarding-entry.hpp"
11#include "security/key-chain.hpp"
Jeff Thompson20af0732013-09-12 17:01:45 -070012#include "sha256-with-rsa-signature.hpp"
Jeff Thompsonb09fcc12013-08-22 10:37:10 -070013#include "node.hpp"
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070014
15using namespace std;
16using namespace ndn::ptr_lib;
17
18namespace ndn {
19
Jeff Thompson48917f02013-08-21 17:12:45 -070020// Use gettimeofday to return the current time in milliseconds.
Jeff Thompson0050abe2013-09-17 12:50:25 -070021static inline double
22getNowMilliseconds()
Jeff Thompson557b81e2013-08-21 15:13:51 -070023{
Jeff Thompson48917f02013-08-21 17:12:45 -070024 timeval t;
25 gettimeofday(&t, NULL);
26 return t.tv_sec * 1000.0 + t.tv_usec / 1000.0;
27}
Jeff Thompson557b81e2013-08-21 15:13:51 -070028
Jeff Thompson590ec232013-09-18 15:55:56 -070029Node::Node(const shared_ptr<Transport>& transport, const shared_ptr<const Transport::ConnectionInfo>& connectionInfo)
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070030: transport_(transport), connectionInfo_(connectionInfo),
31 ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
Jeff Thompson557b81e2013-08-21 15:13:51 -070032{
Jeff Thompson557b81e2013-08-21 15:13:51 -070033}
34
Jeff Thompson0050abe2013-09-17 12:50:25 -070035void
36Node::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070037{
Jeff Thompson86507bc2013-08-23 20:51:38 -070038 // TODO: Properly check if we are already connected to the expected host.
39 if (!transport_->getIsConnected())
40 transport_->connect(*connectionInfo_, *this);
41
Jeff Thompson9cc4be42013-08-27 18:12:41 -070042 pit_.push_back(shared_ptr<PitEntry>(new PitEntry(shared_ptr<const Interest>(new Interest(interest)), onData, onTimeout)));
Jeff Thompson557b81e2013-08-21 15:13:51 -070043
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070044 Blob encoding = interest.wireEncode();
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070045 transport_->send(*encoding);
46}
47
Jeff Thompson0050abe2013-09-17 12:50:25 -070048void
Jeff Thompson590ec232013-09-18 15:55:56 -070049Node::registerPrefix
50 (const Name& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed, KeyChain &keyChain,
51 const Name& signerName, bool byKeyName, int flags, WireFormat& wireFormat)
Jeff Thompson86507bc2013-08-23 20:51:38 -070052{
53 if (ndndId_.size() == 0) {
54 // First fetch the ndndId of the connected hub.
Jeff Thompson590ec232013-09-18 15:55:56 -070055 NdndIdFetcher fetcher
56 (shared_ptr<NdndIdFetcher::Info>(new NdndIdFetcher::Info
57 (this, prefix, onInterest, onRegisterFailed, keyChain, signerName, byKeyName, flags, wireFormat)));
Jeff Thompson86507bc2013-08-23 20:51:38 -070058 // It is OK for func_lib::function make a copy of the function object because the Info is in a shared_ptr.
59 expressInterest(ndndIdFetcherInterest_, fetcher, fetcher);
60 }
61 else
Jeff Thompson590ec232013-09-18 15:55:56 -070062 registerPrefixHelper
63 (make_shared<const Name>(prefix), onInterest, onRegisterFailed, keyChain, make_shared<const Name>(signerName), byKeyName,
64 flags, wireFormat);
Jeff Thompson86507bc2013-08-23 20:51:38 -070065}
66
Jeff Thompson0050abe2013-09-17 12:50:25 -070067void
Jeff Thompson590ec232013-09-18 15:55:56 -070068Node::NdndIdFetcher::operator()(const shared_ptr<const Interest>& interest, const shared_ptr<Data>& ndndIdData)
Jeff Thompson86507bc2013-08-23 20:51:38 -070069{
Jeff Thompson20af0732013-09-12 17:01:45 -070070 Sha256WithRsaSignature *signature = dynamic_cast<Sha256WithRsaSignature*>(ndndIdData->getSignature());
71 if (signature && signature->getPublisherPublicKeyDigest().getPublisherPublicKeyDigest().size() > 0) {
Jeff Thompson86507bc2013-08-23 20:51:38 -070072 // Set the ndndId_ and continue.
Jeff Thompson7a67cb62013-08-26 11:43:18 -070073 // TODO: If there are multiple connected hubs, the NDN ID is really stored per connected hub.
Jeff Thompson20af0732013-09-12 17:01:45 -070074 info_->node_.ndndId_ = signature->getPublisherPublicKeyDigest().getPublisherPublicKeyDigest();
Jeff Thompson590ec232013-09-18 15:55:56 -070075 info_->node_.registerPrefixHelper
76 (info_->prefix_, info_->onInterest_, info_->onRegisterFailed_, info_->keyChain_, info_->signerName_,
77 info_->byKeyName_, info_->flags_, info_->wireFormat_);
Jeff Thompson86507bc2013-08-23 20:51:38 -070078 }
Jeff Thompson590ec232013-09-18 15:55:56 -070079 else
80 info_->onRegisterFailed_(info_->prefix_);
Jeff Thompson86507bc2013-08-23 20:51:38 -070081}
82
Jeff Thompson0050abe2013-09-17 12:50:25 -070083void
Jeff Thompson590ec232013-09-18 15:55:56 -070084Node::NdndIdFetcher::operator()(const shared_ptr<const Interest>& timedOutInterest)
Jeff Thompson86507bc2013-08-23 20:51:38 -070085{
Jeff Thompson590ec232013-09-18 15:55:56 -070086 info_->onRegisterFailed_(info_->prefix_);
Jeff Thompson86507bc2013-08-23 20:51:38 -070087}
88
Jeff Thompson0050abe2013-09-17 12:50:25 -070089void
Jeff Thompson590ec232013-09-18 15:55:56 -070090Node::registerPrefixHelper
91 (const shared_ptr<const Name>& prefix, const OnInterest& onInterest, const OnRegisterFailed& onRegisterFailed,
92 KeyChain &keyChain, const shared_ptr<const Name>& signerName, bool byKeyName, int flags, WireFormat& wireFormat)
Jeff Thompson86507bc2013-08-23 20:51:38 -070093{
Jeff Thompson9cc4be42013-08-27 18:12:41 -070094 // Create a ForwardingEntry.
Jeff Thompson590ec232013-09-18 15:55:56 -070095 ForwardingEntry forwardingEntry("selfreg", *prefix, PublisherPublicKeyDigest(), -1, 3, 2147483647);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070096 Blob content = forwardingEntry.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -070097
98 // Set the ForwardingEntry as the content of a Data packet and sign.
99 Data data;
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700100 data.setContent(content);
Jeff Thompsonfec716d2013-09-11 13:54:36 -0700101 data.getMetaInfo().setTimestampMilliseconds(time(NULL) * 1000.0);
Jeff Thompson590ec232013-09-18 15:55:56 -0700102 keyChain.signData(data, *signerName, byKeyName, wireFormat);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700103 Blob encodedData = data.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700104
105 // Create an interest where the name has the encoded Data packet.
106 Name interestName;
107 const unsigned char component0[] = "ndnx";
108 const unsigned char component2[] = "selfreg";
109 interestName.addComponent(component0, sizeof(component0) - 1);
110 interestName.addComponent(ndndId_);
111 interestName.addComponent(component2, sizeof(component2) - 1);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700112 interestName.addComponent(encodedData);
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700113
114 Interest interest(interestName);
115 interest.setScope(1);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700116 Blob encodedInterest = interest.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700117
118 // Save the onInterest callback and send the registration interest.
Jeff Thompson590ec232013-09-18 15:55:56 -0700119 registeredPrefixTable_.push_back(shared_ptr<PrefixEntry>(new PrefixEntry(prefix, onInterest)));
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700120
121 transport_->send(*encodedInterest);
Jeff Thompson86507bc2013-08-23 20:51:38 -0700122}
123
Jeff Thompson0050abe2013-09-17 12:50:25 -0700124void
125Node::processEvents()
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700126{
127 transport_->processEvents();
Jeff Thompson48917f02013-08-21 17:12:45 -0700128
129 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
130 double nowMilliseconds = getNowMilliseconds();
131 for (int i = (int)pit_.size() - 1; i >= 0; --i) {
132 if (pit_[i]->checkTimeout(this, nowMilliseconds)) {
133 pit_.erase(pit_.begin() + i);
134
135 // Refresh now since the timeout callback might have delayed.
136 nowMilliseconds = getNowMilliseconds();
137 }
138 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700139}
140
Jeff Thompson0050abe2013-09-17 12:50:25 -0700141void
142Node::onReceivedElement(const unsigned char *element, unsigned int elementLength)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700143{
144 BinaryXmlDecoder decoder(element, elementLength);
145
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700146 if (decoder.peekDTag(ndn_BinaryXml_DTag_Interest)) {
147 shared_ptr<Interest> interest(new Interest());
148 interest->wireDecode(element, elementLength);
149
150 PrefixEntry *entry = getEntryForRegisteredPrefix(interest->getName());
151 if (entry)
152 entry->getOnInterest()(entry->getPrefix(), interest, *transport_);
153 }
154 else if (decoder.peekDTag(ndn_BinaryXml_DTag_ContentObject)) {
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700155 shared_ptr<Data> data(new Data());
156 data->wireDecode(element, elementLength);
157
Jeff Thompson557b81e2013-08-21 15:13:51 -0700158 int iPitEntry = getEntryIndexForExpressedInterest(data->getName());
159 if (iPitEntry >= 0) {
Jeff Thompson7aec0252013-08-22 17:29:57 -0700160 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
161 const OnData onData = pit_[iPitEntry]->getOnData();
Jeff Thompson590ec232013-09-18 15:55:56 -0700162 const shared_ptr<const Interest> interest = pit_[iPitEntry]->getInterest();
Jeff Thompson557b81e2013-08-21 15:13:51 -0700163 pit_.erase(pit_.begin() + iPitEntry);
Jeff Thompson7aec0252013-08-22 17:29:57 -0700164 onData(interest, data);
Jeff Thompson557b81e2013-08-21 15:13:51 -0700165 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700166 }
167}
168
Jeff Thompson0050abe2013-09-17 12:50:25 -0700169void
170Node::shutdown()
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700171{
172 transport_->close();
173}
174
Jeff Thompson0050abe2013-09-17 12:50:25 -0700175int
176Node::getEntryIndexForExpressedInterest(const Name& name)
Jeff Thompson557b81e2013-08-21 15:13:51 -0700177{
178 // TODO: Doesn't this belong in the Name class?
179 vector<struct ndn_NameComponent> nameComponents;
180 nameComponents.reserve(name.getComponentCount());
181 struct ndn_Name nameStruct;
Jeff Thompsond1427fb2013-08-29 17:20:32 -0700182 ndn_Name_initialize(&nameStruct, &nameComponents[0], nameComponents.capacity());
Jeff Thompson557b81e2013-08-21 15:13:51 -0700183 name.get(nameStruct);
184
185 int iResult = -1;
186
187 for (unsigned int i = 0; i < pit_.size(); ++i) {
188 if (ndn_Interest_matchesName((struct ndn_Interest *)&pit_[i]->getInterestStruct(), &nameStruct)) {
189 if (iResult < 0 ||
Jeff Thompson48917f02013-08-21 17:12:45 -0700190 pit_[i]->getInterestStruct().name.nComponents > pit_[iResult]->getInterestStruct().name.nComponents)
191 // Update to the longer match.
Jeff Thompson557b81e2013-08-21 15:13:51 -0700192 iResult = i;
193 }
194 }
195
196 return iResult;
197}
Jeff Thompson86507bc2013-08-23 20:51:38 -0700198
Jeff Thompson0050abe2013-09-17 12:50:25 -0700199Node::PrefixEntry*
200Node::getEntryForRegisteredPrefix(const Name& name)
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700201{
202 int iResult = -1;
203
Jeff Thompson7a57f672013-08-28 09:55:39 -0700204 for (unsigned int i = 0; i < registeredPrefixTable_.size(); ++i) {
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700205 if (registeredPrefixTable_[i]->getPrefix()->match(name)) {
206 if (iResult < 0 ||
207 registeredPrefixTable_[i]->getPrefix()->getComponentCount() > registeredPrefixTable_[iResult]->getPrefix()->getComponentCount())
208 // Update to the longer match.
209 iResult = i;
210 }
211 }
212
213 if (iResult >= 0)
214 return registeredPrefixTable_[iResult].get();
215 else
216 return 0;
217}
218
Jeff Thompson590ec232013-09-18 15:55:56 -0700219Node::PitEntry::PitEntry(const shared_ptr<const Interest>& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompson86507bc2013-08-23 20:51:38 -0700220: interest_(interest), onData_(onData), onTimeout_(onTimeout)
221{
222 // Set up timeoutTime_.
223 if (interest_->getInterestLifetimeMilliseconds() >= 0.0)
224 timeoutTimeMilliseconds_ = getNowMilliseconds() + interest_->getInterestLifetimeMilliseconds();
225 else
226 // No timeout.
227 timeoutTimeMilliseconds_ = -1.0;
228
229 // Set up interestStruct_.
230 // TODO: Doesn't this belong in the Interest class?
231 nameComponents_.reserve(interest_->getName().getComponentCount());
232 excludeEntries_.reserve(interest_->getExclude().getEntryCount());
Jeff Thompsond1427fb2013-08-29 17:20:32 -0700233 ndn_Interest_initialize
Jeff Thompson86507bc2013-08-23 20:51:38 -0700234 (&interestStruct_, &nameComponents_[0], nameComponents_.capacity(), &excludeEntries_[0], excludeEntries_.capacity());
235 interest_->get(interestStruct_);
236}
237
Jeff Thompson0050abe2013-09-17 12:50:25 -0700238bool
239Node::PitEntry::checkTimeout(Node *parent, double nowMilliseconds)
Jeff Thompson86507bc2013-08-23 20:51:38 -0700240{
241 if (timeoutTimeMilliseconds_ >= 0.0 && nowMilliseconds >= timeoutTimeMilliseconds_) {
242 if (onTimeout_) {
243 // Ignore all exceptions.
244 try {
245 onTimeout_(interest_);
246 }
247 catch (...) { }
248 }
249
250 return true;
251 }
252 else
253 return false;
254}
Jeff Thompson557b81e2013-08-21 15:13:51 -0700255
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700256}