blob: 779d28563103fa981ff2662ad88a4204980b41aa [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.
21static inline double getNowMilliseconds()
Jeff Thompson557b81e2013-08-21 15:13:51 -070022{
Jeff Thompson48917f02013-08-21 17:12:45 -070023 timeval t;
24 gettimeofday(&t, NULL);
25 return t.tv_sec * 1000.0 + t.tv_usec / 1000.0;
26}
Jeff Thompson557b81e2013-08-21 15:13:51 -070027
Jeff Thompson1656e6a2013-08-29 18:01:48 -070028Node::Node(const ptr_lib::shared_ptr<Transport>& transport, const ptr_lib::shared_ptr<const Transport::ConnectionInfo>& connectionInfo)
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070029: transport_(transport), connectionInfo_(connectionInfo),
30 ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
Jeff Thompson557b81e2013-08-21 15:13:51 -070031{
Jeff Thompson557b81e2013-08-21 15:13:51 -070032}
33
Jeff Thompson1656e6a2013-08-29 18:01:48 -070034void Node::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070035{
Jeff Thompson86507bc2013-08-23 20:51:38 -070036 // TODO: Properly check if we are already connected to the expected host.
37 if (!transport_->getIsConnected())
38 transport_->connect(*connectionInfo_, *this);
39
Jeff Thompson9cc4be42013-08-27 18:12:41 -070040 pit_.push_back(shared_ptr<PitEntry>(new PitEntry(shared_ptr<const Interest>(new Interest(interest)), onData, onTimeout)));
Jeff Thompson557b81e2013-08-21 15:13:51 -070041
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070042 Blob encoding = interest.wireEncode();
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070043 transport_->send(*encoding);
44}
45
Jeff Thompson1656e6a2013-08-29 18:01:48 -070046void Node::registerPrefix(const Name& prefix, const OnInterest& onInterest, int flags)
Jeff Thompson86507bc2013-08-23 20:51:38 -070047{
48 if (ndndId_.size() == 0) {
49 // First fetch the ndndId of the connected hub.
50 NdndIdFetcher fetcher(make_shared<NdndIdFetcher::Info>(this, prefix, onInterest, flags));
51 // It is OK for func_lib::function make a copy of the function object because the Info is in a shared_ptr.
52 expressInterest(ndndIdFetcherInterest_, fetcher, fetcher);
53 }
54 else
55 registerPrefixHelper(prefix, onInterest, flags);
56}
57
Jeff Thompson1656e6a2013-08-29 18:01:48 -070058void Node::NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest>& interest, const ptr_lib::shared_ptr<Data>& ndndIdData)
Jeff Thompson86507bc2013-08-23 20:51:38 -070059{
Jeff Thompson20af0732013-09-12 17:01:45 -070060 Sha256WithRsaSignature *signature = dynamic_cast<Sha256WithRsaSignature*>(ndndIdData->getSignature());
61 if (signature && signature->getPublisherPublicKeyDigest().getPublisherPublicKeyDigest().size() > 0) {
Jeff Thompson86507bc2013-08-23 20:51:38 -070062 // Set the ndndId_ and continue.
Jeff Thompson7a67cb62013-08-26 11:43:18 -070063 // TODO: If there are multiple connected hubs, the NDN ID is really stored per connected hub.
Jeff Thompson20af0732013-09-12 17:01:45 -070064 info_->node_.ndndId_ = signature->getPublisherPublicKeyDigest().getPublisherPublicKeyDigest();
Jeff Thompson86507bc2013-08-23 20:51:38 -070065 info_->node_.registerPrefixHelper(info_->prefix_, info_->onInterest_, info_->flags_);
66 }
67 // TODO: else need to log not getting the ndndId.
68}
69
Jeff Thompson1656e6a2013-08-29 18:01:48 -070070void Node::NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest>& timedOutInterest)
Jeff Thompson86507bc2013-08-23 20:51:38 -070071{
72 // TODO: Log the timeout.
73}
74
Jeff Thompson1656e6a2013-08-29 18:01:48 -070075void Node::registerPrefixHelper(const Name& prefix, const OnInterest& onInterest, int flags)
Jeff Thompson86507bc2013-08-23 20:51:38 -070076{
Jeff Thompson9cc4be42013-08-27 18:12:41 -070077 // Create a ForwardingEntry.
78 ForwardingEntry forwardingEntry("selfreg", prefix, PublisherPublicKeyDigest(), -1, 3, 2147483647);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070079 Blob content = forwardingEntry.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -070080
81 // Set the ForwardingEntry as the content of a Data packet and sign.
82 Data data;
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070083 data.setContent(content);
Jeff Thompsonfec716d2013-09-11 13:54:36 -070084 data.getMetaInfo().setTimestampMilliseconds(time(NULL) * 1000.0);
Jeff Thompson9cc4be42013-08-27 18:12:41 -070085 // TODO: Should we sign with a different key?
86 KeyChain::defaultSign(data);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070087 Blob encodedData = data.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -070088
89 // Create an interest where the name has the encoded Data packet.
90 Name interestName;
91 const unsigned char component0[] = "ndnx";
92 const unsigned char component2[] = "selfreg";
93 interestName.addComponent(component0, sizeof(component0) - 1);
94 interestName.addComponent(ndndId_);
95 interestName.addComponent(component2, sizeof(component2) - 1);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -070096 interestName.addComponent(encodedData);
Jeff Thompson9cc4be42013-08-27 18:12:41 -070097
98 Interest interest(interestName);
99 interest.setScope(1);
Jeff Thompsonc2b7b142013-09-12 15:29:04 -0700100 Blob encodedInterest = interest.wireEncode();
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700101
102 // Save the onInterest callback and send the registration interest.
103 registeredPrefixTable_.push_back(shared_ptr<PrefixEntry>(new PrefixEntry(shared_ptr<const Name>(new Name(prefix)), onInterest)));
104
105 transport_->send(*encodedInterest);
Jeff Thompson86507bc2013-08-23 20:51:38 -0700106}
107
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700108void Node::processEvents()
109{
110 transport_->processEvents();
Jeff Thompson48917f02013-08-21 17:12:45 -0700111
112 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
113 double nowMilliseconds = getNowMilliseconds();
114 for (int i = (int)pit_.size() - 1; i >= 0; --i) {
115 if (pit_[i]->checkTimeout(this, nowMilliseconds)) {
116 pit_.erase(pit_.begin() + i);
117
118 // Refresh now since the timeout callback might have delayed.
119 nowMilliseconds = getNowMilliseconds();
120 }
121 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700122}
123
Jeff Thompson8b173cc2013-08-21 17:54:12 -0700124void Node::onReceivedElement(const unsigned char *element, unsigned int elementLength)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700125{
126 BinaryXmlDecoder decoder(element, elementLength);
127
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700128 if (decoder.peekDTag(ndn_BinaryXml_DTag_Interest)) {
129 shared_ptr<Interest> interest(new Interest());
130 interest->wireDecode(element, elementLength);
131
132 PrefixEntry *entry = getEntryForRegisteredPrefix(interest->getName());
133 if (entry)
134 entry->getOnInterest()(entry->getPrefix(), interest, *transport_);
135 }
136 else if (decoder.peekDTag(ndn_BinaryXml_DTag_ContentObject)) {
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700137 shared_ptr<Data> data(new Data());
138 data->wireDecode(element, elementLength);
139
Jeff Thompson557b81e2013-08-21 15:13:51 -0700140 int iPitEntry = getEntryIndexForExpressedInterest(data->getName());
141 if (iPitEntry >= 0) {
Jeff Thompson7aec0252013-08-22 17:29:57 -0700142 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
143 const OnData onData = pit_[iPitEntry]->getOnData();
144 const ptr_lib::shared_ptr<const Interest> interest = pit_[iPitEntry]->getInterest();
Jeff Thompson557b81e2013-08-21 15:13:51 -0700145 pit_.erase(pit_.begin() + iPitEntry);
Jeff Thompson7aec0252013-08-22 17:29:57 -0700146 onData(interest, data);
Jeff Thompson557b81e2013-08-21 15:13:51 -0700147 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700148 }
149}
150
151void Node::shutdown()
152{
153 transport_->close();
154}
155
Jeff Thompson1656e6a2013-08-29 18:01:48 -0700156int Node::getEntryIndexForExpressedInterest(const Name& name)
Jeff Thompson557b81e2013-08-21 15:13:51 -0700157{
158 // TODO: Doesn't this belong in the Name class?
159 vector<struct ndn_NameComponent> nameComponents;
160 nameComponents.reserve(name.getComponentCount());
161 struct ndn_Name nameStruct;
Jeff Thompsond1427fb2013-08-29 17:20:32 -0700162 ndn_Name_initialize(&nameStruct, &nameComponents[0], nameComponents.capacity());
Jeff Thompson557b81e2013-08-21 15:13:51 -0700163 name.get(nameStruct);
164
165 int iResult = -1;
166
167 for (unsigned int i = 0; i < pit_.size(); ++i) {
168 if (ndn_Interest_matchesName((struct ndn_Interest *)&pit_[i]->getInterestStruct(), &nameStruct)) {
169 if (iResult < 0 ||
Jeff Thompson48917f02013-08-21 17:12:45 -0700170 pit_[i]->getInterestStruct().name.nComponents > pit_[iResult]->getInterestStruct().name.nComponents)
171 // Update to the longer match.
Jeff Thompson557b81e2013-08-21 15:13:51 -0700172 iResult = i;
173 }
174 }
175
176 return iResult;
177}
Jeff Thompson86507bc2013-08-23 20:51:38 -0700178
Jeff Thompson1656e6a2013-08-29 18:01:48 -0700179Node::PrefixEntry *Node::getEntryForRegisteredPrefix(const Name& name)
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700180{
181 int iResult = -1;
182
Jeff Thompson7a57f672013-08-28 09:55:39 -0700183 for (unsigned int i = 0; i < registeredPrefixTable_.size(); ++i) {
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700184 if (registeredPrefixTable_[i]->getPrefix()->match(name)) {
185 if (iResult < 0 ||
186 registeredPrefixTable_[i]->getPrefix()->getComponentCount() > registeredPrefixTable_[iResult]->getPrefix()->getComponentCount())
187 // Update to the longer match.
188 iResult = i;
189 }
190 }
191
192 if (iResult >= 0)
193 return registeredPrefixTable_[iResult].get();
194 else
195 return 0;
196}
197
Jeff Thompson1656e6a2013-08-29 18:01:48 -0700198Node::PitEntry::PitEntry(const ptr_lib::shared_ptr<const Interest>& interest, const OnData& onData, const OnTimeout& onTimeout)
Jeff Thompson86507bc2013-08-23 20:51:38 -0700199: interest_(interest), onData_(onData), onTimeout_(onTimeout)
200{
201 // Set up timeoutTime_.
202 if (interest_->getInterestLifetimeMilliseconds() >= 0.0)
203 timeoutTimeMilliseconds_ = getNowMilliseconds() + interest_->getInterestLifetimeMilliseconds();
204 else
205 // No timeout.
206 timeoutTimeMilliseconds_ = -1.0;
207
208 // Set up interestStruct_.
209 // TODO: Doesn't this belong in the Interest class?
210 nameComponents_.reserve(interest_->getName().getComponentCount());
211 excludeEntries_.reserve(interest_->getExclude().getEntryCount());
Jeff Thompsond1427fb2013-08-29 17:20:32 -0700212 ndn_Interest_initialize
Jeff Thompson86507bc2013-08-23 20:51:38 -0700213 (&interestStruct_, &nameComponents_[0], nameComponents_.capacity(), &excludeEntries_[0], excludeEntries_.capacity());
214 interest_->get(interestStruct_);
215}
216
217bool Node::PitEntry::checkTimeout(Node *parent, double nowMilliseconds)
218{
219 if (timeoutTimeMilliseconds_ >= 0.0 && nowMilliseconds >= timeoutTimeMilliseconds_) {
220 if (onTimeout_) {
221 // Ignore all exceptions.
222 try {
223 onTimeout_(interest_);
224 }
225 catch (...) { }
226 }
227
228 return true;
229 }
230 else
231 return false;
232}
Jeff Thompson557b81e2013-08-21 15:13:51 -0700233
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700234}