blob: a3197d1d461d73df7646c474256f023fe18b4c39 [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 "torrent-file.hpp"
spirosmastorakis4ff8c872016-04-14 09:51:38 -070026#include "update-handler.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 */
Mickey Sweatte908a5c2016-04-08 14:10:45 -070069 TorrentManager(const ndn::Name& torrentFileName,
70 const std::string& dataPath,
71 std::shared_ptr<Face> face = nullptr);
spirosmastorakisa46eee42016-04-05 14:24:45 -070072
Mickey Sweatt527b0492016-03-02 11:07:48 -080073 /*
spirosmastorakisa46eee42016-04-05 14:24:45 -070074 * @brief Initialize the state of this object.
Mickey Sweatt527b0492016-03-02 11:07:48 -080075 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080076 * Read and validate from disk all torrent file segments, file manifests, and data packets for
77 * the torrent file managed by this object initializing all state in this manager respectively.
78 * Also seeds all validated data.
spirosmastorakisa46eee42016-04-05 14:24:45 -070079 */
80 void
81 Initialize();
82
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070083 /**
84 * brief Return 'true' if all segments of the torrent file downloaded, 'false' otherwise.
85 */
86 bool
87 hasAllTorrentSegments() const;
88
spirosmastorakisa46eee42016-04-05 14:24:45 -070089 /*
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070090 * \brief Given a data packet name, find whether we have already downloaded this packet
91 * @param dataName The name of the data packet to download
92 * @return True if we have already downloaded this packet, false otherwise
spirosmastorakisa46eee42016-04-05 14:24:45 -070093 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080094 */
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070095 bool
96 hasDataPacket(const Name& dataName) const;
97
98 /*
99 * \brief Find the torrent file segment that we should download
100 * (either we have nothing or we have them all)
101 * @return A shared_ptr to the name of the segment to download or
102 * nullptr if we have all the segments
103 *
104 */
105 shared_ptr<Name>
106 findTorrentFileSegmentToDownload() const;
107
108 /*
109 * \brief Given a file manifest segment name, find the next file manifest segment
110 * that we should download
111 * @param manifestName The name of the file manifest segment that we want to download
112 * @return A shared_ptr to the name of the segment to download or
113 * nullptr if we have all the segments
114 *
115 */
116 shared_ptr<Name>
117 findManifestSegmentToDownload(const Name& manifestName) const;
118
119 /*
120 * \brief Find the segments of all the file manifests that we are missing
121 * @param manifestNames The name of the manifest file segments to download (currently missing)
122 * This parameter is used as an output vector of names
123 */
124 void
125 findFileManifestsToDownload(std::vector<Name>& manifestNames) const;
126
127 /*
128 * \brief Find the names of the data packets of a file manifest that we are currently missing
129 * @param manifestName The name of the manifest
130 * @param packetNames The name of the data packets to be downloaded
131 * (used as an output vector of names)
132 *
133 * No matter what segment of a manifest file the manifestName parameter might refer to, the
134 * missing data packets starting from the first segment of this manifest file would be returned
135 *
136 */
137 void
138 findDataPacketsToDownload(const Name& manifestName, std::vector<Name>& packetNames) const;
139
140 /*
141 * \brief Find all the data packets that we are currently missing
142 * @param packetNames The name of the data packets to be downloaded
143 * (used as an output vector of names)
144 *
145 */
146 void
147 findAllMissingDataPackets(std::vector<Name>& packetNames) const;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800148
spirosmastorakisa46eee42016-04-05 14:24:45 -0700149 /*
150 * @brief Download the torrent file
151 * @param path The path to write the downloaded segments
152 * @param onSuccess Callback to be called if we successfully download all the
153 * segments of the torrent file. It passes the name of the file manifest
154 * to be downloaded to the callback
155 * @param onFailed Callaback to be called if we fail to download a segment of
156 * the torrent file. It passes the name of the torrent file segment that
157 * failed to download and a failure reason to the callback
158 *
159 * This method provides non-blocking downloading of all the torrent file segments
spirosmastorakisa46eee42016-04-05 14:24:45 -0700160 */
161 void
162 downloadTorrentFile(const std::string& path,
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700163 TorrentFileReceivedCallback onSuccess = {},
164 FailedCallback onFailed = {});
Mickey Sweatt527b0492016-03-02 11:07:48 -0800165
spirosmastorakisa46eee42016-04-05 14:24:45 -0700166 /*
167 * @brief Download a file manifest
168 * @param manifestName The name of the manifest file to be downloaded
169 * @param path The path to write the downloaded segments
170 * @param onSuccess Callback to be called if we successfully download all the
171 * segments of the file manifest. It passes the names of the data packets
172 * to be downloaded to the callback
173 * @param onFailed Callaback to be called if we fail to download a segment of
174 * the file manifest. It passes the name of the data packet that failed
175 * to download and a failure reason
176 *
177 * This method provides non-blocking downloading of all the file manifest segments
178 *
179 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700180 void
181 download_file_manifest(const Name& manifestName,
182 const std::string& path,
183 ManifestReceivedCallback onSuccess,
184 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800185
spirosmastorakisa46eee42016-04-05 14:24:45 -0700186 /*
187 * @brief Download a data packet
188 * @param packetName The name of the data packet to be downloaded
189 * @param onSuccess Callback to be called if we successfully download the data packet.
190 * It passes the name of the data packet to the callback
191 * @param onFailed Callaback to be called if we fail to download the requested data packet
192 * It passes the name of the data packet to the callback and a failure reason
193 *
194 * This method writes the downloaded data packet to m_dataPath on disk
195 *
196 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700197 void
198 download_data_packet(const Name& packetName,
199 DataReceivedCallback onSuccess,
200 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800201
Mickey Sweatt527b0492016-03-02 11:07:48 -0800202 // Seed the specified 'data' to the network.
spirosmastorakis50642f82016-04-08 12:11:18 -0700203 void
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700204 seed(const Data& data);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800205
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700206 /**
207 * @brief Process any data to receive or call timeout callbacks and update prefix list (if needed)
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700208 * By default this blocks until all operations are complete.
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700209 */
210 void
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700211 processEvents(const time::milliseconds& timeout = time::milliseconds(0));
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700212
Mickey Sweatt527b0492016-03-02 11:07:48 -0800213 protected:
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700214 /**
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700215 * \brief Write @p packet composed of torrent date to disk.
216 * @param packet The data packet to be written to the disk
217 * Write the Data packet to disk, return 'true' if data successfully written to disk 'false'
218 * otherwise. Behavior is undefined unless the corresponding file manifest has already been
219 * downloaded.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700220 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700221 bool
222 writeData(const Data& packet);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700223
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700224 /*
225 * \brief Write the @p segment torrent segment to disk at the specified path.
226 * @param segment The torrent file segment to be written to disk
227 * @param path The path at which to write the torrent file segment
228 * Write the segment to disk, return 'true' if data successfully written to disk 'false'
229 * otherwise. Behavior is undefined unless @segment is a correct segment for the torrent file of
230 * this manager and @p path is the directory used for all segments of this torrent file.
231 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700232 bool
233 writeTorrentSegment(const TorrentFile& segment, const std::string& path);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700234
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700235 /*
236 * \brief Write the @p manifest file manifest to disk at the specified @p path.
237 * @param manifest The file manifest to be written to disk
238 * @param path The path at which to write the file manifest
239 * Write the file manifest to disk, return 'true' if data successfully written to disk 'false'
240 * otherwise. Behavior is undefined unless @manifest is a correct file manifest for a file in the
241 * torrent file of this manager and @p path is the directory used for all file manifests of this
242 * torrent file.
243 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700244 bool
245 writeFileManifest(const FileManifest& manifest, const std::string& path);
Mickey Sweattafda1f12016-04-04 17:15:11 -0700246
spirosmastorakisa46eee42016-04-05 14:24:45 -0700247 /*
248 * \brief Download the segments of the torrent file
249 * @param name The name of the torrent file to be downloaded
250 * @param path The path to write the torrent file on disk
spirosmastorakisa46eee42016-04-05 14:24:45 -0700251 * @param onSuccess Optional callback to be called when all the segments of the torrent file
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700252 * have been downloaded. The default value is an empty callback.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700253 * @param onFailed Optional callback to be called when we fail to download a segment of the
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700254 * torrent file. The default value is an empty callback.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700255 *
256 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700257 void
258 downloadTorrentFileSegment(const ndn::Name& name,
259 const std::string& path,
spirosmastorakis50642f82016-04-08 12:11:18 -0700260 TorrentFileReceivedCallback onSuccess,
261 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800262
spirosmastorakisa46eee42016-04-05 14:24:45 -0700263 /*
264 * \brief Download the segments of a file manifest
265 * @param manifestName The name of the file manifest to be downloaded
266 * @param path The path to write the file manifest on disk
267 * @param packetNames A vector containing the name of the data packets in the file manifest
268 * @param onSuccess Callback to be called when all the segments of the file manifest have been
269 * downloaded
270 * @param onFailed Callback to be called when we fail to download a file manifest segment
271 *
272 */
spirosmastorakis50642f82016-04-08 12:11:18 -0700273 void
274 downloadFileManifestSegment(const Name& manifestName,
275 const std::string& path,
276 std::shared_ptr<std::vector<Name>> packetNames,
277 ManifestReceivedCallback onSuccess,
278 FailedCallback onFailed);
spirosmastorakisa46eee42016-04-05 14:24:45 -0700279
280 enum {
281 // Number of times to retry if a routable prefix fails to retrieve data
282 MAX_NUM_OF_RETRIES = 5,
283 // Number of Interests to be sent before sorting the stats table
284 SORTING_INTERVAL = 100
285 };
Mickey Sweatt527b0492016-03-02 11:07:48 -0800286
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700287 void onDataReceived(const Data& data);
288
289 void
290 onInterestReceived(const InterestFilter& filter, const Interest& interest);
291
292 void
293 onRegisterFailed(const Name& prefix, const std::string& reason);
294
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700295protected:
Mickey Sweatt527b0492016-03-02 11:07:48 -0800296 // A map from each fileManifest to corresponding file stream on disk and a bitmap of which Data
297 // packets this manager currently has
298 mutable std::unordered_map<Name,
299 std::pair<std::shared_ptr<fs::fstream>,
300 std::vector<bool>>> m_fileStates;
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700301 // A map for each initial manifest to the size for the sub-manifest
302 std::unordered_map<std::string, size_t> m_subManifestSizes;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800303 // The segments of the TorrentFile this manager has
304 std::vector<TorrentFile> m_torrentSegments;
305 // The FileManifests this manager has
306 std::vector<FileManifest> m_fileManifests;
307 // The name of the initial segment of the torrent file for this manager
308 Name m_torrentFileName;
309 // The path to the location on disk of the Data packet for this manager
310 std::string m_dataPath;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700311
312private:
313 shared_ptr<Interest>
314 createInterest(Name name);
315
316 // Stats table where routable prefixes are stored
317 StatsTable m_statsTable;
318 // Face used for network communication
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700319 std::shared_ptr<Face> m_face;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700320 // Iterator to the routable prefix that we currently use
321 StatsTable::iterator m_stats_table_iter;
322 // Number of retries per routable prefix
323 uint64_t m_retries;
324 // Number of Interests sent since last sorting
325 uint64_t m_sortingCounter;
326 // Keychain instance
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700327 shared_ptr<KeyChain> m_keyChain;
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700328 // TODO(spyros) Fix and reintegrate update handler
329 // // Update Handler instance
330 // shared_ptr<UpdateHandler> m_updateHandler;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800331};
332
333inline
spirosmastorakisa46eee42016-04-05 14:24:45 -0700334TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
335 const std::string& dataPath,
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700336 std::shared_ptr<Face> face)
Mickey Sweatt527b0492016-03-02 11:07:48 -0800337: m_fileStates()
338, m_torrentSegments()
339, m_fileManifests()
340, m_torrentFileName(torrentFileName)
341, m_dataPath(dataPath)
spirosmastorakisa46eee42016-04-05 14:24:45 -0700342, m_face(face)
343, m_retries(0)
344, m_sortingCounter(0)
345, m_keyChain(new KeyChain())
Mickey Sweatt527b0492016-03-02 11:07:48 -0800346{
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700347 if(face == nullptr) {
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700348 m_face = make_shared<Face>();
Mickey Sweatte908a5c2016-04-08 14:10:45 -0700349 }
spirosmastorakis4ff8c872016-04-14 09:51:38 -0700350
spirosmastorakisa46eee42016-04-05 14:24:45 -0700351 // Hardcoded prefixes for now
352 // TODO(Spyros): Think of something more clever to bootstrap...
353 m_statsTable.insert("/ucla");
354 m_statsTable.insert("/arizona");
355 m_stats_table_iter = m_statsTable.begin();
Mickey Sweatt527b0492016-03-02 11:07:48 -0800356}
357
Mickey Sweattb7ee19c2016-04-21 12:18:15 -0700358inline
359void
360TorrentManager::processEvents(const time::milliseconds& timeout)
361{
362 m_face->processEvents(timeout);
363}
364
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700365inline
366bool
367TorrentManager::hasAllTorrentSegments() const
368{
369 return findTorrentFileSegmentToDownload() == nullptr;
370}
371
Mickey Sweatt527b0492016-03-02 11:07:48 -0800372} // end ntorrent
373} // end ndn
374
spirosmastorakisa46eee42016-04-05 14:24:45 -0700375#endif // INCLUDED_TORRENT_FILE_MANAGER_H