blob: 5c942da6238869e18e8031a5f0a70a8fea772a5c [file] [log] [blame]
spirosmastorakis4ff8c872016-04-14 09:51:38 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3* Copyright (c) 2016 Regents of the University of California.
4*
5* This file is part of the nTorrent codebase.
6*
7* nTorrent is free software: you can redistribute it and/or modify it under the
8* terms of the GNU Lesser General Public License as published by the Free Software
9* Foundation, either version 3 of the License, or (at your option) any later version.
10*
11* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
12* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14*
15* You should have received copies of the GNU General Public License and GNU Lesser
16* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
17* <http://www.gnu.org/licenses/>.
18*
19* See AUTHORS for complete list of nTorrent authors and contributors.
20*/
21
22#include "update-handler.hpp"
Mickey Sweatt617d2d42016-04-25 22:02:08 -070023#include "util/logging.hpp"
spirosmastorakis4ff8c872016-04-14 09:51:38 -070024
25#include <ndn-cxx/security/signing-helpers.hpp>
26
27namespace ndn {
28namespace ntorrent {
29
30void
31UpdateHandler::sendAliveInterest(StatsTable::iterator iter)
32{
33 Name interestName = Name("/NTORRENT" + m_torrentName.toUri() +
34 "/ALIVE" + m_ownRoutablePrefix.toUri());
35
36 shared_ptr<Interest> i = make_shared<Interest>(interestName);
37
38 // Create and set the LINK object
39 Link link(interestName, { {1, iter->getRecordName()} });
40 m_keyChain->sign(link, signingWithSha256());
41 Block linkWire = link.wireEncode();
42
43 i->setLink(linkWire);
44
45 m_face->expressInterest(*i, bind(&UpdateHandler::decodeDataPacketContent, this, _1, _2),
46 bind(&UpdateHandler::tryNextRoutablePrefix, this, _1));
47 m_face->processEvents(time::milliseconds(-1));
48}
49
50shared_ptr<Data>
51UpdateHandler::createDataPacket(const Name& name)
52{
53 // Parse the sender's routable prefix contained in the name
54 Name sendersRoutablePrefix = name.getSubName(2 + m_torrentName.size());
55
56 if (m_statsTable->find(sendersRoutablePrefix) == m_statsTable->end()) {
57 m_statsTable->insert(sendersRoutablePrefix);
58 }
59
60 shared_ptr<Data> data = make_shared<Data>(name);
61
62 EncodingEstimator estimator;
63 size_t estimatedSize = encodeContent(estimator);
64
65 EncodingBuffer buffer(estimatedSize, 0);
66 encodeContent(buffer);
67
68 data->setContentType(tlv::ContentType_Blob);
69 data->setContent(buffer.block());
70
71 return data;
72}
73
74template<encoding::Tag TAG>
75size_t
76UpdateHandler::encodeContent(EncodingImpl<TAG>& encoder) const
77{
78 // Content ::= CONTENT-TYPE TLV-LENGTH
79 // RoutableName+
80
81 // RoutableName ::= NAME-TYPE TLV-LENGTH
82 // Name
83
84 size_t totalLength = 0;
85 // Encode the names of the first five entries of the stats table
86 uint32_t namesEncoded = 0;
87 for (const auto& entry : *m_statsTable) {
88 if (namesEncoded >= MAX_NUM_OF_ENCODED_NAMES) {
89 break;
90 }
91 size_t nameLength = 0;
92 nameLength += entry.getRecordName().wireEncode(encoder);
93 totalLength += nameLength;
94 ++namesEncoded;
95 }
96 totalLength += encoder.prependVarNumber(totalLength);
97 totalLength += encoder.prependVarNumber(tlv::Content);
98 return totalLength;
99}
100
101void
102UpdateHandler::decodeDataPacketContent(const Interest& interest, const Data& data)
103{
104 // Content ::= CONTENT-TYPE TLV-LENGTH
105 // RoutableName+
106
107 // RoutableName ::= NAME-TYPE TLV-LENGTH
108 // Name
109
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700110 LOG_INFO << "ALIVE data packet received: " << data.getName() << std::endl;
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700111
112 if (data.getContentType() != tlv::ContentType_Blob) {
113 BOOST_THROW_EXCEPTION(Error("Expected Content Type Blob"));
114 }
115
116 const Block& content = data.getContent();
117 content.parse();
118
119 // Decode the names (maintain their ordering)
120 for (auto element = content.elements_end() - 1; element != content.elements_begin() - 1; element--) {
121 element->parse();
122 Name name(*element);
123 if (name.empty()) {
124 BOOST_THROW_EXCEPTION(Error("Empty routable name was received"));
125 }
126 if (m_statsTable->find(name) == m_statsTable->end()) {
127 m_statsTable->insert(name);
128 }
129 }
130}
131
132bool
133UpdateHandler::needsUpdate()
134{
135 if (m_statsTable->size() < MIN_NUM_OF_ROUTABLE_NAMES) {
136 return true;
137 }
138 for (auto i = m_statsTable->begin(); i != m_statsTable->end(); i++) {
139 if (i->getRecordSuccessRate() >= 0.5) {
140 return false;
141 }
142 }
143 return true;
144}
145
146void
147UpdateHandler::learnOwnRoutablePrefix()
148{
149 Interest i(Name("/localhop/nfd/rib/routable-prefixes"));
150 i.setInterestLifetime(time::milliseconds(100));
151
152 // parse the first contained routable prefix and set it as the ownRoutablePrefix
153 auto prefixReceived = [this] (const Interest& interest, const Data& data) {
154 const Block& content = data.getContent();
155 content.parse();
156
157 auto element = content.elements_begin();
158 element->parse();
159 Name ownRoutablePrefix(*element);
160 m_ownRoutablePrefix = ownRoutablePrefix;
161 };
162
163 auto prefixRetrievalFailed = [this] (const Interest&) {
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700164 LOG_ERROR << "Own Routable Prefix Retrieval Failed. Trying again." << std::endl;
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700165 // TODO(Spyros): This could lead to an infinite loop. Figure out something better...
166 this->learnOwnRoutablePrefix();
167 };
168
169 m_face->expressInterest(i, prefixReceived, prefixRetrievalFailed);
170 m_face->processEvents(time::milliseconds(-1));
171}
172
173void
174UpdateHandler::onInterestReceived(const InterestFilter& filter, const Interest& interest)
175{
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700176 LOG_INFO << "Interest Received: " << interest.getName().toUri() << std::endl;
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700177 shared_ptr<Data> data = this->createDataPacket(interest.getName());
178 m_keyChain->sign(*data, signingWithSha256());
179 m_face->put(*data);
180}
181
182void
183UpdateHandler::onRegisterFailed(const Name& prefix, const std::string& reason)
184{
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700185 LOG_ERROR << "ERROR: Failed to register prefix \""
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700186 << prefix << "\" in local hub's daemon (" << reason << ")"
187 << std::endl;
188 m_face->shutdown();
189}
190
191void
192UpdateHandler::tryNextRoutablePrefix(const Interest& interest)
193{
194 Link link(interest.getLink());
195 const Name& name = link.getDelegations().begin()->second;
196 auto iter = m_statsTable->find(name);
197
198 if (iter != m_statsTable->end()) {
199 if (iter + 1 == m_statsTable->end()) {
200 iter = m_statsTable->begin();
201 }
202 else {
203 ++iter;
204 }
205 }
206 else {
207 iter = m_statsTable->begin();
208 }
209
210 shared_ptr<Interest> newInterest = make_shared<Interest>(interest);
211
212 link.removeDelegation(name);
213 link.addDelegation(1, iter->getRecordName());
214
215 m_keyChain->sign(link, signingWithSha256());
216 Block block = link.wireEncode();
217
218 newInterest->setLink(block);
219
220 m_face->expressInterest(*newInterest, bind(&UpdateHandler::decodeDataPacketContent, this, _1, _2),
221 bind(&UpdateHandler::tryNextRoutablePrefix, this, _1));
222 m_face->processEvents(time::milliseconds(-1));
223}
224
225} // namespace ntorrent
226} // namespace ndn