blob: 28053f285f4cb3704057ca05b94990333b4b5d04 [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*/
21#ifndef INCLUDED_TORRENT_FILE_MANAGER_H
22#define INCLUDED_TORRENT_FILE_MANAGER_H
23
Mickey Sweatt527b0492016-03-02 11:07:48 -080024#include "file-manifest.hpp"
spirosmastorakisa46eee42016-04-05 14:24:45 -070025#include "stats-table.hpp"
26#include "torrent-file.hpp"
Mickey Sweatt527b0492016-03-02 11:07:48 -080027
Mickey Sweatt527b0492016-03-02 11:07:48 -080028#include <ndn-cxx/data.hpp>
spirosmastorakisa46eee42016-04-05 14:24:45 -070029#include <ndn-cxx/face.hpp>
30#include <ndn-cxx/interest.hpp>
31#include <ndn-cxx/link.hpp>
32#include <ndn-cxx/name.hpp>
33#include <ndn-cxx/security/key-chain.hpp>
Mickey Sweatt527b0492016-03-02 11:07:48 -080034
35#include <boost/filesystem/fstream.hpp>
Mickey Sweatt527b0492016-03-02 11:07:48 -080036
37#include <functional>
38#include <memory>
39#include <string>
40#include <unordered_map>
41#include <vector>
42
43namespace fs = boost::filesystem;
44
45namespace ndn {
46namespace ntorrent {
47
Mickey Sweatt599bfef2016-04-05 19:11:20 -070048class TorrentManager : noncopyable {
Mickey Sweatt527b0492016-03-02 11:07:48 -080049 /**
50 * \class TorrentManager
51 *
52 * \brief A class to manage the interaction with the system in seeding/leaching a torrent
53 */
54 public:
spirosmastorakisa46eee42016-04-05 14:24:45 -070055 typedef std::function<void(const ndn::Name&)> DataReceivedCallback;
56 typedef std::function<void(const std::vector<ndn::Name>&)> ManifestReceivedCallback;
spirosmastorakis50642f82016-04-08 12:11:18 -070057 typedef std::function<void(const std::vector<ndn::Name>&)> TorrentFileReceivedCallback;
spirosmastorakisa46eee42016-04-05 14:24:45 -070058 typedef std::function<void(const ndn::Name&, const std::string&)> FailedCallback;
Mickey Sweatt527b0492016-03-02 11:07:48 -080059
spirosmastorakisa46eee42016-04-05 14:24:45 -070060 /*
61 * \brief Create a new Torrent manager with the specified parameters.
62 * @param torrentFileName The full name of the initial segment of the torrent file
63 * @param dataPath The path to the location on disk to use for the torrent data
64 * @param face Optional face object to be used for data retrieval
65 *
66 * The behavior is undefined unless Initialize() is called before calling any other method on a
67 * TorrentManger object.
68 */
69 TorrentManager(const ndn::Name& torrentFileName,
70 const std::string& dataPath,
71 ndn::Face& face);
72
73 /*
74 * \brief Create a new Torrent manager with the specified parameters.
75 * @param torrentFileName The full name of the initial segment of the torrent file
76 * @param dataPath The path to the location on disk to use for the torrent data
77 *
78 * The behavior is undefined unless Initialize() is called before calling any other method on a
79 * TorrentManger object.
80 */
81 TorrentManager(const ndn::Name& torrentFileName,
82 const std::string& dataPath);
83
Mickey Sweatt527b0492016-03-02 11:07:48 -080084 /*
spirosmastorakisa46eee42016-04-05 14:24:45 -070085 * @brief Initialize the state of this object.
Mickey Sweatt527b0492016-03-02 11:07:48 -080086 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080087 * Read and validate from disk all torrent file segments, file manifests, and data packets for
88 * the torrent file managed by this object initializing all state in this manager respectively.
89 * Also seeds all validated data.
spirosmastorakisa46eee42016-04-05 14:24:45 -070090 */
91 void
92 Initialize();
93
94 /*
95 * @brief Download the torrent file
96 * @param path The path to write the downloaded segments
97 * @return A vector of the file manifest names contained in the torrent file
98 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080099 */
spirosmastorakisa46eee42016-04-05 14:24:45 -0700100 std::vector<Name>
101 downloadTorrentFile(const std::string& path);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800102
spirosmastorakisa46eee42016-04-05 14:24:45 -0700103 /*
104 * @brief Download the torrent file
105 * @param path The path to write the downloaded segments
106 * @param onSuccess Callback to be called if we successfully download all the
107 * segments of the torrent file. It passes the name of the file manifest
108 * to be downloaded to the callback
109 * @param onFailed Callaback to be called if we fail to download a segment of
110 * the torrent file. It passes the name of the torrent file segment that
111 * failed to download and a failure reason to the callback
112 *
113 * This method provides non-blocking downloading of all the torrent file segments
114 *
115 */
116 void
117 downloadTorrentFile(const std::string& path,
spirosmastorakis50642f82016-04-08 12:11:18 -0700118 TorrentFileReceivedCallback onSuccess,
spirosmastorakisa46eee42016-04-05 14:24:45 -0700119 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800120
spirosmastorakisa46eee42016-04-05 14:24:45 -0700121 /*
122 * @brief Download a file manifest
123 * @param manifestName The name of the manifest file to be downloaded
124 * @param path The path to write the downloaded segments
125 * @param onSuccess Callback to be called if we successfully download all the
126 * segments of the file manifest. It passes the names of the data packets
127 * to be downloaded to the callback
128 * @param onFailed Callaback to be called if we fail to download a segment of
129 * the file manifest. It passes the name of the data packet that failed
130 * to download and a failure reason
131 *
132 * This method provides non-blocking downloading of all the file manifest segments
133 *
134 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700135 void
136 download_file_manifest(const Name& manifestName,
137 const std::string& path,
138 ManifestReceivedCallback onSuccess,
139 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800140
spirosmastorakisa46eee42016-04-05 14:24:45 -0700141 /*
142 * @brief Download a data packet
143 * @param packetName The name of the data packet to be downloaded
144 * @param onSuccess Callback to be called if we successfully download the data packet.
145 * It passes the name of the data packet to the callback
146 * @param onFailed Callaback to be called if we fail to download the requested data packet
147 * It passes the name of the data packet to the callback and a failure reason
148 *
149 * This method writes the downloaded data packet to m_dataPath on disk
150 *
151 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700152 void
153 download_data_packet(const Name& packetName,
154 DataReceivedCallback onSuccess,
155 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800156
Mickey Sweatt527b0492016-03-02 11:07:48 -0800157 // Seed the specified 'data' to the network.
spirosmastorakis50642f82016-04-08 12:11:18 -0700158 void
159 seed(const Data& data) const;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800160
161 protected:
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700162 /*
163 * \brief Write @p packet composed of torrent date to disk.
164 * @param packet The data packet to be written to the disk
165 * Write the Data packet to disk, return 'true' if data successfully written to disk 'false'
166 * otherwise. Behavior is undefined unless the corresponding file manifest has already been
167 * downloaded.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700168 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700169 bool
170 writeData(const Data& packet);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700171
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700172 /*
173 * \brief Write the @p segment torrent segment to disk at the specified path.
174 * @param segment The torrent file segment to be written to disk
175 * @param path The path at which to write the torrent file segment
176 * Write the segment to disk, return 'true' if data successfully written to disk 'false'
177 * otherwise. Behavior is undefined unless @segment is a correct segment for the torrent file of
178 * this manager and @p path is the directory used for all segments of this torrent file.
179 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700180 bool
181 writeTorrentSegment(const TorrentFile& segment, const std::string& path);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700182
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700183 /*
184 * \brief Write the @p manifest file manifest to disk at the specified @p path.
185 * @param manifest The file manifest to be written to disk
186 * @param path The path at which to write the file manifest
187 * Write the file manifest to disk, return 'true' if data successfully written to disk 'false'
188 * otherwise. Behavior is undefined unless @manifest is a correct file manifest for a file in the
189 * torrent file of this manager and @p path is the directory used for all file manifests of this
190 * torrent file.
191 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700192 bool
193 writeFileManifest(const FileManifest& manifest, const std::string& path);
Mickey Sweattafda1f12016-04-04 17:15:11 -0700194
spirosmastorakisa46eee42016-04-05 14:24:45 -0700195 /*
196 * \brief Download the segments of the torrent file
197 * @param name The name of the torrent file to be downloaded
198 * @param path The path to write the torrent file on disk
199 * @param manifestNames A vector containing the name of the manifests in the torrent file.
200 * This parameter will be updated every time we receive a torrent
201 * file segment
202 * @param async Blocking (sync) or non-blocking (async) operation
203 * @param onSuccess Optional callback to be called when all the segments of the torrent file
204 * have been downloaded. The default value is an empty callack. A callback
205 * should be specified when async is false
206 * @param onFailed Optional callback to be called when we fail to download a segment of the
207 * torrent file. The default value is an empty callack. A callback should be
208 * specified when async is false
209 *
210 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700211 void
212 downloadTorrentFileSegment(const ndn::Name& name,
213 const std::string& path,
214 std::shared_ptr<std::vector<Name>> manifestNames,
215 bool async,
216 TorrentFileReceivedCallback onSuccess,
217 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800218
spirosmastorakisa46eee42016-04-05 14:24:45 -0700219 /*
220 * \brief Download the segments of a file manifest
221 * @param manifestName The name of the file manifest to be downloaded
222 * @param path The path to write the file manifest on disk
223 * @param packetNames A vector containing the name of the data packets in the file manifest
224 * @param onSuccess Callback to be called when all the segments of the file manifest have been
225 * downloaded
226 * @param onFailed Callback to be called when we fail to download a file manifest segment
227 *
228 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700229 void
230 downloadFileManifestSegment(const Name& manifestName,
231 const std::string& path,
232 std::shared_ptr<std::vector<Name>> packetNames,
233 ManifestReceivedCallback onSuccess,
234 FailedCallback onFailed);
spirosmastorakisa46eee42016-04-05 14:24:45 -0700235
236 enum {
237 // Number of times to retry if a routable prefix fails to retrieve data
238 MAX_NUM_OF_RETRIES = 5,
239 // Number of Interests to be sent before sorting the stats table
240 SORTING_INTERVAL = 100
241 };
Mickey Sweatt527b0492016-03-02 11:07:48 -0800242
243 // A map from each fileManifest to corresponding file stream on disk and a bitmap of which Data
244 // packets this manager currently has
245 mutable std::unordered_map<Name,
246 std::pair<std::shared_ptr<fs::fstream>,
247 std::vector<bool>>> m_fileStates;
248 // The segments of the TorrentFile this manager has
249 std::vector<TorrentFile> m_torrentSegments;
250 // The FileManifests this manager has
251 std::vector<FileManifest> m_fileManifests;
252 // The name of the initial segment of the torrent file for this manager
253 Name m_torrentFileName;
254 // The path to the location on disk of the Data packet for this manager
255 std::string m_dataPath;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700256
spirosmastorakis50642f82016-04-08 12:11:18 -0700257protected:
258 /*
259 * \brief Find the torrent file segment that we should download
260 * (either we have nothing or we have them all)
261 * @return A shared_ptr to the name of the segment to download or
262 * nullptr if we have all the segments
263 *
264 */
265 shared_ptr<Name>
266 findTorrentFileSegmentToDownload();
267
268 /*
269 * \brief Given a file manifest segment name, find the next file manifest segment
270 * that we should download
271 * @param manifestName The name of the file manifest segment that we want to download
272 * @return A shared_ptr to the name of the segment to download or
273 * nullptr if we have all the segments
274 *
275 */
276 shared_ptr<Name>
277 findManifestSegmentToDownload(const Name& manifestName);
278
279 /*
280 * \brief Given a data packet name, find whether we have already downloaded this packet
281 * @param dataName The name of the data packet to download
282 * @return True if we have already downloaded this packet, false otherwise
283 *
284 */
285 bool
286 dataAlreadyDownloaded(const Name& dataName);
287
288 /*
289 * \brief Find the segments of all the file manifests that we are missing
290 * @param manifestNames The name of the manifest file segments to download (currently missing)
291 * This parameter is used as an output vector of names
292 */
293 void
294 findFileManifestsToDownload(std::vector<Name>& manifestNames);
295
296 /*
297 * \brief Find the names of the data packets of a file manifest that we are currently missing
298 * @param manifestName The name of the manifest
299 * @param packetNames The name of the data packets to be downloaded
300 * (used as an output vector of names)
301 *
302 * No matter what segment of a manifest file the manifestName parameter might refer to, the
303 * missing data packets starting from the first segment of this manifest file would be returned
304 *
305 */
306 void
307 findDataPacketsToDownload(const Name& manifestName, std::vector<Name>& packetNames);
308
309 /*
310 * \brief Find all the data packets that we are currently missing
311 * @param packetNames The name of the data packets to be downloaded
312 * (used as an output vector of names)
313 *
314 */
315 void
316 findAllMissingDataPackets(std::vector<Name>& packetNames);
317
spirosmastorakisa46eee42016-04-05 14:24:45 -0700318private:
319 shared_ptr<Interest>
320 createInterest(Name name);
321
322 // Stats table where routable prefixes are stored
323 StatsTable m_statsTable;
324 // Face used for network communication
325 Face& m_face;
326 // Iterator to the routable prefix that we currently use
327 StatsTable::iterator m_stats_table_iter;
328 // Number of retries per routable prefix
329 uint64_t m_retries;
330 // Number of Interests sent since last sorting
331 uint64_t m_sortingCounter;
332 // Keychain instance
333 unique_ptr<KeyChain> m_keyChain;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800334};
335
336inline
spirosmastorakisa46eee42016-04-05 14:24:45 -0700337TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
338 const std::string& dataPath,
339 ndn::Face& face)
Mickey Sweatt527b0492016-03-02 11:07:48 -0800340: m_fileStates()
341, m_torrentSegments()
342, m_fileManifests()
343, m_torrentFileName(torrentFileName)
344, m_dataPath(dataPath)
spirosmastorakisa46eee42016-04-05 14:24:45 -0700345, m_face(face)
346, m_retries(0)
347, m_sortingCounter(0)
348, m_keyChain(new KeyChain())
Mickey Sweatt527b0492016-03-02 11:07:48 -0800349{
spirosmastorakisa46eee42016-04-05 14:24:45 -0700350 // Hardcoded prefixes for now
351 // TODO(Spyros): Think of something more clever to bootstrap...
352 m_statsTable.insert("/ucla");
353 m_statsTable.insert("/arizona");
354 m_stats_table_iter = m_statsTable.begin();
355}
356
357inline
358TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
359 const std::string& dataPath)
360: m_fileStates()
361, m_torrentSegments()
362, m_fileManifests()
363, m_torrentFileName(torrentFileName)
364, m_dataPath(dataPath)
365, m_face(*(new ndn::Face()))
366, m_retries(0)
367, m_sortingCounter(0)
368, m_keyChain(new KeyChain())
369{
370 // Hardcoded prefixes for now
371 // TODO(Spyros): Think of something more clever to bootstrap...
372 m_statsTable.insert("/ucla");
373 m_statsTable.insert("/arizona");
374 m_stats_table_iter = m_statsTable.begin();
Mickey Sweatt527b0492016-03-02 11:07:48 -0800375}
376
377} // end ntorrent
378} // end ndn
379
spirosmastorakisa46eee42016-04-05 14:24:45 -0700380#endif // INCLUDED_TORRENT_FILE_MANAGER_H