blob: a96f21bc26294109dc2a4f0860150002e5ddc68f [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;
57 typedef std::function<void(const ndn::Name&, const std::string&)> FailedCallback;
Mickey Sweatt527b0492016-03-02 11:07:48 -080058
spirosmastorakisa46eee42016-04-05 14:24:45 -070059 /*
60 * \brief Create a new Torrent manager with the specified parameters.
61 * @param torrentFileName The full name of the initial segment of the torrent file
62 * @param dataPath The path to the location on disk to use for the torrent data
63 * @param face Optional face object to be used for data retrieval
64 *
65 * The behavior is undefined unless Initialize() is called before calling any other method on a
66 * TorrentManger object.
67 */
68 TorrentManager(const ndn::Name& torrentFileName,
69 const std::string& dataPath,
70 ndn::Face& face);
71
72 /*
73 * \brief Create a new Torrent manager with the specified parameters.
74 * @param torrentFileName The full name of the initial segment of the torrent file
75 * @param dataPath The path to the location on disk to use for the torrent data
76 *
77 * The behavior is undefined unless Initialize() is called before calling any other method on a
78 * TorrentManger object.
79 */
80 TorrentManager(const ndn::Name& torrentFileName,
81 const std::string& dataPath);
82
Mickey Sweatt527b0492016-03-02 11:07:48 -080083 /*
spirosmastorakisa46eee42016-04-05 14:24:45 -070084 * @brief Initialize the state of this object.
Mickey Sweatt527b0492016-03-02 11:07:48 -080085 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080086 * Read and validate from disk all torrent file segments, file manifests, and data packets for
87 * the torrent file managed by this object initializing all state in this manager respectively.
88 * Also seeds all validated data.
spirosmastorakisa46eee42016-04-05 14:24:45 -070089 */
90 void
91 Initialize();
92
93 /*
94 * @brief Download the torrent file
95 * @param path The path to write the downloaded segments
96 * @return A vector of the file manifest names contained in the torrent file
97 *
Mickey Sweatt527b0492016-03-02 11:07:48 -080098 */
spirosmastorakisa46eee42016-04-05 14:24:45 -070099 std::vector<Name>
100 downloadTorrentFile(const std::string& path);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800101
spirosmastorakisa46eee42016-04-05 14:24:45 -0700102 /*
103 * @brief Download the torrent file
104 * @param path The path to write the downloaded segments
105 * @param onSuccess Callback to be called if we successfully download all the
106 * segments of the torrent file. It passes the name of the file manifest
107 * to be downloaded to the callback
108 * @param onFailed Callaback to be called if we fail to download a segment of
109 * the torrent file. It passes the name of the torrent file segment that
110 * failed to download and a failure reason to the callback
111 *
112 * This method provides non-blocking downloading of all the torrent file segments
113 *
114 */
115 void
116 downloadTorrentFile(const std::string& path,
117 DataReceivedCallback onSuccess,
118 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800119
spirosmastorakisa46eee42016-04-05 14:24:45 -0700120 /*
121 * @brief Download a file manifest
122 * @param manifestName The name of the manifest file to be downloaded
123 * @param path The path to write the downloaded segments
124 * @param onSuccess Callback to be called if we successfully download all the
125 * segments of the file manifest. It passes the names of the data packets
126 * to be downloaded to the callback
127 * @param onFailed Callaback to be called if we fail to download a segment of
128 * the file manifest. It passes the name of the data packet that failed
129 * to download and a failure reason
130 *
131 * This method provides non-blocking downloading of all the file manifest segments
132 *
133 */
Mickey Sweatt527b0492016-03-02 11:07:48 -0800134 void download_file_manifest(const Name& manifestName,
135 const std::string& path,
136 ManifestReceivedCallback onSuccess,
spirosmastorakisa46eee42016-04-05 14:24:45 -0700137 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800138
spirosmastorakisa46eee42016-04-05 14:24:45 -0700139 /*
140 * @brief Download a data packet
141 * @param packetName The name of the data packet to be downloaded
142 * @param onSuccess Callback to be called if we successfully download the data packet.
143 * It passes the name of the data packet to the callback
144 * @param onFailed Callaback to be called if we fail to download the requested data packet
145 * It passes the name of the data packet to the callback and a failure reason
146 *
147 * This method writes the downloaded data packet to m_dataPath on disk
148 *
149 */
Mickey Sweatt527b0492016-03-02 11:07:48 -0800150 void download_data_packet(const Name& packetName,
151 DataReceivedCallback onSuccess,
spirosmastorakisa46eee42016-04-05 14:24:45 -0700152 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800153
Mickey Sweatt527b0492016-03-02 11:07:48 -0800154 // Seed the specified 'data' to the network.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700155 void seed(const Data& data) const;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800156
157 protected:
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700158 /*
159 * \brief Write @p packet composed of torrent date to disk.
160 * @param packet The data packet to be written to the disk
161 * Write the Data packet to disk, return 'true' if data successfully written to disk 'false'
162 * otherwise. Behavior is undefined unless the corresponding file manifest has already been
163 * downloaded.
spirosmastorakisa46eee42016-04-05 14:24:45 -0700164 */
165 bool writeData(const Data& packet);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700166
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700167 /*
168 * \brief Write the @p segment torrent segment to disk at the specified path.
169 * @param segment The torrent file segment to be written to disk
170 * @param path The path at which to write the torrent file segment
171 * Write the segment to disk, return 'true' if data successfully written to disk 'false'
172 * otherwise. Behavior is undefined unless @segment is a correct segment for the torrent file of
173 * this manager and @p path is the directory used for all segments of this torrent file.
174 */
spirosmastorakisa46eee42016-04-05 14:24:45 -0700175 bool writeTorrentSegment(const TorrentFile& segment, const std::string& path);
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700176
Mickey Sweatt599bfef2016-04-05 19:11:20 -0700177 /*
178 * \brief Write the @p manifest file manifest to disk at the specified @p path.
179 * @param manifest The file manifest to be written to disk
180 * @param path The path at which to write the file manifest
181 * Write the file manifest to disk, return 'true' if data successfully written to disk 'false'
182 * otherwise. Behavior is undefined unless @manifest is a correct file manifest for a file in the
183 * torrent file of this manager and @p path is the directory used for all file manifests of this
184 * torrent file.
185 */
spirosmastorakisa46eee42016-04-05 14:24:45 -0700186 bool writeFileManifest(const FileManifest& manifest, const std::string& path);
Mickey Sweattafda1f12016-04-04 17:15:11 -0700187
spirosmastorakisa46eee42016-04-05 14:24:45 -0700188 /*
189 * \brief Download the segments of the torrent file
190 * @param name The name of the torrent file to be downloaded
191 * @param path The path to write the torrent file on disk
192 * @param manifestNames A vector containing the name of the manifests in the torrent file.
193 * This parameter will be updated every time we receive a torrent
194 * file segment
195 * @param async Blocking (sync) or non-blocking (async) operation
196 * @param onSuccess Optional callback to be called when all the segments of the torrent file
197 * have been downloaded. The default value is an empty callack. A callback
198 * should be specified when async is false
199 * @param onFailed Optional callback to be called when we fail to download a segment of the
200 * torrent file. The default value is an empty callack. A callback should be
201 * specified when async is false
202 *
203 */
204 void downloadTorrentFileSegment(const ndn::Name& name,
205 const std::string& path,
206 std::shared_ptr<std::vector<Name>> manifestNames,
207 bool async,
208 DataReceivedCallback onSuccess,
209 FailedCallback onFailed);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800210
spirosmastorakisa46eee42016-04-05 14:24:45 -0700211 /*
212 * \brief Download the segments of a file manifest
213 * @param manifestName The name of the file manifest to be downloaded
214 * @param path The path to write the file manifest on disk
215 * @param packetNames A vector containing the name of the data packets in the file manifest
216 * @param onSuccess Callback to be called when all the segments of the file manifest have been
217 * downloaded
218 * @param onFailed Callback to be called when we fail to download a file manifest segment
219 *
220 */
221 void downloadFileManifestSegment(const Name& manifestName,
222 const std::string& path,
223 std::shared_ptr<std::vector<Name>> packetNames,
224 TorrentManager::ManifestReceivedCallback onSuccess,
225 TorrentManager::FailedCallback onFailed);
226
227 enum {
228 // Number of times to retry if a routable prefix fails to retrieve data
229 MAX_NUM_OF_RETRIES = 5,
230 // Number of Interests to be sent before sorting the stats table
231 SORTING_INTERVAL = 100
232 };
Mickey Sweatt527b0492016-03-02 11:07:48 -0800233
234 // A map from each fileManifest to corresponding file stream on disk and a bitmap of which Data
235 // packets this manager currently has
236 mutable std::unordered_map<Name,
237 std::pair<std::shared_ptr<fs::fstream>,
238 std::vector<bool>>> m_fileStates;
239 // The segments of the TorrentFile this manager has
240 std::vector<TorrentFile> m_torrentSegments;
241 // The FileManifests this manager has
242 std::vector<FileManifest> m_fileManifests;
243 // The name of the initial segment of the torrent file for this manager
244 Name m_torrentFileName;
245 // The path to the location on disk of the Data packet for this manager
246 std::string m_dataPath;
spirosmastorakisa46eee42016-04-05 14:24:45 -0700247
248private:
249 shared_ptr<Interest>
250 createInterest(Name name);
251
252 // Stats table where routable prefixes are stored
253 StatsTable m_statsTable;
254 // Face used for network communication
255 Face& m_face;
256 // Iterator to the routable prefix that we currently use
257 StatsTable::iterator m_stats_table_iter;
258 // Number of retries per routable prefix
259 uint64_t m_retries;
260 // Number of Interests sent since last sorting
261 uint64_t m_sortingCounter;
262 // Keychain instance
263 unique_ptr<KeyChain> m_keyChain;
Mickey Sweatt527b0492016-03-02 11:07:48 -0800264};
265
266inline
spirosmastorakisa46eee42016-04-05 14:24:45 -0700267TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
268 const std::string& dataPath,
269 ndn::Face& face)
Mickey Sweatt527b0492016-03-02 11:07:48 -0800270: m_fileStates()
271, m_torrentSegments()
272, m_fileManifests()
273, m_torrentFileName(torrentFileName)
274, m_dataPath(dataPath)
spirosmastorakisa46eee42016-04-05 14:24:45 -0700275, m_face(face)
276, m_retries(0)
277, m_sortingCounter(0)
278, m_keyChain(new KeyChain())
Mickey Sweatt527b0492016-03-02 11:07:48 -0800279{
spirosmastorakisa46eee42016-04-05 14:24:45 -0700280 // Hardcoded prefixes for now
281 // TODO(Spyros): Think of something more clever to bootstrap...
282 m_statsTable.insert("/ucla");
283 m_statsTable.insert("/arizona");
284 m_stats_table_iter = m_statsTable.begin();
285}
286
287inline
288TorrentManager::TorrentManager(const ndn::Name& torrentFileName,
289 const std::string& dataPath)
290: m_fileStates()
291, m_torrentSegments()
292, m_fileManifests()
293, m_torrentFileName(torrentFileName)
294, m_dataPath(dataPath)
295, m_face(*(new ndn::Face()))
296, m_retries(0)
297, m_sortingCounter(0)
298, m_keyChain(new KeyChain())
299{
300 // Hardcoded prefixes for now
301 // TODO(Spyros): Think of something more clever to bootstrap...
302 m_statsTable.insert("/ucla");
303 m_statsTable.insert("/arizona");
304 m_stats_table_iter = m_statsTable.begin();
Mickey Sweatt527b0492016-03-02 11:07:48 -0800305}
306
307} // end ntorrent
308} // end ndn
309
spirosmastorakisa46eee42016-04-05 14:24:45 -0700310#endif // INCLUDED_TORRENT_FILE_MANAGER_H