blob: 6a60e3b086cd58aea45a4b93fa6666d5f525a317 [file] [log] [blame]
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -07001/**
2 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
4 */
5
Jeff Thompson48917f02013-08-21 17:12:45 -07006#include <sys/time.h>
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -07007#include "encoding/binary-xml-decoder.hpp"
8#include "c/encoding/binary-xml.h"
Jeff Thompson9cc4be42013-08-27 18:12:41 -07009#include "forwarding-entry.hpp"
10#include "security/key-chain.hpp"
Jeff Thompsonb09fcc12013-08-22 10:37:10 -070011#include "node.hpp"
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070012
13using namespace std;
14using namespace ndn::ptr_lib;
15
16namespace ndn {
17
Jeff Thompson48917f02013-08-21 17:12:45 -070018// Use gettimeofday to return the current time in milliseconds.
19static inline double getNowMilliseconds()
Jeff Thompson557b81e2013-08-21 15:13:51 -070020{
Jeff Thompson48917f02013-08-21 17:12:45 -070021 timeval t;
22 gettimeofday(&t, NULL);
23 return t.tv_sec * 1000.0 + t.tv_usec / 1000.0;
24}
Jeff Thompson557b81e2013-08-21 15:13:51 -070025
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070026Node::Node(const ptr_lib::shared_ptr<Transport> &transport, const ptr_lib::shared_ptr<const Transport::ConnectionInfo> &connectionInfo)
27: transport_(transport), connectionInfo_(connectionInfo),
28 ndndIdFetcherInterest_(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"), 4000.0)
Jeff Thompson557b81e2013-08-21 15:13:51 -070029{
Jeff Thompson557b81e2013-08-21 15:13:51 -070030}
31
Jeff Thompson4fe45512013-08-23 14:06:38 -070032void Node::expressInterest(const Interest &interest, const OnData &onData, const OnTimeout &onTimeout)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070033{
Jeff Thompson86507bc2013-08-23 20:51:38 -070034 // TODO: Properly check if we are already connected to the expected host.
35 if (!transport_->getIsConnected())
36 transport_->connect(*connectionInfo_, *this);
37
Jeff Thompson9cc4be42013-08-27 18:12:41 -070038 pit_.push_back(shared_ptr<PitEntry>(new PitEntry(shared_ptr<const Interest>(new Interest(interest)), onData, onTimeout)));
Jeff Thompson557b81e2013-08-21 15:13:51 -070039
Jeff Thompson9cc4be42013-08-27 18:12:41 -070040 shared_ptr<vector<unsigned char> > encoding = interest.wireEncode();
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -070041 transport_->send(*encoding);
42}
43
Jeff Thompson86507bc2013-08-23 20:51:38 -070044void Node::registerPrefix(const Name &prefix, const OnInterest &onInterest, int flags)
45{
46 if (ndndId_.size() == 0) {
47 // First fetch the ndndId of the connected hub.
48 NdndIdFetcher fetcher(make_shared<NdndIdFetcher::Info>(this, prefix, onInterest, flags));
49 // It is OK for func_lib::function make a copy of the function object because the Info is in a shared_ptr.
50 expressInterest(ndndIdFetcherInterest_, fetcher, fetcher);
51 }
52 else
53 registerPrefixHelper(prefix, onInterest, flags);
54}
55
56void Node::NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest> &interest, const ptr_lib::shared_ptr<Data> &ndndIdData)
57{
58 if (ndndIdData->getSignedInfo().getPublisherPublicKeyDigest().getPublisherPublicKeyDigest().size() > 0) {
59 // Set the ndndId_ and continue.
Jeff Thompson7a67cb62013-08-26 11:43:18 -070060 // TODO: If there are multiple connected hubs, the NDN ID is really stored per connected hub.
Jeff Thompson86507bc2013-08-23 20:51:38 -070061 info_->node_.ndndId_ = ndndIdData->getSignedInfo().getPublisherPublicKeyDigest().getPublisherPublicKeyDigest();
62 info_->node_.registerPrefixHelper(info_->prefix_, info_->onInterest_, info_->flags_);
63 }
64 // TODO: else need to log not getting the ndndId.
65}
66
67void Node::NdndIdFetcher::operator()(const ptr_lib::shared_ptr<const Interest> &timedOutInterest)
68{
69 // TODO: Log the timeout.
70}
71
72void Node::registerPrefixHelper(const Name &prefix, const OnInterest &onInterest, int flags)
73{
Jeff Thompson9cc4be42013-08-27 18:12:41 -070074 // Create a ForwardingEntry.
75 ForwardingEntry forwardingEntry("selfreg", prefix, PublisherPublicKeyDigest(), -1, 3, 2147483647);
76 ptr_lib::shared_ptr<vector<unsigned char> > content = forwardingEntry.wireEncode();
77
78 // Set the ForwardingEntry as the content of a Data packet and sign.
79 Data data;
80 data.setContent(*content);
81 data.getSignedInfo().setTimestampMilliseconds(time(NULL) * 1000.0);
82 // TODO: Should we sign with a different key?
83 KeyChain::defaultSign(data);
84 ptr_lib::shared_ptr<vector<unsigned char> > encodedData = data.wireEncode();
85
86 // Create an interest where the name has the encoded Data packet.
87 Name interestName;
88 const unsigned char component0[] = "ndnx";
89 const unsigned char component2[] = "selfreg";
90 interestName.addComponent(component0, sizeof(component0) - 1);
91 interestName.addComponent(ndndId_);
92 interestName.addComponent(component2, sizeof(component2) - 1);
93 interestName.addComponent(*encodedData);
94
95 Interest interest(interestName);
96 interest.setScope(1);
97 ptr_lib::shared_ptr<vector<unsigned char> > encodedInterest = interest.wireEncode();
98
99 // Save the onInterest callback and send the registration interest.
100 registeredPrefixTable_.push_back(shared_ptr<PrefixEntry>(new PrefixEntry(shared_ptr<const Name>(new Name(prefix)), onInterest)));
101
102 transport_->send(*encodedInterest);
Jeff Thompson86507bc2013-08-23 20:51:38 -0700103}
104
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700105void Node::processEvents()
106{
107 transport_->processEvents();
Jeff Thompson48917f02013-08-21 17:12:45 -0700108
109 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
110 double nowMilliseconds = getNowMilliseconds();
111 for (int i = (int)pit_.size() - 1; i >= 0; --i) {
112 if (pit_[i]->checkTimeout(this, nowMilliseconds)) {
113 pit_.erase(pit_.begin() + i);
114
115 // Refresh now since the timeout callback might have delayed.
116 nowMilliseconds = getNowMilliseconds();
117 }
118 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700119}
120
Jeff Thompson8b173cc2013-08-21 17:54:12 -0700121void Node::onReceivedElement(const unsigned char *element, unsigned int elementLength)
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700122{
123 BinaryXmlDecoder decoder(element, elementLength);
124
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700125 if (decoder.peekDTag(ndn_BinaryXml_DTag_Interest)) {
126 shared_ptr<Interest> interest(new Interest());
127 interest->wireDecode(element, elementLength);
128
129 PrefixEntry *entry = getEntryForRegisteredPrefix(interest->getName());
130 if (entry)
131 entry->getOnInterest()(entry->getPrefix(), interest, *transport_);
132 }
133 else if (decoder.peekDTag(ndn_BinaryXml_DTag_ContentObject)) {
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700134 shared_ptr<Data> data(new Data());
135 data->wireDecode(element, elementLength);
136
Jeff Thompson557b81e2013-08-21 15:13:51 -0700137 int iPitEntry = getEntryIndexForExpressedInterest(data->getName());
138 if (iPitEntry >= 0) {
Jeff Thompson7aec0252013-08-22 17:29:57 -0700139 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
140 const OnData onData = pit_[iPitEntry]->getOnData();
141 const ptr_lib::shared_ptr<const Interest> interest = pit_[iPitEntry]->getInterest();
Jeff Thompson557b81e2013-08-21 15:13:51 -0700142 pit_.erase(pit_.begin() + iPitEntry);
Jeff Thompson7aec0252013-08-22 17:29:57 -0700143 onData(interest, data);
Jeff Thompson557b81e2013-08-21 15:13:51 -0700144 }
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700145 }
146}
147
148void Node::shutdown()
149{
150 transport_->close();
151}
152
Jeff Thompson557b81e2013-08-21 15:13:51 -0700153int Node::getEntryIndexForExpressedInterest(const Name &name)
154{
155 // TODO: Doesn't this belong in the Name class?
156 vector<struct ndn_NameComponent> nameComponents;
157 nameComponents.reserve(name.getComponentCount());
158 struct ndn_Name nameStruct;
159 ndn_Name_init(&nameStruct, &nameComponents[0], nameComponents.capacity());
160 name.get(nameStruct);
161
162 int iResult = -1;
163
164 for (unsigned int i = 0; i < pit_.size(); ++i) {
165 if (ndn_Interest_matchesName((struct ndn_Interest *)&pit_[i]->getInterestStruct(), &nameStruct)) {
166 if (iResult < 0 ||
Jeff Thompson48917f02013-08-21 17:12:45 -0700167 pit_[i]->getInterestStruct().name.nComponents > pit_[iResult]->getInterestStruct().name.nComponents)
168 // Update to the longer match.
Jeff Thompson557b81e2013-08-21 15:13:51 -0700169 iResult = i;
170 }
171 }
172
173 return iResult;
174}
Jeff Thompson86507bc2013-08-23 20:51:38 -0700175
Jeff Thompson9cc4be42013-08-27 18:12:41 -0700176Node::PrefixEntry *Node::getEntryForRegisteredPrefix(const Name &name)
177{
178 int iResult = -1;
179
180 for (unsigned int i = 0; i < pit_.size(); ++i) {
181 if (registeredPrefixTable_[i]->getPrefix()->match(name)) {
182 if (iResult < 0 ||
183 registeredPrefixTable_[i]->getPrefix()->getComponentCount() > registeredPrefixTable_[iResult]->getPrefix()->getComponentCount())
184 // Update to the longer match.
185 iResult = i;
186 }
187 }
188
189 if (iResult >= 0)
190 return registeredPrefixTable_[iResult].get();
191 else
192 return 0;
193}
194
Jeff Thompson86507bc2013-08-23 20:51:38 -0700195Node::PitEntry::PitEntry(const ptr_lib::shared_ptr<const Interest> &interest, const OnData &onData, const OnTimeout &onTimeout)
196: interest_(interest), onData_(onData), onTimeout_(onTimeout)
197{
198 // Set up timeoutTime_.
199 if (interest_->getInterestLifetimeMilliseconds() >= 0.0)
200 timeoutTimeMilliseconds_ = getNowMilliseconds() + interest_->getInterestLifetimeMilliseconds();
201 else
202 // No timeout.
203 timeoutTimeMilliseconds_ = -1.0;
204
205 // Set up interestStruct_.
206 // TODO: Doesn't this belong in the Interest class?
207 nameComponents_.reserve(interest_->getName().getComponentCount());
208 excludeEntries_.reserve(interest_->getExclude().getEntryCount());
209 ndn_Interest_init
210 (&interestStruct_, &nameComponents_[0], nameComponents_.capacity(), &excludeEntries_[0], excludeEntries_.capacity());
211 interest_->get(interestStruct_);
212}
213
214bool Node::PitEntry::checkTimeout(Node *parent, double nowMilliseconds)
215{
216 if (timeoutTimeMilliseconds_ >= 0.0 && nowMilliseconds >= timeoutTimeMilliseconds_) {
217 if (onTimeout_) {
218 // Ignore all exceptions.
219 try {
220 onTimeout_(interest_);
221 }
222 catch (...) { }
223 }
224
225 return true;
226 }
227 else
228 return false;
229}
Jeff Thompson557b81e2013-08-21 15:13:51 -0700230
Jeff Thompsonbf50a1a2013-08-20 18:01:01 -0700231}