1 /*
2     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
3     SPDX-FileCopyrightText: 2005 Ivan Vasic <ivasic@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 #ifndef BTTORRENTCONTROL_H
8 #define BTTORRENTCONTROL_H
9 
10 #include <QDateTime>
11 #include <QObject>
12 #include <QTimer>
13 #include <QUrl>
14 
15 #include "globals.h"
16 #include "torrent.h"
17 #include <interfaces/torrentinterface.h>
18 #include <interfaces/trackerslist.h>
19 #include <ktorrent_export.h>
20 #include <util/timer.h>
21 
22 class QStringList;
23 class QString;
24 class KJob;
25 
26 namespace bt
27 {
28 class StatsFile;
29 class Choker;
30 class PeerSourceManager;
31 class ChunkManager;
32 class PeerManager;
33 class Downloader;
34 class Uploader;
35 class Peer;
36 class BitSet;
37 class QueueManagerInterface;
38 class TimeEstimator;
39 class WaitJob;
40 class MonitorInterface;
41 class ChunkSelectorFactoryInterface;
42 class CacheFactory;
43 class JobQueue;
44 class DataCheckerJob;
45 
46 /**
47  * @author Joris Guisson
48  * @brief Controls just about everything
49  *
50  * This is the interface which any user gets to deal with.
51  * This class controls the uploading, downloading, choking,
52  * updating the tracker and chunk management.
53  */
54 class KTORRENT_EXPORT TorrentControl : public TorrentInterface, public FilePriorityListener
55 {
56     Q_OBJECT
57 public:
58     TorrentControl();
59     ~TorrentControl() override;
60 
61     /// Get the Torrent.
getTorrent()62     const Torrent &getTorrent() const
63     {
64         return *tor;
65     }
66 
67     /**
68      * Initialize the TorrentControl.
69      * @param qman The QueueManager
70      * @param data The data of the torrent
71      * @param tmpdir The directory to store temporary data
72      * @param datadir The directory to store the actual file(s)
73      *      (only used the first time we load a torrent)
74      * @throw Error when something goes wrong
75      */
76     void init(QueueManagerInterface *qman, const QByteArray &data, const QString &tmpdir, const QString &datadir);
77 
78     /// Tell the TorrentControl obj to preallocate diskspace in the next update
setPreallocateDiskSpace(bool pa)79     void setPreallocateDiskSpace(bool pa)
80     {
81         prealloc = pa;
82     }
83 
84     /// Test if the torrent has existing files, only works the first time a torrent is loaded
85     bool hasExistingFiles() const;
86 
87     const BitSet &downloadedChunksBitSet() const override;
88     const BitSet &availableChunksBitSet() const override;
89     const BitSet &excludedChunksBitSet() const override;
90     const BitSet &onlySeedChunksBitSet() const override;
91     bool changeTorDir(const QString &new_dir) override;
92     bool changeOutputDir(const QString &new_dir, int flags) override;
93     void rollback() override;
94     void setDisplayName(const QString &n) override;
95     TrackersList *getTrackersList() override;
96     const TrackersList *getTrackersList() const override;
getDataDir()97     QString getDataDir() const override
98     {
99         return outputdir;
100     }
getTorDir()101     QString getTorDir() const override
102     {
103         return tordir;
104     }
105     void setMonitor(MonitorInterface *tmo) override;
106     Uint32 getRunningTimeDL() const override;
107     Uint32 getRunningTimeUL() const override;
108     Uint32 getNumFiles() const override;
109     TorrentFileInterface &getTorrentFile(Uint32 index) override;
110     const TorrentFileInterface &getTorrentFile(Uint32 index) const override;
111     bool moveTorrentFiles(const QMap<TorrentFileInterface *, QString> &files) override;
112     void recreateMissingFiles() override;
113     void dndMissingFiles() override;
114     TorrentFileStream::Ptr createTorrentFileStream(bt::Uint32 index, bool streaming_mode, QObject *parent) override;
115     void addPeerSource(PeerSource *ps) override;
116     void removePeerSource(PeerSource *ps) override;
117     const QTextCodec *getTextCodec() const override;
118     void changeTextCodec(QTextCodec *tc) override;
119     Uint32 getNumWebSeeds() const override;
120     const WebSeedInterface *getWebSeed(Uint32 i) const override;
121     WebSeedInterface *getWebSeed(Uint32 i) override;
122     bool addWebSeed(const QUrl &url) override;
123     bool removeWebSeed(const QUrl &url) override;
124     bool readyForPreview() const override;
125     bool isMultimedia() const override;
126     void markExistingFilesAsDownloaded() override;
getPriority()127     int getPriority() const override
128     {
129         return istats.priority;
130     }
131     void setPriority(int p) override;
132     bool overMaxRatio() override;
133     void setMaxShareRatio(float ratio) override;
getMaxShareRatio()134     float getMaxShareRatio() const override
135     {
136         return stats.max_share_ratio;
137     }
138     bool overMaxSeedTime() override;
139     void setMaxSeedTime(float hours) override;
getMaxSeedTime()140     float getMaxSeedTime() const override
141     {
142         return stats.max_seed_time;
143     }
144     void setAllowedToStart(bool on) override;
145     void setQueued(bool queued) override;
146     void setChunkSelector(ChunkSelectorInterface *csel) override;
147     void networkUp() override;
148     bool announceAllowed() override;
149     Job *startDataCheck(bool auto_import, bt::Uint32 from, bt::Uint32 to) override;
150     bool hasMissingFiles(QStringList &sl) override;
151     bool isStorageMounted(QStringList &missing) override;
152     Uint32 getNumDHTNodes() const override;
153     const DHTNode &getDHTNode(Uint32 i) const override;
154     void deleteDataFiles() override;
155     const bt::PeerID &getOwnPeerID() const override;
156     QString getComments() const override;
getJobQueue()157     const JobQueue *getJobQueue() const override
158     {
159         return job_queue;
160     }
161     bool isFeatureEnabled(TorrentFeature tf) override;
162     void setFeatureEnabled(TorrentFeature tf, bool on) override;
163     bool checkDiskSpace(bool emit_sig = true) override;
164     void setTrafficLimits(Uint32 up, Uint32 down) override;
165     void getTrafficLimits(Uint32 &up, Uint32 &down) override;
166     void setAssuredSpeeds(Uint32 up, Uint32 down) override;
167     void getAssuredSpeeds(Uint32 &up, Uint32 &down) override;
168     const SHA1Hash &getInfoHash() const override;
169     void setUserModifiedFileName(const QString &n) override;
170     int getETA() override;
setMoveWhenCompletedDir(const QString & dir)171     void setMoveWhenCompletedDir(const QString &dir) override
172     {
173         completed_dir = dir;
174         saveStats();
175     }
getMoveWhenCompletedDir()176     QString getMoveWhenCompletedDir() const override
177     {
178         return completed_dir;
179     }
180     void setSuperSeeding(bool on) override;
181 
182     /// Create all the necessary files
183     void createFiles();
184 
185     /// Get the PeerManager
186     const PeerManager *getPeerMgr() const;
187 
188     /**
189      * Set a custom chunk selector factory (needs to be done for init is called)
190      * Note: TorrentControl does not take ownership
191      */
192     void setChunkSelectorFactory(ChunkSelectorFactoryInterface *csfi);
193 
194     /// Set a custom Cache factory
195     void setCacheFactory(CacheFactory *cf);
196 
197     /// Get time in msec since the last Stats file save on disk
getStatsSyncElapsedTime()198     TimeStamp getStatsSyncElapsedTime()
199     {
200         return stats_save_timer.getElapsedSinceUpdate();
201     }
202 
203 public:
204     /**
205      * Update the object, should be called periodically.
206      */
207     void update() override;
208 
209     /**
210      * Pause the torrent.
211      */
212     void pause() override;
213 
214     /**
215      * Unpause the torrent.
216      */
217     void unpause() override;
218 
219     /**
220      * Start the download of the torrent.
221      */
222     void start() override;
223 
224     /**
225      * Stop the download, closes all connections.
226      * @param wjob WaitJob to wait at exit for the completion of stopped requests
227      */
228     void stop(WaitJob *wjob = nullptr) override;
229 
230     /**
231      * Update the tracker, this should normally handled internally.
232      * We leave it public so that the user can do a manual announce.
233      */
234     void updateTracker() override;
235 
236     /**
237      * Scrape the tracker.
238      * */
239     void scrapeTracker() override;
240 
241     /**
242      * A scrape has finished on the tracker.
243      * */
244     void trackerScrapeDone();
245 
246     /**
247      * Enable or disable data check upon completion
248      * @param on
249      */
setDataCheckWhenCompleted(bool on)250     static void setDataCheckWhenCompleted(bool on)
251     {
252         completed_datacheck = on;
253     }
254 
255     /**
256      * Set the minimum amount of diskspace in MB. When there is less then this free, torrents will be stopped.
257      * @param m
258      */
setMinimumDiskSpace(Uint32 m)259     static void setMinimumDiskSpace(Uint32 m)
260     {
261         min_diskspace = m;
262     }
263 
264 protected:
265     /// Called when a data check is finished by DataCheckerJob
266     void afterDataCheck(DataCheckerJob *job, const BitSet &result);
267     void beforeDataCheck();
268     void preallocFinished(const QString &error, bool completed);
269     void allJobsDone();
270     bool preallocate();
271 
272 private:
273     void onNewPeer(Peer *p);
274     void onPeerRemoved(Peer *p);
275     void doChoking();
276     void onIOError(const QString &msg);
277     /// Update the stats of the torrent.
278     void updateStats();
279     void corrupted(Uint32 chunk);
280     void moveDataFilesFinished(KJob *j);
281     void moveDataFilesWithMapFinished(KJob *j);
282     void downloaded(Uint32 chunk);
283     void moveToCompletedDir();
284     void emitFinished();
285 
286     void updateTracker(const QString &ev, bool last_succes = true);
287     void updateStatus() override;
288     void saveStats();
289     void loadStats();
290     void loadOutputDir();
291     void loadEncoding();
292     void getSeederInfo(Uint32 &total, Uint32 &connected_to) const;
293     void getLeecherInfo(Uint32 &total, Uint32 &connected_to) const;
294     void continueStart();
295     void handleError(const QString &err) override;
296     void initInternal(QueueManagerInterface *qman, const QString &tmpdir, const QString &ddir);
297     void checkExisting(QueueManagerInterface *qman);
298     void setupDirs(const QString &tmpdir, const QString &ddir);
299     void setupStats();
300     void setupData();
301     void setUploadProps(Uint32 limit, Uint32 rate);
302     void setDownloadProps(Uint32 limit, Uint32 rate);
303     void downloadPriorityChanged(TorrentFile *tf, Priority newpriority, Priority oldpriority) override;
304     void updateRunningTimes();
305 
306 Q_SIGNALS:
307     void dataCheckFinished();
308 
309 private:
310     JobQueue *job_queue;
311     QueueManagerInterface *m_qman;
312     Torrent *tor;
313     PeerSourceManager *psman;
314     ChunkManager *cman;
315     PeerManager *pman;
316     Downloader *downloader;
317     Uploader *uploader;
318     Choker *choke;
319     TimeEstimator *m_eta;
320     MonitorInterface *tmon;
321     CacheFactory *cache_factory;
322     QString move_data_files_destination_path;
323     Timer choker_update_timer;
324     Timer stats_save_timer;
325     Timer stalled_timer;
326     Timer wanted_update_timer;
327     QString tordir;
328     QString old_tordir;
329     QString outputdir;
330     QString error_msg;
331     QString completed_dir;
332     bool prealloc;
333     TimeStamp last_diskspace_check;
334     bool loading_stats;
335 
336     struct InternalStats {
337         QDateTime time_started_dl;
338         QDateTime time_started_ul;
339         Uint32 running_time_dl;
340         Uint32 running_time_ul;
341         Uint64 prev_bytes_dl;
342         Uint64 prev_bytes_ul;
343         Uint64 session_bytes_uploaded;
344         bool io_error;
345         bool custom_output_name;
346         Uint16 port;
347         int priority;
348         bool dht_on;
349         bool diskspace_warning_emitted;
350     };
351 
352     Uint32 upload_gid; // group ID for upload
353     Uint32 upload_limit;
354     Uint32 download_gid; // group ID for download
355     Uint32 download_limit;
356 
357     Uint32 assured_download_speed;
358     Uint32 assured_upload_speed;
359 
360     InternalStats istats;
361     StatsFile *stats_file;
362 
363     TorrentFileStream::WPtr stream;
364 
365     static bool completed_datacheck;
366     static Uint32 min_diskspace;
367 
368     friend class DataCheckerJob;
369     friend class PreallocationJob;
370     friend class JobQueue;
371 };
372 
373 }
374 
375 #endif
376