blob: b1fd7308693c353b7d579c63cb2c4ea91228a7a1 [file] [log] [blame]
Mickey Sweatt527b0492016-03-02 11:07:48 -08001/* -*- 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*/
spirosmastorakisd351c6b2016-05-06 17:02:48 -070021
Mickey Sweatt527b0492016-03-02 11:07:48 -080022#ifndef INCLUDED_TORRENT_FILE_MANAGER_H
23#define INCLUDED_TORRENT_FILE_MANAGER_H
24
Mickey Sweatt527b0492016-03-02 11:07:48 -080025#include "file-manifest.hpp"
spirosmastorakis9b68b532016-05-02 21:40:29 -070026#include "interest-queue.hpp"
spirosmastorakisa46eee42016-04-05 14:24:45 -070027#include "torrent-file.hpp"
spirosmastorakis4ff8c872016-04-14 09:51:38 -070028#include "update-handler.hpp"
Mickey Sweatt527b0492016-03-02 11:07:48 -080029
Mickey Sweatt527b0492016-03-02 11:07:48 -080030#include <ndn-cxx/data.hpp>
spirosmastorakisa46eee42016-04-05 14:24:45 -070031#include <ndn-cxx/face.hpp>
32#include <ndn-cxx/interest.hpp>
33#include <ndn-cxx/link.hpp>
34#include <ndn-cxx/name.hpp>
35#include <ndn-cxx/security/key-chain.hpp>
Mickey Sweatt527b0492016-03-02 11:07:48 -080036
37#include <boost/filesystem/fstream.hpp>
Mickey Sweatt527b0492016-03-02 11:07:48 -080038
39#include <functional>
40#include <memory>
41#include <string>
42#include <unordered_map>
Mickey Sweatt44e4fd92016-05-02 15:43:11 -070043#include <unordered_set>
Mickey Sweatt527b0492016-03-02 11:07:48 -080044#include <vector>
45
46namespace fs = boost::filesystem;
47
48namespace ndn {
49namespace ntorrent {
50
Mickey Sweatt599bfef2016-04-05 19:11:20 -070051class TorrentManager : noncopyable {
Mickey Sweatt527b0492016-03-02 11:07:48 -080052 /**
53 * \class TorrentManager
54 *
55 * \brief A class to manage the interaction with the system in seeding/leaching a torrent
56 */
57 public:
spirosmastorakisa46eee42016-04-05 14:24:45 -070058 typedef std::function<void(const ndn::Name&)> DataReceivedCallback;
59 typedef std::function<void(const std::vector<ndn::Name>&)> ManifestReceivedCallback;
spirosmastorakis50642f82016-04-08 12:11:18 -070060 typedef std::function<void(const std::vector<ndn::Name>&)> TorrentFileReceivedCallback;
spirosmastorakisa46eee42016-04-05 14:24:45 -070061 typedef std::function<void(const ndn::Name&, const std::string&)> FailedCallback;
Mickey Sweatt527b0492016-03-02 11:07:48 -080062
spirosmastorakisa46eee42016-04-05 14:24:45 -070063 /*
64 * \brief Create a new Torrent manager with the specified parameters.
65 * @param torrentFileName The full name of the initial segment of the torrent file
66 * @param dataPath The path to the location on disk to use for the torrent data
67 * @param face Optional face object to be used for data retrieval
68 *
69 * The behavior is undefined unless Initialize() is called before calling any other method on a
70 * TorrentManger object.
71 */
Mickey Sweatte908a5c2016-04-08 14:10:45 -070072 TorrentManager(const ndn::Name& torrentFileName,
73 const std::string& dataPath,
Mickey Sweatt44e4fd92016-05-02 15:43:11 -070074 bool seed = true,
Mickey Sweatte908a5c2016-04-08 14:10:45 -070075 std::shared_ptr<Face> face = nullptr);
spirosmastorakisa46eee42016-04-05 14:24:45 -070076
Mickey Sweatt527b0492016-03-02 11:07:48 -080077 /*
spirosmastorakisa46eee42016-04-05 14:24:45 -070078 * @brief Initialize the state of this object.
Mickey Sweatt527b0492016-03-02 11:07:48 -080079 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080080 * Read and validate from disk all torrent file segments, file manifests, and data packets for
81 * the torrent file managed by this object initializing all state in this manager respectively.
82 * Also seeds all validated data.
spirosmastorakisa46eee42016-04-05 14:24:45 -070083 */
84 void
85 Initialize();
86
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070087 /**
88 * brief Return 'true' if all segments of the torrent file downloaded, 'false' otherwise.
89 */
90 bool
91 hasAllTorrentSegments() const;
92
spirosmastorakisa46eee42016-04-05 14:24:45 -070093 /*
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070094 * \brief Given a data packet name, find whether we have already downloaded this packet
95 * @param dataName The name of the data packet to download
96 * @return True if we have already downloaded this packet, false otherwise
spirosmastorakisa46eee42016-04-05 14:24:45 -070097 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080098 */
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070099 bool
100 hasDataPacket(const Name& dataName) const;
101
102 /*
103 * \brief Find the torrent file segment that we should download
104 * (either we have nothing or we have them all)
105 * @return A shared_ptr to the name of the segment to download or
106 * nullptr if we have all the segments
107 *
108 */
109 shared_ptr<Name>
110 findTorrentFileSegmentToDownload() const;
111
112 /*
113 * \brief Given a file manifest segment name, find the next file manifest segment
114 * that we should download
115 * @param manifestName The name of the file manifest segment that we want to download
116 * @return A shared_ptr to the name of the segment to download or
117 * nullptr if we have all the segments
118 *
119 */
120 shared_ptr<Name>
121 findManifestSegmentToDownload(const Name& manifestName) const;
122
123 /*
124 * \brief Find the segments of all the file manifests that we are missing
125 * @param manifestNames The name of the manifest file segments to download (currently missing)
126 * This parameter is used as an output vector of names
127 */
128 void
129 findFileManifestsToDownload(std::vector<Name>& manifestNames) const;
130
131 /*
132 * \brief Find the names of the data packets of a file manifest that we are currently missing
133 * @param manifestName The name of the manifest
134 * @param packetNames The name of the data packets to be downloaded
135 * (used as an output vector of names)
136 *
137 * No matter what segment of a manifest file the manifestName parameter might refer to, the
138 * missing data packets starting from the first segment of this manifest file would be returned
139 *
140 */
141 void
142 findDataPacketsToDownload(const Name& manifestName, std::vector<Name>& packetNames) const;
143
144 /*
145 * \brief Find all the data packets that we are currently missing
146 * @param packetNames The name of the data packets to be downloaded
147 * (used as an output vector of names)
148 *
149 */
150 void
151 findAllMissingDataPackets(std::vector<Name>& packetNames) const;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800152
spirosmastorakisa46eee42016-04-05 14:24:45 -0700153 /*
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700154 * @brief Stop all network activities of this manager
155 */
156 void
157 shutdown();
158 /*
spirosmastorakisa46eee42016-04-05 14:24:45 -0700159 * @brief Download the torrent file
160 * @param path The path to write the downloaded segments
161 * @param onSuccess Callback to be called if we successfully download all the
162 * segments of the torrent file. It passes the name of the file manifest
163 * to be downloaded to the callback
164 * @param onFailed Callaback to be called if we fail to download a segment of
165 * the torrent file. It passes the name of the torrent file segment that
166 * failed to download and a failure reason to the callback
167 *
168 * This method provides non-blocking downloading of all the torrent file segments
spirosmastorakisa46eee42016-04-05 14:24:45 -0700169 */
170 void
171 downloadTorrentFile(const std::string& path,
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700172 TorrentFileReceivedCallback onSuccess = {},
173 FailedCallback onFailed = {});
Mickey Sweatt527b0492016-03-02 11:07:48 -0800174
spirosmastorakisa46eee42016-04-05 14:24:45 -0700175 /*
176 * @brief Download a file manifest
177 * @param manifestName The name of the manifest file to be downloaded
178 * @param path The path to write the downloaded segments
179 * @param onSuccess Callback to be called if we successfully download all the
180 * segments of the file manifest. It passes the names of the data packets
181 * to be downloaded to the callback
182 * @param onFailed Callaback to be called if we fail to download a segment of
183 * the file manifest. It passes the name of the data packet that failed
184 * to download and a failure reason
185 *
186 * This method provides non-blocking downloading of all the file manifest segments
187 *
188 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700189 void
190 download_file_manifest(const Name& manifestName,
191 const std::string& path,
192 ManifestReceivedCallback onSuccess,
193 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800194
spirosmastorakisa46eee42016-04-05 14:24:45 -0700195 /*
196 * @brief Download a data packet
197 * @param packetName The name of the data packet to be downloaded
198 * @param onSuccess Callback to be called if we successfully download the data packet.
199 * It passes the name of the data packet to the callback
200 * @param onFailed Callaback to be called if we fail to download the requested data packet
201 * It passes the name of the data packet to the callback and a failure reason
202 *
203 * This method writes the downloaded data packet to m_dataPath on disk
204 *
205 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700206 void
207 download_data_packet(const Name& packetName,
208 DataReceivedCallback onSuccess,
209 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800210
Mickey Sweatt527b0492016-03-02 11:07:48 -0800211 // Seed the specified 'data' to the network.
spirosmastorakis50642f82016-04-08 12:11:18 -0700212 void
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700213 seed(const Data& data);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800214
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700215 /**
216 * @brief Process any data to receive or call timeout callbacks and update prefix list (if needed)
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700217 * By default this blocks until all operations are complete.
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700218 */
219 void
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700220 processEvents(const time::milliseconds& timeout = time::milliseconds(0));
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700221
Mickey Sweatt527b0492016-03-02 11:07:48 -0800222 protected:
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700223 /**
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700224 * \brief Write @p packet composed of torrent date to disk.
225 * @param packet The data packet to be written to the disk
226 * Write the Data packet to disk, return 'true' if data successfully written to disk 'false'
227 * otherwise. Behavior is undefined unless the corresponding file manifest has already been
228 * downloaded.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700229 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700230 bool
231 writeData(const Data& packet);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700232
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700233 /*
234 * \brief Write the @p segment torrent segment to disk at the specified path.
235 * @param segment The torrent file segment to be written to disk
236 * @param path The path at which to write the torrent file segment
237 * Write the segment to disk, return 'true' if data successfully written to disk 'false'
238 * otherwise. Behavior is undefined unless @segment is a correct segment for the torrent file of
239 * this manager and @p path is the directory used for all segments of this torrent file.
240 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700241 bool
242 writeTorrentSegment(const TorrentFile& segment, const std::string& path);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700243
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700244 /*
245 * \brief Write the @p manifest file manifest to disk at the specified @p path.
246 * @param manifest The file manifest to be written to disk
247 * @param path The path at which to write the file manifest
248 * Write the file manifest to disk, return 'true' if data successfully written to disk 'false'
249 * otherwise. Behavior is undefined unless @manifest is a correct file manifest for a file in the
250 * torrent file of this manager and @p path is the directory used for all file manifests of this
251 * torrent file.
252 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700253 bool
254 writeFileManifest(const FileManifest& manifest, const std::string& path);
Mickey Sweattafda1f12016-04-04 17:15:11 -0700255
spirosmastorakisa46eee42016-04-05 14:24:45 -0700256 /*
257 * \brief Download the segments of the torrent file
258 * @param name The name of the torrent file to be downloaded
259 * @param path The path to write the torrent file on disk
spirosmastorakisa46eee42016-04-05 14:24:45 -0700260 * @param onSuccess Optional callback to be called when all the segments of the torrent file
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700261 * have been downloaded. The default value is an empty callback.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700262 * @param onFailed Optional callback to be called when we fail to download a segment of the
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700263 * torrent file. The default value is an empty callback.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700264 *
265 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700266 void
267 downloadTorrentFileSegment(const ndn::Name& name,
268 const std::string& path,
spirosmastorakis50642f82016-04-08 12:11:18 -0700269 TorrentFileReceivedCallback onSuccess,
270 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800271
spirosmastorakisa46eee42016-04-05 14:24:45 -0700272 /*
273 * \brief Download the segments of a file manifest
274 * @param manifestName The name of the file manifest to be downloaded
275 * @param path The path to write the file manifest on disk
276 * @param packetNames A vector containing the name of the data packets in the file manifest
277 * @param onSuccess Callback to be called when all the segments of the file manifest have been
278 * downloaded
279 * @param onFailed Callback to be called when we fail to download a file manifest segment
280 *
281 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700282 void
283 downloadFileManifestSegment(const Name& manifestName,
284 const std::string& path,
285 std::shared_ptr<std::vector<Name>> packetNames,
286 ManifestReceivedCallback onSuccess,
287 FailedCallback onFailed);
spirosmastorakisa46eee42016-04-05 14:24:45 -0700288
289 enum {
290 // Number of times to retry if a routable prefix fails to retrieve data
291 MAX_NUM_OF_RETRIES = 5,
292 // Number of Interests to be sent before sorting the stats table
spirosmastorakis9b68b532016-05-02 21:40:29 -0700293 SORTING_INTERVAL = 100,
294 // Maximum window size used for sending new Interests out
295 WINDOW_SIZE = 50
spirosmastorakisa46eee42016-04-05 14:24:45 -0700296 };
Mickey Sweatt527b0492016-03-02 11:07:48 -0800297
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700298 void onDataReceived(const Data& data);
299
300 void
301 onInterestReceived(const InterestFilter& filter, const Interest& interest);
302
303 void
304 onRegisterFailed(const Name& prefix, const std::string& reason);
305
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700306protected:
Mickey Sweatt527b0492016-03-02 11:07:48 -0800307 // A map from each fileManifest to corresponding file stream on disk and a bitmap of which Data
308 // packets this manager currently has
309 mutable std::unordered_map<Name,
310 std::pair<std::shared_ptr<fs::fstream>,
311 std::vector<bool>>> m_fileStates;
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700312 // A map for each initial manifest to the size for the sub-manifest
313 std::unordered_map<std::string, size_t> m_subManifestSizes;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800314 // The segments of the TorrentFile this manager has
315 std::vector<TorrentFile> m_torrentSegments;
316 // The FileManifests this manager has
317 std::vector<FileManifest> m_fileManifests;
318 // The name of the initial segment of the torrent file for this manager
319 Name m_torrentFileName;
320 // The path to the location on disk of the Data packet for this manager
321 std::string m_dataPath;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700322
323private:
324 shared_ptr<Interest>
325 createInterest(Name name);
326
spirosmastorakis9b68b532016-05-02 21:40:29 -0700327 void
328 sendInterest();
329
330
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700331 // A flag to determine if upon completion we should continue seeding
332 bool m_seedFlag;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700333 // Face used for network communication
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700334 std::shared_ptr<Face> m_face;
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700335 // Stats table where routable prefixes are stored
336 StatsTable m_statsTable;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700337 // Iterator to the routable prefix that we currently use
338 StatsTable::iterator m_stats_table_iter;
339 // Number of retries per routable prefix
340 uint64_t m_retries;
341 // Number of Interests sent since last sorting
342 uint64_t m_sortingCounter;
343 // Keychain instance
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700344 shared_ptr<KeyChain> m_keyChain;
Mickey Sweatt0dc0a1e2016-05-04 11:25:49 -0700345 // A collection for all interests that have been sent for which we have not received a response
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700346 std::unordered_set<ndn::Name> m_pendingInterests;
Mickey Sweatt0dc0a1e2016-05-04 11:25:49 -0700347 // A queue to hold all interests for requested data that we have yet to send
spirosmastorakis9b68b532016-05-02 21:40:29 -0700348 shared_ptr<InterestQueue> m_interestQueue;
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700349 // TODO(spyros) Fix and reintegrate update handler
350 // // Update Handler instance
351 // shared_ptr<UpdateHandler> m_updateHandler;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800352};
353
354inline
spirosmastorakisa46eee42016-04-05 14:24:45 -0700355TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
356 const std::string& dataPath,
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700357 bool seed,
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700358 std::shared_ptr<Face> face)
Mickey Sweatt527b0492016-03-02 11:07:48 -0800359: m_fileStates()
360, m_torrentSegments()
361, m_fileManifests()
362, m_torrentFileName(torrentFileName)
363, m_dataPath(dataPath)
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700364, m_seedFlag(seed)
spirosmastorakisa46eee42016-04-05 14:24:45 -0700365, m_face(face)
366, m_retries(0)
367, m_sortingCounter(0)
368, m_keyChain(new KeyChain())
Mickey Sweatt527b0492016-03-02 11:07:48 -0800369{
spirosmastorakis9b68b532016-05-02 21:40:29 -0700370 m_interestQueue = make_shared<InterestQueue>();
371
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700372 if(face == nullptr) {
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700373 m_face = make_shared<Face>();
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700374 }
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700375
spirosmastorakisa46eee42016-04-05 14:24:45 -0700376 // Hardcoded prefixes for now
377 // TODO(Spyros): Think of something more clever to bootstrap...
378 m_statsTable.insert("/ucla");
379 m_statsTable.insert("/arizona");
380 m_stats_table_iter = m_statsTable.begin();
Mickey Sweatt527b0492016-03-02 11:07:48 -0800381}
382
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700383inline
384void
385TorrentManager::processEvents(const time::milliseconds& timeout)
386{
387 m_face->processEvents(timeout);
388}
389
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700390inline
391bool
392TorrentManager::hasAllTorrentSegments() const
393{
394 return findTorrentFileSegmentToDownload() == nullptr;
395}
396
Mickey Sweatt527b0492016-03-02 11:07:48 -0800397} // end ntorrent
398} // end ndn
399
spirosmastorakisa46eee42016-04-05 14:24:45 -0700400#endif // INCLUDED_TORRENT_FILE_MANAGER_H