2 * This file Copyright (C) Mnemosyne LLC
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2 (b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
10 * $Id: torrent.c 13769 2013-01-05 17:46:12Z jordan $
13 #include <signal.h> /* signal () */
14 #include <sys/types.h> /* stat */
15 #include <sys/stat.h> /* stat */
17 #include <sys/wait.h> /* wait () */
20 #define waitpid(pid, status, options) _cwait (status, pid, WAIT_CHILD)
22 #include <unistd.h> /* stat */
28 #include <string.h> /* memcmp */
29 #include <stdlib.h> /* qsort */
30 #include <stdio.h> /* remove () */
32 #include <event2/util.h> /* evutil_vsnprintf () */
34 #include "transmission.h"
35 #include "announcer.h"
36 #include "bandwidth.h"
39 #include "completion.h"
40 #include "crypto.h" /* for tr_sha1 */
42 #include "fdlimit.h" /* tr_fdTorrentClose */
43 #include "inout.h" /* tr_ioTestPiece () */
46 #include "peer-common.h" /* MAX_BLOCK_SIZE */
48 #include "platform.h" /* TR_PATH_DELIMITER_STR */
52 #include "torrent-magnet.h"
53 #include "trevent.h" /* tr_runInEventThread () */
62 #define tr_deeplog_tor(tor, ...) \
65 if (tr_deepLoggingIsActive ()) \
66 tr_deepLog (__FILE__, __LINE__, tr_torrentName (tor), __VA_ARGS__); \
75 tr_torrentName (const tr_torrent
* tor
)
77 assert (tr_isTorrent (tor
));
79 return tor
->info
.name
;
83 tr_torrentId (const tr_torrent
* tor
)
89 tr_torrentFindFromId (tr_session
* session
, int id
)
91 tr_torrent
* tor
= NULL
;
93 while ((tor
= tr_torrentNext (session
, tor
)))
94 if (tor
->uniqueId
== id
)
101 tr_torrentFindFromHashString (tr_session
* session
, const char * str
)
103 tr_torrent
* tor
= NULL
;
105 while ((tor
= tr_torrentNext (session
, tor
)))
106 if (!evutil_ascii_strcasecmp (str
, tor
->info
.hashString
))
113 tr_torrentFindFromHash (tr_session
* session
, const uint8_t * torrentHash
)
115 tr_torrent
* tor
= NULL
;
117 while ((tor
= tr_torrentNext (session
, tor
)))
118 if (*tor
->info
.hash
== *torrentHash
)
119 if (!memcmp (tor
->info
.hash
, torrentHash
, SHA_DIGEST_LENGTH
))
126 tr_torrentFindFromMagnetLink (tr_session
* session
, const char * magnet
)
128 tr_magnet_info
* info
;
129 tr_torrent
* tor
= NULL
;
131 if ((info
= tr_magnetParse (magnet
)))
133 tor
= tr_torrentFindFromHash (session
, info
->hash
);
134 tr_magnetFree (info
);
141 tr_torrentFindFromObfuscatedHash (tr_session
* session
,
142 const uint8_t * obfuscatedTorrentHash
)
144 tr_torrent
* tor
= NULL
;
146 while ((tor
= tr_torrentNext (session
, tor
)))
147 if (!memcmp (tor
->obfuscatedHash
, obfuscatedTorrentHash
,
155 tr_torrentIsPieceTransferAllowed (const tr_torrent
* tor
,
156 tr_direction direction
)
161 if (tr_torrentUsesSpeedLimit (tor
, direction
))
162 if (tr_torrentGetSpeedLimit_Bps (tor
, direction
) <= 0)
165 if (tr_torrentUsesSessionLimits (tor
))
166 if (tr_sessionGetActiveSpeedLimit_Bps (tor
->session
, direction
, &limit
))
174 **** PER-TORRENT UL / DL SPEEDS
178 tr_torrentSetSpeedLimit_Bps (tr_torrent
* tor
, tr_direction dir
, unsigned int Bps
)
180 assert (tr_isTorrent (tor
));
181 assert (tr_isDirection (dir
));
183 if (tr_bandwidthSetDesiredSpeed_Bps (&tor
->bandwidth
, dir
, Bps
))
184 tr_torrentSetDirty (tor
);
187 tr_torrentSetSpeedLimit_KBps (tr_torrent
* tor
, tr_direction dir
, unsigned int KBps
)
189 tr_torrentSetSpeedLimit_Bps (tor
, dir
, toSpeedBytes (KBps
));
193 tr_torrentGetSpeedLimit_Bps (const tr_torrent
* tor
, tr_direction dir
)
195 assert (tr_isTorrent (tor
));
196 assert (tr_isDirection (dir
));
198 return tr_bandwidthGetDesiredSpeed_Bps (&tor
->bandwidth
, dir
);
201 tr_torrentGetSpeedLimit_KBps (const tr_torrent
* tor
, tr_direction dir
)
203 return toSpeedKBps (tr_torrentGetSpeedLimit_Bps (tor
, dir
));
207 tr_torrentUseSpeedLimit (tr_torrent
* tor
, tr_direction dir
, bool do_use
)
209 assert (tr_isTorrent (tor
));
210 assert (tr_isDirection (dir
));
212 if (tr_bandwidthSetLimited (&tor
->bandwidth
, dir
, do_use
))
213 tr_torrentSetDirty (tor
);
217 tr_torrentUsesSpeedLimit (const tr_torrent
* tor
, tr_direction dir
)
219 assert (tr_isTorrent (tor
));
220 assert (tr_isDirection (dir
));
222 return tr_bandwidthIsLimited (&tor
->bandwidth
, dir
);
226 tr_torrentUseSessionLimits (tr_torrent
* tor
, bool doUse
)
230 assert (tr_isTorrent (tor
));
232 changed
= tr_bandwidthHonorParentLimits (&tor
->bandwidth
, TR_UP
, doUse
);
233 changed
|= tr_bandwidthHonorParentLimits (&tor
->bandwidth
, TR_DOWN
, doUse
);
236 tr_torrentSetDirty (tor
);
240 tr_torrentUsesSessionLimits (const tr_torrent
* tor
)
242 assert (tr_isTorrent (tor
));
244 return tr_bandwidthAreParentLimitsHonored (&tor
->bandwidth
, TR_UP
);
252 tr_torrentSetRatioMode (tr_torrent
* tor
, tr_ratiolimit mode
)
254 assert (tr_isTorrent (tor
));
255 assert (mode
==TR_RATIOLIMIT_GLOBAL
|| mode
==TR_RATIOLIMIT_SINGLE
|| mode
==TR_RATIOLIMIT_UNLIMITED
);
257 if (mode
!= tor
->ratioLimitMode
)
259 tor
->ratioLimitMode
= mode
;
261 tr_torrentSetDirty (tor
);
266 tr_torrentGetRatioMode (const tr_torrent
* tor
)
268 assert (tr_isTorrent (tor
));
270 return tor
->ratioLimitMode
;
274 tr_torrentSetRatioLimit (tr_torrent
* tor
, double desiredRatio
)
276 assert (tr_isTorrent (tor
));
278 if ((int)(desiredRatio
*100.0) != (int)(tor
->desiredRatio
*100.0))
280 tor
->desiredRatio
= desiredRatio
;
282 tr_torrentSetDirty (tor
);
287 tr_torrentGetRatioLimit (const tr_torrent
* tor
)
289 assert (tr_isTorrent (tor
));
291 return tor
->desiredRatio
;
295 tr_torrentGetSeedRatio (const tr_torrent
* tor
, double * ratio
)
299 switch (tr_torrentGetRatioMode (tor
))
301 case TR_RATIOLIMIT_SINGLE
:
304 *ratio
= tr_torrentGetRatioLimit (tor
);
307 case TR_RATIOLIMIT_GLOBAL
:
308 isLimited
= tr_sessionIsRatioLimited (tor
->session
);
309 if (isLimited
&& ratio
)
310 *ratio
= tr_sessionGetRatioLimit (tor
->session
);
313 default: /* TR_RATIOLIMIT_UNLIMITED */
321 /* returns true if the seed ratio applies --
322 * it applies if the torrent's a seed AND it has a seed ratio set */
324 tr_torrentGetSeedRatioBytes (tr_torrent
* tor
,
325 uint64_t * setmeLeft
,
326 uint64_t * setmeGoal
)
329 bool seedRatioApplies
= false;
331 if (tr_torrentGetSeedRatio (tor
, &seedRatio
))
333 const uint64_t u
= tor
->uploadedCur
+ tor
->uploadedPrev
;
334 const uint64_t d
= tor
->downloadedCur
+ tor
->downloadedPrev
;
335 const uint64_t baseline
= d
? d
: tr_cpSizeWhenDone (&tor
->completion
);
336 const uint64_t goal
= baseline
* seedRatio
;
337 if (setmeLeft
) *setmeLeft
= goal
> u
? goal
- u
: 0;
338 if (setmeGoal
) *setmeGoal
= goal
;
339 seedRatioApplies
= tr_torrentIsSeed (tor
);
342 return seedRatioApplies
;
346 tr_torrentIsSeedRatioDone (tr_torrent
* tor
)
349 return tr_torrentGetSeedRatioBytes (tor
, &bytesLeft
, NULL
) && !bytesLeft
;
357 tr_torrentSetIdleMode (tr_torrent
* tor
, tr_idlelimit mode
)
359 assert (tr_isTorrent (tor
));
360 assert (mode
==TR_IDLELIMIT_GLOBAL
|| mode
==TR_IDLELIMIT_SINGLE
|| mode
==TR_IDLELIMIT_UNLIMITED
);
362 if (mode
!= tor
->idleLimitMode
)
364 tor
->idleLimitMode
= mode
;
366 tr_torrentSetDirty (tor
);
371 tr_torrentGetIdleMode (const tr_torrent
* tor
)
373 assert (tr_isTorrent (tor
));
375 return tor
->idleLimitMode
;
379 tr_torrentSetIdleLimit (tr_torrent
* tor
, uint16_t idleMinutes
)
381 assert (tr_isTorrent (tor
));
385 tor
->idleLimitMinutes
= idleMinutes
;
387 tr_torrentSetDirty (tor
);
392 tr_torrentGetIdleLimit (const tr_torrent
* tor
)
394 assert (tr_isTorrent (tor
));
396 return tor
->idleLimitMinutes
;
400 tr_torrentGetSeedIdle (const tr_torrent
* tor
, uint16_t * idleMinutes
)
404 switch (tr_torrentGetIdleMode (tor
))
406 case TR_IDLELIMIT_SINGLE
:
409 *idleMinutes
= tr_torrentGetIdleLimit (tor
);
412 case TR_IDLELIMIT_GLOBAL
:
413 isLimited
= tr_sessionIsIdleLimited (tor
->session
);
414 if (isLimited
&& idleMinutes
)
415 *idleMinutes
= tr_sessionGetIdleLimit (tor
->session
);
418 default: /* TR_IDLELIMIT_UNLIMITED */
427 tr_torrentIsSeedIdleLimitDone (tr_torrent
* tor
)
429 uint16_t idleMinutes
;
430 return tr_torrentGetSeedIdle (tor
, &idleMinutes
)
431 && difftime (tr_time (), MAX (tor
->startDate
, tor
->activityDate
)) >= idleMinutes
* 60u;
439 tr_torrentCheckSeedLimit (tr_torrent
* tor
)
441 assert (tr_isTorrent (tor
));
443 if (!tor
->isRunning
|| tor
->isStopping
|| !tr_torrentIsSeed (tor
))
446 /* if we're seeding and reach our seed ratio limit, stop the torrent */
447 if (tr_torrentIsSeedRatioDone (tor
))
449 tr_torinf (tor
, "Seed ratio reached; pausing torrent");
451 tor
->isStopping
= true;
453 /* maybe notify the client */
454 if (tor
->ratio_limit_hit_func
!= NULL
)
455 tor
->ratio_limit_hit_func (tor
, tor
->ratio_limit_hit_func_user_data
);
457 /* if we're seeding and reach our inactiviy limit, stop the torrent */
458 else if (tr_torrentIsSeedIdleLimitDone (tor
))
460 tr_torinf (tor
, "Seeding idle limit reached; pausing torrent");
462 tor
->isStopping
= true;
463 tor
->finishedSeedingByIdle
= true;
465 /* maybe notify the client */
466 if (tor
->idle_limit_hit_func
!= NULL
)
467 tor
->idle_limit_hit_func (tor
, tor
->idle_limit_hit_func_user_data
);
476 tr_torrentSetLocalError (tr_torrent
* tor
, const char * fmt
, ...)
480 assert (tr_isTorrent (tor
));
483 tor
->error
= TR_STAT_LOCAL_ERROR
;
484 tor
->errorTracker
[0] = '\0';
485 evutil_vsnprintf (tor
->errorString
, sizeof (tor
->errorString
), fmt
, ap
);
488 tr_torerr (tor
, "%s", tor
->errorString
);
491 tor
->isStopping
= true;
495 tr_torrentClearError (tr_torrent
* tor
)
497 tor
->error
= TR_STAT_OK
;
498 tor
->errorString
[0] = '\0';
499 tor
->errorTracker
[0] = '\0';
503 onTrackerResponse (tr_torrent
* tor
, const tr_tracker_event
* event
, void * unused UNUSED
)
505 switch (event
->messageType
)
507 case TR_TRACKER_PEERS
:
510 const int8_t seedProbability
= event
->seedProbability
;
511 const bool allAreSeeds
= seedProbability
== 100;
514 tr_tordbg (tor
, "Got %zu seeds from tracker", event
->pexCount
);
516 tr_tordbg (tor
, "Got %zu peers from tracker", event
->pexCount
);
518 for (i
= 0; i
< event
->pexCount
; ++i
)
519 tr_peerMgrAddPex (tor
, TR_PEER_FROM_TRACKER
, &event
->pex
[i
], seedProbability
);
524 case TR_TRACKER_WARNING
:
525 tr_torerr (tor
, _("Tracker warning: \"%s\""), event
->text
);
526 tor
->error
= TR_STAT_TRACKER_WARNING
;
527 tr_strlcpy (tor
->errorTracker
, event
->tracker
, sizeof (tor
->errorTracker
));
528 tr_strlcpy (tor
->errorString
, event
->text
, sizeof (tor
->errorString
));
531 case TR_TRACKER_ERROR
:
532 tr_torerr (tor
, _("Tracker error: \"%s\""), event
->text
);
533 tor
->error
= TR_STAT_TRACKER_ERROR
;
534 tr_strlcpy (tor
->errorTracker
, event
->tracker
, sizeof (tor
->errorTracker
));
535 tr_strlcpy (tor
->errorString
, event
->text
, sizeof (tor
->errorString
));
538 case TR_TRACKER_ERROR_CLEAR
:
539 if (tor
->error
!= TR_STAT_LOCAL_ERROR
)
540 tr_torrentClearError (tor
);
547 **** TORRENT INSTANTIATION
551 static tr_piece_index_t
552 getBytePiece (const tr_info
* info
, uint64_t byteOffset
)
554 tr_piece_index_t piece
;
557 assert (info
->pieceSize
!= 0);
559 piece
= byteOffset
/ info
->pieceSize
;
561 /* handle 0-byte files at the end of a torrent */
562 if (byteOffset
== info
->totalSize
)
563 piece
= info
->pieceCount
- 1;
569 initFilePieces (tr_info
* info
,
570 tr_file_index_t fileIndex
)
573 uint64_t firstByte
, lastByte
;
576 assert (fileIndex
< info
->fileCount
);
578 file
= &info
->files
[fileIndex
];
579 firstByte
= file
->offset
;
580 lastByte
= firstByte
+ (file
->length
? file
->length
- 1 : 0);
581 file
->firstPiece
= getBytePiece (info
, firstByte
);
582 file
->lastPiece
= getBytePiece (info
, lastByte
);
586 pieceHasFile (tr_piece_index_t piece
,
587 const tr_file
* file
)
589 return (file
->firstPiece
<= piece
) && (piece
<= file
->lastPiece
);
593 calculatePiecePriority (const tr_torrent
* tor
,
594 tr_piece_index_t piece
,
598 tr_priority_t priority
= TR_PRI_LOW
;
600 /* find the first file that has data in this piece */
603 while (i
> 0 && pieceHasFile (piece
, &tor
->info
.files
[i
- 1]))
606 for (i
= 0; i
< tor
->info
.fileCount
; ++i
)
607 if (pieceHasFile (piece
, &tor
->info
.files
[i
]))
611 /* the piece's priority is the max of the priorities
612 * of all the files in that piece */
613 for (; i
< tor
->info
.fileCount
; ++i
)
615 const tr_file
* file
= &tor
->info
.files
[i
];
617 if (!pieceHasFile (piece
, file
))
620 priority
= MAX (priority
, file
->priority
);
622 /* when dealing with multimedia files, getting the first and
623 last pieces can sometimes allow you to preview it a bit
624 before it's fully downloaded... */
625 if (file
->priority
>= TR_PRI_NORMAL
)
626 if (file
->firstPiece
== piece
|| file
->lastPiece
== piece
)
627 priority
= TR_PRI_HIGH
;
634 tr_torrentInitFilePieces (tr_torrent
* tor
)
640 tr_info
* inf
= &tor
->info
;
642 /* assign the file offsets */
643 for (f
=0; f
<inf
->fileCount
; ++f
) {
644 inf
->files
[f
].offset
= offset
;
645 offset
+= inf
->files
[f
].length
;
646 initFilePieces (inf
, f
);
649 /* build the array of first-file hints to give calculatePiecePriority */
650 firstFiles
= tr_new (int, inf
->pieceCount
);
651 for (p
=f
=0; p
<inf
->pieceCount
; ++p
) {
652 while (inf
->files
[f
].lastPiece
< p
)
658 /* test to confirm the first-file hints are correct */
659 for (p
=0; p
<inf
->pieceCount
; ++p
) {
661 assert (inf
->files
[f
].firstPiece
<= p
);
662 assert (inf
->files
[f
].lastPiece
>= p
);
664 assert (inf
->files
[f
-1].lastPiece
< p
);
665 for (f
=0; f
<inf
->fileCount
; ++f
)
666 if (pieceHasFile (p
, &inf
->files
[f
]))
668 assert ((int)f
== firstFiles
[p
]);
672 for (p
=0; p
<inf
->pieceCount
; ++p
)
673 inf
->pieces
[p
].priority
= calculatePiecePriority (tor
, p
, firstFiles
[p
]);
675 tr_free (firstFiles
);
678 static void torrentStart (tr_torrent
* tor
, bool bypass_queue
);
681 * Decide on a block size. Constraints:
682 * (1) most clients decline requests over 16 KiB
683 * (2) pieceSize must be a multiple of block size
686 tr_getBlockSize (uint32_t pieceSize
)
688 uint32_t b
= pieceSize
;
690 while (b
> MAX_BLOCK_SIZE
)
693 if (!b
|| (pieceSize
% b
)) /* not cleanly divisible */
698 static void refreshCurrentDir (tr_torrent
* tor
);
701 torrentInitFromInfo (tr_torrent
* tor
)
704 tr_info
* info
= &tor
->info
;
706 tor
->blockSize
= tr_getBlockSize (info
->pieceSize
);
709 tor
->lastPieceSize
= (uint32_t)(info
->totalSize
% info
->pieceSize
);
711 if (!tor
->lastPieceSize
)
712 tor
->lastPieceSize
= info
->pieceSize
;
715 tor
->lastBlockSize
= info
->totalSize
% tor
->blockSize
;
717 if (!tor
->lastBlockSize
)
718 tor
->lastBlockSize
= tor
->blockSize
;
720 tor
->blockCount
= tor
->blockSize
721 ? (info
->totalSize
+ tor
->blockSize
- 1) / tor
->blockSize
724 tor
->blockCountInPiece
= tor
->blockSize
725 ? info
->pieceSize
/ tor
->blockSize
728 tor
->blockCountInLastPiece
= tor
->blockSize
729 ? (tor
->lastPieceSize
+ tor
->blockSize
- 1) / tor
->blockSize
733 if (tor
->blockSize
!= 0)
734 assert ((info
->pieceSize
% tor
->blockSize
) == 0);
735 t
= info
->pieceCount
- 1;
736 t
*= info
->pieceSize
;
737 t
+= tor
->lastPieceSize
;
738 assert (t
== info
->totalSize
);
739 t
= tor
->blockCount
- 1;
741 t
+= tor
->lastBlockSize
;
742 assert (t
== info
->totalSize
);
743 t
= info
->pieceCount
- 1;
744 t
*= tor
->blockCountInPiece
;
745 t
+= tor
->blockCountInLastPiece
;
746 assert (t
== (uint64_t)tor
->blockCount
);
748 tr_cpConstruct (&tor
->completion
, tor
);
750 tr_torrentInitFilePieces (tor
);
752 tor
->completeness
= tr_cpGetStatus (&tor
->completion
);
755 static void tr_torrentFireMetadataCompleted (tr_torrent
* tor
);
758 tr_torrentGotNewInfoDict (tr_torrent
* tor
)
760 torrentInitFromInfo (tor
);
762 tr_peerMgrOnTorrentGotMetainfo (tor
);
764 tr_torrentFireMetadataCompleted (tor
);
768 hasAnyLocalData (const tr_torrent
* tor
)
772 for (i
=0; i
<tor
->info
.fileCount
; ++i
)
773 if (tr_torrentFindFile2 (tor
, i
, NULL
, NULL
, NULL
))
780 setLocalErrorIfFilesDisappeared (tr_torrent
* tor
)
782 const bool disappeared
= (tr_cpHaveTotal (&tor
->completion
) > 0) && !hasAnyLocalData (tor
);
786 tr_deeplog_tor (tor
, "%s", "[LAZY] uh oh, the files disappeared");
787 tr_torrentSetLocalError (tor
, "%s", _("No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it."));
794 torrentInit (tr_torrent
* tor
, const tr_ctor
* ctor
)
801 static int nextUniqueId
= 1;
802 tr_session
* session
= tr_ctorGetSession (ctor
);
804 assert (session
!= NULL
);
806 tr_sessionLock (session
);
808 tor
->session
= session
;
809 tor
->uniqueId
= nextUniqueId
++;
810 tor
->magicNumber
= TORRENT_MAGIC_NUMBER
;
811 tor
->queuePosition
= session
->torrentCount
;
813 tr_peerIdInit (tor
->peer_id
);
815 tr_sha1 (tor
->obfuscatedHash
, "req2", 4,
816 tor
->info
.hash
, SHA_DIGEST_LENGTH
,
819 if (!tr_ctorGetDownloadDir (ctor
, TR_FORCE
, &dir
) ||
820 !tr_ctorGetDownloadDir (ctor
, TR_FALLBACK
, &dir
))
821 tor
->downloadDir
= tr_strdup (dir
);
823 if (tr_ctorGetIncompleteDir (ctor
, &dir
))
824 dir
= tr_sessionGetIncompleteDir (session
);
825 if (tr_sessionIsIncompleteDirEnabled (session
))
826 tor
->incompleteDir
= tr_strdup (dir
);
828 tr_bandwidthConstruct (&tor
->bandwidth
, session
, &session
->bandwidth
);
830 tor
->bandwidth
.priority
= tr_ctorGetBandwidthPriority (ctor
);
832 tor
->error
= TR_STAT_OK
;
834 tor
->finishedSeedingByIdle
= false;
836 tr_peerMgrAddTorrent (session
->peerMgr
, tor
);
838 assert (!tor
->downloadedCur
);
839 assert (!tor
->uploadedCur
);
841 tr_torrentSetAddedDate (tor
, tr_time ()); /* this is a default value to be
842 overwritten by the resume file */
844 torrentInitFromInfo (tor
);
845 loaded
= tr_torrentLoadResume (tor
, ~0, ctor
);
846 tor
->completeness
= tr_cpGetStatus (&tor
->completion
);
847 setLocalErrorIfFilesDisappeared (tor
);
849 tr_ctorInitTorrentPriorities (ctor
, tor
);
850 tr_ctorInitTorrentWanted (ctor
, tor
);
852 refreshCurrentDir (tor
);
854 doStart
= tor
->isRunning
;
857 if (! (loaded
& TR_FR_SPEEDLIMIT
))
859 tr_torrentUseSpeedLimit (tor
, TR_UP
, false);
860 tr_torrentSetSpeedLimit_Bps (tor
, TR_UP
, tr_sessionGetSpeedLimit_Bps (tor
->session
, TR_UP
));
861 tr_torrentUseSpeedLimit (tor
, TR_DOWN
, false);
862 tr_torrentSetSpeedLimit_Bps (tor
, TR_DOWN
, tr_sessionGetSpeedLimit_Bps (tor
->session
, TR_DOWN
));
863 tr_torrentUseSessionLimits (tor
, true);
866 if (! (loaded
& TR_FR_RATIOLIMIT
))
868 tr_torrentSetRatioMode (tor
, TR_RATIOLIMIT_GLOBAL
);
869 tr_torrentSetRatioLimit (tor
, tr_sessionGetRatioLimit (tor
->session
));
872 if (! (loaded
& TR_FR_IDLELIMIT
))
874 tr_torrentSetIdleMode (tor
, TR_IDLELIMIT_GLOBAL
);
875 tr_torrentSetIdleLimit (tor
, tr_sessionGetIdleLimit (tor
->session
));
878 /* add the torrent to tr_session.torrentList */
879 session
->torrentCount
++;
880 if (session
->torrentList
== NULL
)
881 session
->torrentList
= tor
;
883 tr_torrent
* it
= session
->torrentList
;
884 while (it
->next
!= NULL
)
889 /* if we don't have a local .torrent file already, assume the torrent is new */
890 isNewTorrent
= stat (tor
->info
.torrent
, &st
);
892 /* maybe save our own copy of the metainfo */
893 if (tr_ctorGetSave (ctor
))
896 if (!tr_ctorGetMetainfo (ctor
, &val
))
898 const char * path
= tor
->info
.torrent
;
899 const int err
= tr_bencToFile (val
, TR_FMT_BENC
, path
);
901 tr_torrentSetLocalError (tor
, "Unable to save torrent file: %s", tr_strerror (err
));
902 tr_sessionSetTorrentFile (tor
->session
, tor
->info
.hashString
, path
);
906 tor
->tiers
= tr_announcerAddTorrent (tor
, onTrackerResponse
, NULL
);
910 tor
->startAfterVerify
= doStart
;
911 tr_torrentVerify (tor
);
915 tr_torrentStart (tor
);
918 tr_sessionUnlock (session
);
921 static tr_parse_result
922 torrentParseImpl (const tr_ctor
* ctor
, tr_info
* setmeInfo
,
923 bool * setmeHasInfo
, int * dictLength
)
927 bool hasInfo
= false;
929 const tr_benc
* metainfo
;
930 tr_session
* session
= tr_ctorGetSession (ctor
);
931 tr_parse_result result
= TR_PARSE_OK
;
933 if (setmeInfo
== NULL
)
935 memset (setmeInfo
, 0, sizeof (tr_info
));
937 if (tr_ctorGetMetainfo (ctor
, &metainfo
))
940 didParse
= tr_metainfoParse (session
, metainfo
, setmeInfo
,
941 &hasInfo
, dictLength
);
942 doFree
= didParse
&& (setmeInfo
== &tmp
);
945 result
= TR_PARSE_ERR
;
947 if (didParse
&& hasInfo
&& !tr_getBlockSize (setmeInfo
->pieceSize
))
948 result
= TR_PARSE_ERR
;
950 if (didParse
&& session
&& tr_torrentExists (session
, setmeInfo
->hash
))
951 result
= TR_PARSE_DUPLICATE
;
954 tr_metainfoFree (setmeInfo
);
956 if (setmeHasInfo
!= NULL
)
957 *setmeHasInfo
= hasInfo
;
963 tr_torrentParse (const tr_ctor
* ctor
, tr_info
* setmeInfo
)
965 return torrentParseImpl (ctor
, setmeInfo
, NULL
, NULL
);
969 tr_torrentNew (const tr_ctor
* ctor
, int * setmeError
)
975 tr_torrent
* tor
= NULL
;
977 assert (ctor
!= NULL
);
978 assert (tr_isSession (tr_ctorGetSession (ctor
)));
980 r
= torrentParseImpl (ctor
, &tmpInfo
, &hasInfo
, &len
);
981 if (r
== TR_PARSE_OK
)
983 tor
= tr_new0 (tr_torrent
, 1);
986 tor
->infoDictLength
= len
;
987 torrentInit (tor
, ctor
);
991 if (r
== TR_PARSE_DUPLICATE
)
992 tr_metainfoFree (&tmpInfo
);
1006 tr_torrentSetDownloadDir (tr_torrent
* tor
, const char * path
)
1008 assert (tr_isTorrent (tor
));
1010 if (!path
|| !tor
->downloadDir
|| strcmp (path
, tor
->downloadDir
))
1012 tr_free (tor
->downloadDir
);
1013 tor
->downloadDir
= tr_strdup (path
);
1014 tr_torrentSetDirty (tor
);
1017 refreshCurrentDir (tor
);
1021 tr_torrentGetDownloadDir (const tr_torrent
* tor
)
1023 assert (tr_isTorrent (tor
));
1025 return tor
->downloadDir
;
1029 tr_torrentGetCurrentDir (const tr_torrent
* tor
)
1031 assert (tr_isTorrent (tor
));
1033 return tor
->currentDir
;
1038 tr_torrentChangeMyPort (tr_torrent
* tor
)
1040 assert (tr_isTorrent (tor
));
1043 tr_announcerChangeMyPort (tor
);
1047 tr_torrentManualUpdateImpl (void * vtor
)
1049 tr_torrent
* tor
= vtor
;
1051 assert (tr_isTorrent (tor
));
1054 tr_announcerManualAnnounce (tor
);
1058 tr_torrentManualUpdate (tr_torrent
* tor
)
1060 assert (tr_isTorrent (tor
));
1062 tr_runInEventThread (tor
->session
, tr_torrentManualUpdateImpl
, tor
);
1066 tr_torrentCanManualUpdate (const tr_torrent
* tor
)
1068 return (tr_isTorrent (tor
))
1070 && (tr_announcerCanManualAnnounce (tor
));
1074 tr_torrentInfo (const tr_torrent
* tor
)
1076 return tr_isTorrent (tor
) ? &tor
->info
: NULL
;
1080 tr_torrentStatCached (tr_torrent
* tor
)
1082 const time_t now
= tr_time ();
1084 return tr_isTorrent (tor
) && (now
== tor
->lastStatTime
)
1086 : tr_torrentStat (tor
);
1090 tr_torrentSetVerifyState (tr_torrent
* tor
, tr_verify_state state
)
1092 assert (tr_isTorrent (tor
));
1093 assert (state
==TR_VERIFY_NONE
|| state
==TR_VERIFY_WAIT
|| state
==TR_VERIFY_NOW
);
1095 tor
->verifyState
= state
;
1096 tor
->anyDate
= tr_time ();
1099 static tr_torrent_activity
1100 torrentGetActivity (const tr_torrent
* tor
)
1102 const bool is_seed
= tr_torrentIsSeed (tor
);
1103 assert (tr_isTorrent (tor
));
1105 if (tor
->verifyState
== TR_VERIFY_NOW
)
1106 return TR_STATUS_CHECK
;
1108 if (tor
->verifyState
== TR_VERIFY_WAIT
)
1109 return TR_STATUS_CHECK_WAIT
;
1112 return is_seed
? TR_STATUS_SEED
: TR_STATUS_DOWNLOAD
;
1114 if (tr_torrentIsQueued (tor
)) {
1115 if (is_seed
&& tr_sessionGetQueueEnabled (tor
->session
, TR_UP
))
1116 return TR_STATUS_SEED_WAIT
;
1117 if (!is_seed
&& tr_sessionGetQueueEnabled (tor
->session
, TR_DOWN
))
1118 return TR_STATUS_DOWNLOAD_WAIT
;
1121 return TR_STATUS_STOPPED
;
1125 tr_torrentGetActivity (tr_torrent
* tor
)
1127 /* FIXME: is this call still needed? */
1128 tr_torrentRecheckCompleteness (tor
);
1130 return torrentGetActivity (tor
);
1134 torrentGetIdleSecs (const tr_torrent
* tor
)
1137 const tr_torrent_activity activity
= torrentGetActivity (tor
);
1139 if ((activity
== TR_STATUS_DOWNLOAD
|| activity
== TR_STATUS_SEED
) && tor
->startDate
!= 0)
1140 idle_secs
= difftime (tr_time (), MAX (tor
->startDate
, tor
->activityDate
));
1148 tr_torrentIsStalled (const tr_torrent
* tor
)
1150 return tr_sessionGetQueueStalledEnabled (tor
->session
)
1151 && (torrentGetIdleSecs (tor
) > (tr_sessionGetQueueStalledMinutes (tor
->session
) * 60));
1156 getVerifyProgress (const tr_torrent
* tor
)
1160 assert (tr_isTorrent (tor
));
1162 if (tr_torrentHasMetadata (tor
))
1164 tr_piece_index_t i
, n
;
1165 tr_piece_index_t checked
= 0;
1167 for (i
=0, n
=tor
->info
.pieceCount
; i
!=n
; ++i
)
1168 if (tor
->info
.pieces
[i
].timeChecked
)
1171 d
= checked
/ (double)tor
->info
.pieceCount
;
1178 tr_torrentStat (tr_torrent
* tor
)
1182 uint64_t seedRatioBytesLeft
;
1183 uint64_t seedRatioBytesGoal
;
1184 bool seedRatioApplies
;
1185 uint16_t seedIdleMinutes
;
1190 assert (tr_isTorrent (tor
));
1191 tr_torrentLock (tor
);
1193 tor
->lastStatTime
= tr_time ();
1196 s
->id
= tor
->uniqueId
;
1197 s
->activity
= tr_torrentGetActivity (tor
);
1198 s
->error
= tor
->error
;
1199 s
->queuePosition
= tor
->queuePosition
;
1200 s
->isStalled
= tr_torrentIsStalled (tor
);
1201 tr_strlcpy (s
->errorString
, tor
->errorString
, sizeof (s
->errorString
));
1203 s
->manualAnnounceTime
= tr_announcerNextManualAnnounce (tor
);
1205 tr_peerMgrTorrentStats (tor
,
1207 &s
->webseedsSendingToUs
,
1208 &s
->peersSendingToUs
,
1209 &s
->peersGettingFromUs
,
1212 now
= tr_time_msec ();
1213 s
->rawUploadSpeed_KBps
= toSpeedKBps (tr_bandwidthGetRawSpeed_Bps (&tor
->bandwidth
, now
, TR_UP
));
1214 s
->pieceUploadSpeed_KBps
= toSpeedKBps (tr_bandwidthGetPieceSpeed_Bps (&tor
->bandwidth
, now
, TR_UP
));
1215 s
->rawDownloadSpeed_KBps
= toSpeedKBps (tr_bandwidthGetRawSpeed_Bps (&tor
->bandwidth
, now
, TR_DOWN
));
1216 s
->pieceDownloadSpeed_KBps
= toSpeedKBps (tr_bandwidthGetPieceSpeed_Bps (&tor
->bandwidth
, now
, TR_DOWN
));
1218 s
->percentComplete
= tr_cpPercentComplete (&tor
->completion
);
1219 s
->metadataPercentComplete
= tr_torrentGetMetadataPercent (tor
);
1221 s
->percentDone
= tr_cpPercentDone (&tor
->completion
);
1222 s
->leftUntilDone
= tr_cpLeftUntilDone (&tor
->completion
);
1223 s
->sizeWhenDone
= tr_cpSizeWhenDone (&tor
->completion
);
1224 s
->recheckProgress
= s
->activity
== TR_STATUS_CHECK
? getVerifyProgress (tor
) : 0;
1225 s
->activityDate
= tor
->activityDate
;
1226 s
->addedDate
= tor
->addedDate
;
1227 s
->doneDate
= tor
->doneDate
;
1228 s
->startDate
= tor
->startDate
;
1229 s
->secondsSeeding
= tor
->secondsSeeding
;
1230 s
->secondsDownloading
= tor
->secondsDownloading
;
1231 s
->idleSecs
= torrentGetIdleSecs (tor
);
1233 s
->corruptEver
= tor
->corruptCur
+ tor
->corruptPrev
;
1234 s
->downloadedEver
= tor
->downloadedCur
+ tor
->downloadedPrev
;
1235 s
->uploadedEver
= tor
->uploadedCur
+ tor
->uploadedPrev
;
1236 s
->haveValid
= tr_cpHaveValid (&tor
->completion
);
1237 s
->haveUnchecked
= tr_cpHaveTotal (&tor
->completion
) - s
->haveValid
;
1238 s
->desiredAvailable
= tr_peerMgrGetDesiredAvailable (tor
);
1240 s
->ratio
= tr_getRatio (s
->uploadedEver
,
1241 s
->downloadedEver
? s
->downloadedEver
: s
->haveValid
);
1243 seedRatioApplies
= tr_torrentGetSeedRatioBytes (tor
, &seedRatioBytesLeft
,
1244 &seedRatioBytesGoal
);
1246 switch (s
->activity
)
1248 /* etaXLSpeed exists because if we use the piece speed directly,
1249 * brief fluctuations cause the ETA to jump all over the place.
1250 * so, etaXLSpeed is a smoothed-out version of the piece speed
1251 * to dampen the effect of fluctuations */
1253 case TR_STATUS_DOWNLOAD
:
1254 if ((tor
->etaDLSpeedCalculatedAt
+ 800) < now
) {
1255 tor
->etaDLSpeed_KBps
= ((tor
->etaDLSpeedCalculatedAt
+ 4000) < now
)
1256 ? s
->pieceDownloadSpeed_KBps
/* if no recent previous speed, no need to smooth */
1257 : ((tor
->etaDLSpeed_KBps
*4.0) + s
->pieceDownloadSpeed_KBps
)/5.0; /* smooth across 5 readings */
1258 tor
->etaDLSpeedCalculatedAt
= now
;
1261 if ((s
->leftUntilDone
> s
->desiredAvailable
) && (tor
->info
.webseedCount
< 1))
1262 s
->eta
= TR_ETA_NOT_AVAIL
;
1263 else if (tor
->etaDLSpeed_KBps
< 1)
1264 s
->eta
= TR_ETA_UNKNOWN
;
1266 s
->eta
= s
->leftUntilDone
/ toSpeedBytes (tor
->etaDLSpeed_KBps
);
1268 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1271 case TR_STATUS_SEED
: {
1272 if (!seedRatioApplies
)
1273 s
->eta
= TR_ETA_NOT_AVAIL
;
1275 if ((tor
->etaULSpeedCalculatedAt
+ 800) < now
) {
1276 tor
->etaULSpeed_KBps
= ((tor
->etaULSpeedCalculatedAt
+ 4000) < now
)
1277 ? s
->pieceUploadSpeed_KBps
/* if no recent previous speed, no need to smooth */
1278 : ((tor
->etaULSpeed_KBps
*4.0) + s
->pieceUploadSpeed_KBps
)/5.0; /* smooth across 5 readings */
1279 tor
->etaULSpeedCalculatedAt
= now
;
1281 if (tor
->etaULSpeed_KBps
< 1)
1282 s
->eta
= TR_ETA_UNKNOWN
;
1284 s
->eta
= seedRatioBytesLeft
/ toSpeedBytes (tor
->etaULSpeed_KBps
);
1287 if (tor
->etaULSpeed_KBps
< 1 && tr_torrentGetSeedIdle (tor
, &seedIdleMinutes
))
1288 s
->etaIdle
= seedIdleMinutes
* 60 - s
->idleSecs
;
1290 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1295 s
->eta
= TR_ETA_NOT_AVAIL
;
1296 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1300 /* s->haveValid is here to make sure a torrent isn't marked 'finished'
1301 * when the user hits "uncheck all" prior to starting the torrent... */
1302 s
->finished
= tor
->finishedSeedingByIdle
|| (seedRatioApplies
&& !seedRatioBytesLeft
&& s
->haveValid
);
1304 if (!seedRatioApplies
|| s
->finished
)
1305 s
->seedRatioPercentDone
= 1;
1306 else if (!seedRatioBytesGoal
) /* impossible? safeguard for div by zero */
1307 s
->seedRatioPercentDone
= 0;
1309 s
->seedRatioPercentDone
= (double)(seedRatioBytesGoal
- seedRatioBytesLeft
) / seedRatioBytesGoal
;
1311 tr_torrentUnlock (tor
);
1313 /* test some of the constraints */
1314 assert (s
->sizeWhenDone
<= tor
->info
.totalSize
);
1315 assert (s
->leftUntilDone
<= s
->sizeWhenDone
);
1316 assert (s
->desiredAvailable
<= s
->leftUntilDone
);
1325 fileBytesCompleted (const tr_torrent
* tor
, tr_file_index_t index
)
1328 const tr_file
* f
= &tor
->info
.files
[index
];
1332 tr_block_index_t first
;
1333 tr_block_index_t last
;
1334 tr_torGetFileBlockRange (tor
, index
, &first
, &last
);
1338 if (tr_cpBlockIsComplete (&tor
->completion
, first
))
1343 /* the first block */
1344 if (tr_cpBlockIsComplete (&tor
->completion
, first
))
1345 total
+= tor
->blockSize
- (f
->offset
% tor
->blockSize
);
1347 /* the middle blocks */
1348 if (first
+ 1 < last
) {
1349 uint64_t u
= tr_bitfieldCountRange (&tor
->completion
.blockBitfield
, first
+1, last
);
1350 u
*= tor
->blockSize
;
1354 /* the last block */
1355 if (tr_cpBlockIsComplete (&tor
->completion
, last
))
1356 total
+= (f
->offset
+ f
->length
) - ((uint64_t)tor
->blockSize
* last
);
1364 tr_torrentFiles (const tr_torrent
* tor
,
1365 tr_file_index_t
* fileCount
)
1368 const tr_file_index_t n
= tor
->info
.fileCount
;
1369 tr_file_stat
* files
= tr_new0 (tr_file_stat
, n
);
1370 tr_file_stat
* walk
= files
;
1371 const bool isSeed
= tor
->completeness
== TR_SEED
;
1373 assert (tr_isTorrent (tor
));
1375 for (i
=0; i
<n
; ++i
, ++walk
) {
1376 const uint64_t b
= isSeed
? tor
->info
.files
[i
].length
: fileBytesCompleted (tor
, i
);
1377 walk
->bytesCompleted
= b
;
1378 walk
->progress
= tor
->info
.files
[i
].length
> 0 ? ((float)b
/ tor
->info
.files
[i
].length
) : 1.0f
;
1388 tr_torrentFilesFree (tr_file_stat
* files
,
1389 tr_file_index_t fileCount UNUSED
)
1399 tr_torrentWebSpeeds_KBps (const tr_torrent
* tor
)
1401 double * ret
= NULL
;
1403 if (tr_isTorrent (tor
))
1405 tr_torrentLock (tor
);
1406 ret
= tr_peerMgrWebSpeeds_KBps (tor
);
1407 tr_torrentUnlock (tor
);
1414 tr_torrentPeers (const tr_torrent
* tor
, int * peerCount
)
1416 tr_peer_stat
* ret
= NULL
;
1418 if (tr_isTorrent (tor
))
1420 tr_torrentLock (tor
);
1421 ret
= tr_peerMgrPeerStats (tor
, peerCount
);
1422 tr_torrentUnlock (tor
);
1429 tr_torrentPeersFree (tr_peer_stat
* peers
, int peerCount UNUSED
)
1435 tr_torrentTrackers (const tr_torrent
* torrent
, int * setmeTrackerCount
)
1437 tr_tracker_stat
* ret
= NULL
;
1439 if (tr_isTorrent (torrent
))
1441 tr_torrentLock (torrent
);
1442 ret
= tr_announcerStats (torrent
, setmeTrackerCount
);
1443 tr_torrentUnlock (torrent
);
1450 tr_torrentTrackersFree (tr_tracker_stat
* trackers
, int trackerCount
)
1452 tr_announcerStatsFree (trackers
, trackerCount
);
1456 tr_torrentAvailability (const tr_torrent
* tor
, int8_t * tab
, int size
)
1458 if (tr_isTorrent (tor
) && (tab
!= NULL
) && (size
> 0))
1460 tr_torrentLock (tor
);
1461 tr_peerMgrTorrentAvailability (tor
, tab
, size
);
1462 tr_torrentUnlock (tor
);
1467 tr_torrentAmountFinished (const tr_torrent
* tor
,
1471 assert (tr_isTorrent (tor
));
1473 tr_torrentLock (tor
);
1474 tr_cpGetAmountDone (&tor
->completion
, tab
, size
);
1475 tr_torrentUnlock (tor
);
1479 tr_torrentResetTransferStats (tr_torrent
* tor
)
1481 tr_torrentLock (tor
);
1483 tor
->downloadedPrev
+= tor
->downloadedCur
;
1484 tor
->downloadedCur
= 0;
1485 tor
->uploadedPrev
+= tor
->uploadedCur
;
1486 tor
->uploadedCur
= 0;
1487 tor
->corruptPrev
+= tor
->corruptCur
;
1488 tor
->corruptCur
= 0;
1490 tr_torrentSetDirty (tor
);
1492 tr_torrentUnlock (tor
);
1496 tr_torrentSetHasPiece (tr_torrent
* tor
,
1497 tr_piece_index_t pieceIndex
,
1500 assert (tr_isTorrent (tor
));
1501 assert (pieceIndex
< tor
->info
.pieceCount
);
1504 tr_cpPieceAdd (&tor
->completion
, pieceIndex
);
1506 tr_cpPieceRem (&tor
->completion
, pieceIndex
);
1514 static bool queueIsSequenced (tr_session
*);
1518 freeTorrent (tr_torrent
* tor
)
1521 tr_session
* session
= tor
->session
;
1522 tr_info
* inf
= &tor
->info
;
1523 const time_t now
= tr_time ();
1525 assert (!tor
->isRunning
);
1527 tr_sessionLock (session
);
1529 tr_peerMgrRemoveTorrent (tor
);
1531 tr_announcerRemoveTorrent (session
->announcer
, tor
);
1533 tr_cpDestruct (&tor
->completion
);
1535 tr_free (tor
->downloadDir
);
1536 tr_free (tor
->incompleteDir
);
1538 if (tor
== session
->torrentList
)
1539 session
->torrentList
= tor
->next
;
1540 else for (t
= session
->torrentList
; t
!= NULL
; t
= t
->next
) {
1541 if (t
->next
== tor
) {
1542 t
->next
= tor
->next
;
1547 /* decrement the torrent count */
1548 assert (session
->torrentCount
>= 1);
1549 session
->torrentCount
--;
1551 /* resequence the queue positions */
1553 while ((t
= tr_torrentNext (session
, t
))) {
1554 if (t
->queuePosition
> tor
->queuePosition
) {
1559 assert (queueIsSequenced (session
));
1561 tr_bandwidthDestruct (&tor
->bandwidth
);
1563 tr_metainfoFree (inf
);
1564 memset (tor
, ~0, sizeof (tr_torrent
));
1567 tr_sessionUnlock (session
);
1571 *** Start/Stop Callback
1574 static void torrentSetQueued (tr_torrent
* tor
, bool queued
);
1577 torrentStartImpl (void * vtor
)
1580 tr_torrent
* tor
= vtor
;
1582 assert (tr_isTorrent (tor
));
1584 tr_sessionLock (tor
->session
);
1586 tr_torrentRecheckCompleteness (tor
);
1587 torrentSetQueued (tor
, false);
1590 tor
->isRunning
= true;
1591 tor
->completeness
= tr_cpGetStatus (&tor
->completion
);
1592 tor
->startDate
= tor
->anyDate
= now
;
1593 tr_torrentClearError (tor
);
1594 tor
->finishedSeedingByIdle
= false;
1596 tr_torrentResetTransferStats (tor
);
1597 tr_announcerTorrentStarted (tor
);
1598 tor
->dhtAnnounceAt
= now
+ tr_cryptoWeakRandInt (20);
1599 tor
->dhtAnnounce6At
= now
+ tr_cryptoWeakRandInt (20);
1600 tor
->lpdAnnounceAt
= now
;
1601 tr_peerMgrStartTorrent (tor
);
1603 tr_sessionUnlock (tor
->session
);
1607 tr_torrentGetCurrentSizeOnDisk (const tr_torrent
* tor
)
1610 uint64_t byte_count
= 0;
1611 const tr_file_index_t n
= tor
->info
.fileCount
;
1616 char * filename
= tr_torrentFindFile (tor
, i
);
1619 if (filename
&& !stat (filename
, &sb
))
1620 byte_count
+= sb
.st_size
;
1629 torrentShouldQueue (const tr_torrent
* tor
)
1631 const tr_direction dir
= tr_torrentGetQueueDirection (tor
);
1633 return tr_sessionCountQueueFreeSlots (tor
->session
, dir
) == 0;
1637 torrentStart (tr_torrent
* tor
, bool bypass_queue
)
1639 switch (torrentGetActivity (tor
))
1641 case TR_STATUS_SEED
:
1642 case TR_STATUS_DOWNLOAD
:
1643 return; /* already started */
1646 case TR_STATUS_SEED_WAIT
:
1647 case TR_STATUS_DOWNLOAD_WAIT
:
1649 return; /* already queued */
1652 case TR_STATUS_CHECK
:
1653 case TR_STATUS_CHECK_WAIT
:
1654 /* verifying right now... wait until that's done so
1655 * we'll know what completeness to use/announce */
1656 tor
->startAfterVerify
= true;
1660 case TR_STATUS_STOPPED
:
1661 if (!bypass_queue
&& torrentShouldQueue (tor
)) {
1662 torrentSetQueued (tor
, true);
1668 /* don't allow the torrent to be started if the files disappeared */
1669 if (setLocalErrorIfFilesDisappeared (tor
))
1672 /* otherwise, start it now... */
1673 tr_sessionLock (tor
->session
);
1675 /* allow finished torrents to be resumed */
1676 if (tr_torrentIsSeedRatioDone (tor
)) {
1677 tr_torinf (tor
, _("Restarted manually -- disabling its seed ratio"));
1678 tr_torrentSetRatioMode (tor
, TR_RATIOLIMIT_UNLIMITED
);
1681 /* corresponds to the peer_id sent as a tracker request parameter.
1682 * one tracker admin says: "When the same torrent is opened and
1683 * closed and opened again without quitting Transmission ...
1684 * change the peerid. It would help sometimes if a stopped event
1685 * was missed to ensure that we didn't think someone was cheating. */
1686 tr_peerIdInit (tor
->peer_id
);
1688 tr_torrentSetDirty (tor
);
1689 tr_runInEventThread (tor
->session
, torrentStartImpl
, tor
);
1691 tr_sessionUnlock (tor
->session
);
1695 tr_torrentStart (tr_torrent
* tor
)
1697 if (tr_isTorrent (tor
))
1698 torrentStart (tor
, false);
1702 tr_torrentStartNow (tr_torrent
* tor
)
1704 if (tr_isTorrent (tor
))
1705 torrentStart (tor
, true);
1709 torrentRecheckDoneImpl (void * vtor
)
1711 tr_torrent
* tor
= vtor
;
1712 assert (tr_isTorrent (tor
));
1714 tr_torrentRecheckCompleteness (tor
);
1716 if (tor
->startAfterVerify
) {
1717 tor
->startAfterVerify
= false;
1718 torrentStart (tor
, false);
1723 torrentRecheckDoneCB (tr_torrent
* tor
)
1725 assert (tr_isTorrent (tor
));
1727 tr_runInEventThread (tor
->session
, torrentRecheckDoneImpl
, tor
);
1731 verifyTorrent (void * vtor
)
1734 tr_torrent
* tor
= vtor
;
1736 tr_sessionLock (tor
->session
);
1738 /* if the torrent's already being verified, stop it */
1739 tr_verifyRemove (tor
);
1741 startAfter
= (tor
->isRunning
|| tor
->startAfterVerify
) && !tor
->isStopping
;
1744 tr_torrentStop (tor
);
1746 tor
->startAfterVerify
= startAfter
;
1748 if (setLocalErrorIfFilesDisappeared (tor
))
1749 tor
->startAfterVerify
= false;
1751 tr_verifyAdd (tor
, torrentRecheckDoneCB
);
1753 tr_sessionUnlock (tor
->session
);
1757 tr_torrentVerify (tr_torrent
* tor
)
1759 if (tr_isTorrent (tor
))
1760 tr_runInEventThread (tor
->session
, verifyTorrent
, tor
);
1764 tr_torrentSave (tr_torrent
* tor
)
1766 assert (tr_isTorrent (tor
));
1770 tor
->isDirty
= false;
1771 tr_torrentSaveResume (tor
);
1776 stopTorrent (void * vtor
)
1778 tr_torrent
* tor
= vtor
;
1779 tr_torinf (tor
, "Pausing");
1781 assert (tr_isTorrent (tor
));
1783 tr_torrentLock (tor
);
1785 tr_verifyRemove (tor
);
1786 torrentSetQueued (tor
, false);
1787 tr_peerMgrStopTorrent (tor
);
1788 tr_announcerTorrentStopped (tor
);
1789 tr_cacheFlushTorrent (tor
->session
->cache
, tor
);
1791 tr_fdTorrentClose (tor
->session
, tor
->uniqueId
);
1793 if (!tor
->isDeleting
)
1794 tr_torrentSave (tor
);
1796 tr_torrentUnlock (tor
);
1800 tr_torrentStop (tr_torrent
* tor
)
1802 assert (tr_isTorrent (tor
));
1804 if (tr_isTorrent (tor
))
1806 tr_sessionLock (tor
->session
);
1809 tor
->isStopping
= 0;
1810 tr_torrentSetDirty (tor
);
1811 tr_runInEventThread (tor
->session
, stopTorrent
, tor
);
1813 tr_sessionUnlock (tor
->session
);
1818 closeTorrent (void * vtor
)
1821 tr_torrent
* tor
= vtor
;
1823 assert (tr_isTorrent (tor
));
1825 d
= tr_bencListAddDict (&tor
->session
->removedTorrents
, 2);
1826 tr_bencDictAddInt (d
, "id", tor
->uniqueId
);
1827 tr_bencDictAddInt (d
, "date", tr_time ());
1829 tr_torinf (tor
, "%s", _("Removing torrent"));
1833 if (tor
->isDeleting
)
1835 tr_metainfoRemoveSaved (tor
->session
, &tor
->info
);
1836 tr_torrentRemoveResume (tor
);
1844 tr_torrentFree (tr_torrent
* tor
)
1846 if (tr_isTorrent (tor
))
1848 tr_session
* session
= tor
->session
;
1849 assert (tr_isSession (session
));
1850 tr_sessionLock (session
);
1852 tr_torrentClearCompletenessCallback (tor
);
1853 tr_runInEventThread (session
, closeTorrent
, tor
);
1855 tr_sessionUnlock (session
);
1863 tr_fileFunc
* deleteFunc
;
1866 static void tr_torrentDeleteLocalData (tr_torrent
*, tr_fileFunc
);
1869 removeTorrent (void * vdata
)
1871 struct remove_data
* data
= vdata
;
1873 if (data
->deleteFlag
)
1874 tr_torrentDeleteLocalData (data
->tor
, data
->deleteFunc
);
1876 tr_torrentClearCompletenessCallback (data
->tor
);
1877 closeTorrent (data
->tor
);
1882 tr_torrentRemove (tr_torrent
* tor
,
1884 tr_fileFunc deleteFunc
)
1886 struct remove_data
* data
;
1888 assert (tr_isTorrent (tor
));
1889 tor
->isDeleting
= 1;
1891 data
= tr_new0 (struct remove_data
, 1);
1893 data
->deleteFlag
= deleteFlag
;
1894 data
->deleteFunc
= deleteFunc
;
1895 tr_runInEventThread (tor
->session
, removeTorrent
, data
);
1903 getCompletionString (int type
)
1907 /* Translators: this is a minor point that's safe to skip over, but FYI:
1908 "Complete" and "Done" are specific, different terms in Transmission:
1909 "Complete" means we've downloaded every file in the torrent.
1910 "Done" means we're done downloading the files we wanted, but NOT all
1912 case TR_PARTIAL_SEED
:
1916 return _("Complete");
1919 return _("Incomplete");
1924 fireCompletenessChange (tr_torrent
* tor
,
1925 tr_completeness status
,
1928 assert ((status
== TR_LEECH
)
1929 || (status
== TR_SEED
)
1930 || (status
== TR_PARTIAL_SEED
));
1932 if (tor
->completeness_func
)
1933 tor
->completeness_func (tor
, status
, wasRunning
,
1934 tor
->completeness_func_user_data
);
1938 tr_torrentSetCompletenessCallback (tr_torrent
* tor
,
1939 tr_torrent_completeness_func func
,
1942 assert (tr_isTorrent (tor
));
1944 tor
->completeness_func
= func
;
1945 tor
->completeness_func_user_data
= user_data
;
1949 tr_torrentClearCompletenessCallback (tr_torrent
* torrent
)
1951 tr_torrentSetCompletenessCallback (torrent
, NULL
, NULL
);
1955 tr_torrentSetRatioLimitHitCallback (tr_torrent
* tor
,
1956 tr_torrent_ratio_limit_hit_func func
,
1959 assert (tr_isTorrent (tor
));
1961 tor
->ratio_limit_hit_func
= func
;
1962 tor
->ratio_limit_hit_func_user_data
= user_data
;
1966 tr_torrentClearRatioLimitHitCallback (tr_torrent
* torrent
)
1968 tr_torrentSetRatioLimitHitCallback (torrent
, NULL
, NULL
);
1972 tr_torrentSetIdleLimitHitCallback (tr_torrent
* tor
,
1973 tr_torrent_idle_limit_hit_func func
,
1976 assert (tr_isTorrent (tor
));
1978 tor
->idle_limit_hit_func
= func
;
1979 tor
->idle_limit_hit_func_user_data
= user_data
;
1983 tr_torrentClearIdleLimitHitCallback (tr_torrent
* torrent
)
1985 tr_torrentSetIdleLimitHitCallback (torrent
, NULL
, NULL
);
1989 onSigCHLD (int i UNUSED
)
1991 waitpid (-1, NULL
, WNOHANG
);
1995 torrentCallScript (const tr_torrent
* tor
, const char * script
)
1998 const time_t now
= tr_time ();
2000 tr_strlcpy (timeStr
, ctime (&now
), sizeof (timeStr
));
2001 *strchr (timeStr
,'\n') = '\0';
2003 if (script
&& *script
)
2006 char * cmd
[] = { tr_strdup (script
), NULL
};
2008 tr_strdup_printf ("TR_APP_VERSION=%s", SHORT_VERSION_STRING
),
2009 tr_strdup_printf ("TR_TIME_LOCALTIME=%s", timeStr
),
2010 tr_strdup_printf ("TR_TORRENT_DIR=%s", tor
->currentDir
),
2011 tr_strdup_printf ("TR_TORRENT_ID=%d", tr_torrentId (tor
)),
2012 tr_strdup_printf ("TR_TORRENT_HASH=%s", tor
->info
.hashString
),
2013 tr_strdup_printf ("TR_TORRENT_NAME=%s", tr_torrentName (tor
)),
2016 tr_torinf (tor
, "Calling script \"%s\"", script
);
2019 if (_spawnvpe (_P_NOWAIT
, script
, (const char*)cmd
, env
) == -1)
2020 tr_torerr (tor
, "error executing script \"%s\": %s", cmd
[0], tr_strerror (errno
));
2022 signal (SIGCHLD
, onSigCHLD
);
2026 for (i
=0; env
[i
]; ++i
)
2029 if (execvp (script
, cmd
) == -1)
2030 tr_torerr (tor
, "error executing script \"%s\": %s", cmd
[0], tr_strerror (errno
));
2036 for (i
=0; cmd
[i
]; ++i
) tr_free (cmd
[i
]);
2037 for (i
=0; env
[i
]; ++i
) tr_free (env
[i
]);
2042 tr_torrentRecheckCompleteness (tr_torrent
* tor
)
2044 tr_completeness completeness
;
2046 assert (tr_isTorrent (tor
));
2048 tr_torrentLock (tor
);
2050 completeness
= tr_cpGetStatus (&tor
->completion
);
2052 if (completeness
!= tor
->completeness
)
2054 const int recentChange
= tor
->downloadedCur
!= 0;
2055 const bool wasLeeching
= !tr_torrentIsSeed (tor
);
2056 const bool wasRunning
= tor
->isRunning
;
2060 tr_torinf (tor
, _("State changed from \"%1$s\" to \"%2$s\""),
2061 getCompletionString (tor
->completeness
),
2062 getCompletionString (completeness
));
2065 tor
->completeness
= completeness
;
2066 tr_fdTorrentClose (tor
->session
, tor
->uniqueId
);
2068 fireCompletenessChange (tor
, completeness
, wasRunning
);
2070 if (tr_torrentIsSeed (tor
))
2074 tr_announcerTorrentCompleted (tor
);
2075 tor
->doneDate
= tor
->anyDate
= tr_time ();
2078 if (wasLeeching
&& wasRunning
)
2080 /* clear interested flag on all peers */
2081 tr_peerMgrClearInterest (tor
);
2083 /* if completeness was TR_LEECH then the seed limit check will have been skipped in bandwidthPulse */
2084 tr_torrentCheckSeedLimit (tor
);
2087 if (tor
->currentDir
== tor
->incompleteDir
)
2088 tr_torrentSetLocation (tor
, tor
->downloadDir
, true, NULL
, NULL
);
2090 if (tr_sessionIsTorrentDoneScriptEnabled (tor
->session
))
2091 torrentCallScript (tor
, tr_sessionGetTorrentDoneScript (tor
->session
));
2094 tr_torrentSetDirty (tor
);
2097 tr_torrentUnlock (tor
);
2105 tr_torrentFireMetadataCompleted (tr_torrent
* tor
)
2107 assert (tr_isTorrent (tor
));
2109 if (tor
->metadata_func
)
2110 tor
->metadata_func (tor
, tor
->metadata_func_user_data
);
2114 tr_torrentSetMetadataCallback (tr_torrent
* tor
,
2115 tr_torrent_metadata_func func
,
2118 assert (tr_isTorrent (tor
));
2120 tor
->metadata_func
= func
;
2121 tor
->metadata_func_user_data
= user_data
;
2130 tr_torrentInitFilePriority (tr_torrent
* tor
,
2131 tr_file_index_t fileIndex
,
2132 tr_priority_t priority
)
2137 assert (tr_isTorrent (tor
));
2138 assert (fileIndex
< tor
->info
.fileCount
);
2139 assert (tr_isPriority (priority
));
2141 file
= &tor
->info
.files
[fileIndex
];
2142 file
->priority
= priority
;
2143 for (i
= file
->firstPiece
; i
<= file
->lastPiece
; ++i
)
2144 tor
->info
.pieces
[i
].priority
= calculatePiecePriority (tor
, i
, fileIndex
);
2148 tr_torrentSetFilePriorities (tr_torrent
* tor
,
2149 const tr_file_index_t
* files
,
2150 tr_file_index_t fileCount
,
2151 tr_priority_t priority
)
2154 assert (tr_isTorrent (tor
));
2155 tr_torrentLock (tor
);
2157 for (i
= 0; i
< fileCount
; ++i
)
2158 if (files
[i
] < tor
->info
.fileCount
)
2159 tr_torrentInitFilePriority (tor
, files
[i
], priority
);
2160 tr_torrentSetDirty (tor
);
2161 tr_peerMgrRebuildRequests (tor
);
2163 tr_torrentUnlock (tor
);
2167 tr_torrentGetFilePriorities (const tr_torrent
* tor
)
2172 assert (tr_isTorrent (tor
));
2174 tr_torrentLock (tor
);
2175 p
= tr_new0 (tr_priority_t
, tor
->info
.fileCount
);
2176 for (i
= 0; i
< tor
->info
.fileCount
; ++i
)
2177 p
[i
] = tor
->info
.files
[i
].priority
;
2178 tr_torrentUnlock (tor
);
2188 setFileDND (tr_torrent
* tor
, tr_file_index_t fileIndex
, int doDownload
)
2190 const int8_t dnd
= !doDownload
;
2191 tr_piece_index_t firstPiece
;
2192 int8_t firstPieceDND
;
2193 tr_piece_index_t lastPiece
;
2194 int8_t lastPieceDND
;
2196 tr_file
* file
= &tor
->info
.files
[fileIndex
];
2199 firstPiece
= file
->firstPiece
;
2200 lastPiece
= file
->lastPiece
;
2202 /* can't set the first piece to DND unless
2203 every file using that piece is DND */
2204 firstPieceDND
= dnd
;
2207 for (i
= fileIndex
- 1; firstPieceDND
; --i
)
2209 if (tor
->info
.files
[i
].lastPiece
!= firstPiece
)
2211 firstPieceDND
= tor
->info
.files
[i
].dnd
;
2217 /* can't set the last piece to DND unless
2218 every file using that piece is DND */
2220 for (i
= fileIndex
+ 1; lastPieceDND
&& i
< tor
->info
.fileCount
; ++i
)
2222 if (tor
->info
.files
[i
].firstPiece
!= lastPiece
)
2224 lastPieceDND
= tor
->info
.files
[i
].dnd
;
2227 if (firstPiece
== lastPiece
)
2229 tor
->info
.pieces
[firstPiece
].dnd
= firstPieceDND
&& lastPieceDND
;
2233 tr_piece_index_t pp
;
2234 tor
->info
.pieces
[firstPiece
].dnd
= firstPieceDND
;
2235 tor
->info
.pieces
[lastPiece
].dnd
= lastPieceDND
;
2236 for (pp
= firstPiece
+ 1; pp
< lastPiece
; ++pp
)
2237 tor
->info
.pieces
[pp
].dnd
= dnd
;
2242 tr_torrentInitFileDLs (tr_torrent
* tor
,
2243 const tr_file_index_t
* files
,
2244 tr_file_index_t fileCount
,
2249 assert (tr_isTorrent (tor
));
2251 tr_torrentLock (tor
);
2253 for (i
=0; i
<fileCount
; ++i
)
2254 if (files
[i
] < tor
->info
.fileCount
)
2255 setFileDND (tor
, files
[i
], doDownload
);
2257 tr_cpInvalidateDND (&tor
->completion
);
2259 tr_torrentUnlock (tor
);
2263 tr_torrentSetFileDLs (tr_torrent
* tor
,
2264 const tr_file_index_t
* files
,
2265 tr_file_index_t fileCount
,
2268 assert (tr_isTorrent (tor
));
2269 tr_torrentLock (tor
);
2271 tr_torrentInitFileDLs (tor
, files
, fileCount
, doDownload
);
2272 tr_torrentSetDirty (tor
);
2273 tr_peerMgrRebuildRequests (tor
);
2275 tr_torrentUnlock (tor
);
2283 tr_torrentGetPriority (const tr_torrent
* tor
)
2285 assert (tr_isTorrent (tor
));
2287 return tor
->bandwidth
.priority
;
2291 tr_torrentSetPriority (tr_torrent
* tor
, tr_priority_t priority
)
2293 assert (tr_isTorrent (tor
));
2294 assert (tr_isPriority (priority
));
2296 if (tor
->bandwidth
.priority
!= priority
)
2298 tor
->bandwidth
.priority
= priority
;
2300 tr_torrentSetDirty (tor
);
2309 tr_torrentSetPeerLimit (tr_torrent
* tor
,
2310 uint16_t maxConnectedPeers
)
2312 assert (tr_isTorrent (tor
));
2314 if (tor
->maxConnectedPeers
!= maxConnectedPeers
)
2316 tor
->maxConnectedPeers
= maxConnectedPeers
;
2318 tr_torrentSetDirty (tor
);
2323 tr_torrentGetPeerLimit (const tr_torrent
* tor
)
2325 assert (tr_isTorrent (tor
));
2327 return tor
->maxConnectedPeers
;
2335 tr_torrentGetBlockLocation (const tr_torrent
* tor
,
2336 tr_block_index_t block
,
2337 tr_piece_index_t
* piece
,
2341 uint64_t pos
= block
;
2342 pos
*= tor
->blockSize
;
2343 *piece
= pos
/ tor
->info
.pieceSize
;
2344 *offset
= pos
- (*piece
* tor
->info
.pieceSize
);
2345 *length
= tr_torBlockCountBytes (tor
, block
);
2350 _tr_block (const tr_torrent
* tor
,
2351 tr_piece_index_t index
,
2354 tr_block_index_t ret
;
2356 assert (tr_isTorrent (tor
));
2359 ret
*= (tor
->info
.pieceSize
/ tor
->blockSize
);
2360 ret
+= offset
/ tor
->blockSize
;
2365 tr_torrentReqIsValid (const tr_torrent
* tor
,
2366 tr_piece_index_t index
,
2372 assert (tr_isTorrent (tor
));
2374 if (index
>= tor
->info
.pieceCount
)
2376 else if (length
< 1)
2378 else if ((offset
+ length
) > tr_torPieceCountBytes (tor
, index
))
2380 else if (length
> MAX_BLOCK_SIZE
)
2382 else if (tr_pieceOffset (tor
, index
, offset
, length
) > tor
->info
.totalSize
)
2385 if (err
) tr_tordbg (tor
, "index %lu offset %lu length %lu err %d\n",
2386 (unsigned long)index
,
2387 (unsigned long)offset
,
2388 (unsigned long)length
,
2395 tr_pieceOffset (const tr_torrent
* tor
,
2396 tr_piece_index_t index
,
2402 assert (tr_isTorrent (tor
));
2404 ret
= tor
->info
.pieceSize
;
2412 tr_torGetFileBlockRange (const tr_torrent
* tor
,
2413 const tr_file_index_t file
,
2414 tr_block_index_t
* first
,
2415 tr_block_index_t
* last
)
2417 const tr_file
* f
= &tor
->info
.files
[file
];
2418 uint64_t offset
= f
->offset
;
2419 *first
= offset
/ tor
->blockSize
;
2423 offset
+= f
->length
- 1;
2424 *last
= offset
/ tor
->blockSize
;
2429 tr_torGetPieceBlockRange (const tr_torrent
* tor
,
2430 const tr_piece_index_t piece
,
2431 tr_block_index_t
* first
,
2432 tr_block_index_t
* last
)
2434 uint64_t offset
= tor
->info
.pieceSize
;
2436 *first
= offset
/ tor
->blockSize
;
2437 offset
+= (tr_torPieceCountBytes (tor
, piece
) - 1);
2438 *last
= offset
/ tor
->blockSize
;
2447 tr_torrentSetPieceChecked (tr_torrent
* tor
, tr_piece_index_t pieceIndex
)
2449 assert (tr_isTorrent (tor
));
2450 assert (pieceIndex
< tor
->info
.pieceCount
);
2452 tor
->info
.pieces
[pieceIndex
].timeChecked
= tr_time ();
2456 tr_torrentSetChecked (tr_torrent
* tor
, time_t when
)
2458 tr_piece_index_t i
, n
;
2460 assert (tr_isTorrent (tor
));
2462 for (i
=0, n
=tor
->info
.pieceCount
; i
!=n
; ++i
)
2463 tor
->info
.pieces
[i
].timeChecked
= when
;
2467 tr_torrentCheckPiece (tr_torrent
* tor
, tr_piece_index_t pieceIndex
)
2469 const bool pass
= tr_ioTestPiece (tor
, pieceIndex
);
2471 tr_deeplog_tor (tor
, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex
, (int)pass
);
2472 tr_torrentSetHasPiece (tor
, pieceIndex
, pass
);
2473 tr_torrentSetPieceChecked (tor
, pieceIndex
);
2474 tor
->anyDate
= tr_time ();
2475 tr_torrentSetDirty (tor
);
2481 tr_torrentGetFileMTime (const tr_torrent
* tor
, tr_file_index_t i
)
2484 if (!tr_fdFileGetCachedMTime (tor
->session
, tor
->uniqueId
, i
, &mtime
))
2485 tr_torrentFindFile2 (tor
, i
, NULL
, NULL
, &mtime
);
2490 tr_torrentPieceNeedsCheck (const tr_torrent
* tor
, tr_piece_index_t p
)
2494 const tr_info
* inf
= tr_torrentInfo (tor
);
2496 /* if we've never checked this piece, then it needs to be checked */
2497 if (!inf
->pieces
[p
].timeChecked
)
2500 /* If we think we've completed one of the files in this piece,
2501 * but it's been modified since we last checked it,
2502 * then it needs to be rechecked */
2503 tr_ioFindFileLocation (tor
, p
, 0, &f
, &unused
);
2504 for (; f
< inf
->fileCount
&& pieceHasFile (p
, &inf
->files
[f
]); ++f
)
2505 if (tr_cpFileIsComplete (&tor
->completion
, f
))
2506 if (tr_torrentGetFileMTime (tor
, f
) > inf
->pieces
[p
].timeChecked
)
2517 compareTrackerByTier (const void * va
, const void * vb
)
2519 const tr_tracker_info
* a
= va
;
2520 const tr_tracker_info
* b
= vb
;
2523 if (a
->tier
!= b
->tier
)
2524 return a
->tier
- b
->tier
;
2526 /* get the effects of a stable sort by comparing the two elements' addresses */
2531 tr_torrentSetAnnounceList (tr_torrent
* tor
,
2532 const tr_tracker_info
* trackers_in
,
2538 tr_tracker_info
* trackers
;
2540 tr_torrentLock (tor
);
2542 assert (tr_isTorrent (tor
));
2544 /* ensure the trackers' tiers are in ascending order */
2545 trackers
= tr_memdup (trackers_in
, sizeof (tr_tracker_info
) * trackerCount
);
2546 qsort (trackers
, trackerCount
, sizeof (tr_tracker_info
), compareTrackerByTier
);
2548 /* look for bad URLs */
2549 for (i
=0; ok
&& i
<trackerCount
; ++i
)
2550 if (!tr_urlIsValidTracker (trackers
[i
].announce
))
2553 /* save to the .torrent file */
2554 if (ok
&& !tr_bencLoadFile (&metainfo
, TR_FMT_BENC
, tor
->info
.torrent
))
2559 /* remove the old fields */
2560 tr_bencDictRemove (&metainfo
, "announce");
2561 tr_bencDictRemove (&metainfo
, "announce-list");
2563 /* add the new fields */
2564 if (trackerCount
> 0)
2566 tr_bencDictAddStr (&metainfo
, "announce", trackers
[0].announce
);
2568 if (trackerCount
> 1)
2572 tr_benc
* tier
= NULL
;
2573 tr_benc
* announceList
= tr_bencDictAddList (&metainfo
, "announce-list", 0);
2575 for (i
=0; i
<trackerCount
; ++i
) {
2576 if (prevTier
!= trackers
[i
].tier
) {
2577 prevTier
= trackers
[i
].tier
;
2578 tier
= tr_bencListAddList (announceList
, 0);
2580 tr_bencListAddStr (tier
, trackers
[i
].announce
);
2584 /* try to parse it back again, to make sure it's good */
2585 memset (&tmpInfo
, 0, sizeof (tr_info
));
2586 if (tr_metainfoParse (tor
->session
, &metainfo
, &tmpInfo
,
2587 &hasInfo
, &tor
->infoDictLength
))
2589 /* it's good, so keep these new trackers and free the old ones */
2592 swap
.trackers
= tor
->info
.trackers
;
2593 swap
.trackerCount
= tor
->info
.trackerCount
;
2594 tor
->info
.trackers
= tmpInfo
.trackers
;
2595 tor
->info
.trackerCount
= tmpInfo
.trackerCount
;
2596 tmpInfo
.trackers
= swap
.trackers
;
2597 tmpInfo
.trackerCount
= swap
.trackerCount
;
2599 tr_metainfoFree (&tmpInfo
);
2600 tr_bencToFile (&metainfo
, TR_FMT_BENC
, tor
->info
.torrent
);
2604 tr_bencFree (&metainfo
);
2606 /* if we had a tracker-related error on this torrent,
2607 * and that tracker's been removed,
2608 * then clear the error */
2609 if ((tor
->error
== TR_STAT_TRACKER_WARNING
)
2610 || (tor
->error
== TR_STAT_TRACKER_ERROR
))
2614 for (i
=0; clear
&& i
<trackerCount
; ++i
)
2615 if (!strcmp (trackers
[i
].announce
, tor
->errorTracker
))
2619 tr_torrentClearError (tor
);
2622 /* tell the announcer to reload this torrent's tracker list */
2623 tr_announcerResetTorrent (tor
->session
->announcer
, tor
);
2626 tr_torrentUnlock (tor
);
2637 tr_torrentSetAddedDate (tr_torrent
* tor
,
2640 assert (tr_isTorrent (tor
));
2643 tor
->anyDate
= MAX (tor
->anyDate
, tor
->addedDate
);
2647 tr_torrentSetActivityDate (tr_torrent
* tor
, time_t t
)
2649 assert (tr_isTorrent (tor
));
2651 tor
->activityDate
= t
;
2652 tor
->anyDate
= MAX (tor
->anyDate
, tor
->activityDate
);
2656 tr_torrentSetDoneDate (tr_torrent
* tor
,
2659 assert (tr_isTorrent (tor
));
2662 tor
->anyDate
= MAX (tor
->anyDate
, tor
->doneDate
);
2670 tr_torrentGetBytesLeftToAllocate (const tr_torrent
* tor
)
2673 uint64_t bytesLeft
= 0;
2675 assert (tr_isTorrent (tor
));
2677 for (i
=0; i
<tor
->info
.fileCount
; ++i
)
2679 if (!tor
->info
.files
[i
].dnd
)
2682 const uint64_t length
= tor
->info
.files
[i
].length
;
2683 char * path
= tr_torrentFindFile (tor
, i
);
2685 bytesLeft
+= length
;
2687 if ((path
!= NULL
) && !stat (path
, &sb
)
2688 && S_ISREG (sb
.st_mode
)
2689 && ((uint64_t)sb
.st_size
<= length
))
2690 bytesLeft
-= sb
.st_size
;
2700 ***** Removing the torrent's local data
2704 isJunkFile (const char * base
)
2707 static const char * files
[] = { ".DS_Store", "desktop.ini", "Thumbs.db" };
2708 static const int file_count
= sizeof (files
) / sizeof (files
[0]);
2710 for (i
=0; i
<file_count
; ++i
)
2711 if (!strcmp (base
, files
[i
]))
2715 /* check for resource forks. <http://support.apple.com/kb/TA20578> */
2716 if (!memcmp (base
, "._", 2))
2724 removeEmptyFoldersAndJunkFiles (const char * folder
)
2727 if ((odir
= opendir (folder
))) {
2729 while ((d
= readdir (odir
))) {
2730 if (strcmp (d
->d_name
, ".") && strcmp (d
->d_name
, "..")) {
2732 char * filename
= tr_buildPath (folder
, d
->d_name
, NULL
);
2733 if (!stat (filename
, &sb
) && S_ISDIR (sb
.st_mode
))
2734 removeEmptyFoldersAndJunkFiles (filename
);
2735 else if (isJunkFile (d
->d_name
))
2746 * This convoluted code does something (seemingly) simple:
2747 * remove the torrent's local files.
2749 * Fun complications:
2750 * 1. Try to preserve the directory hierarchy in the recycle bin.
2751 * 2. If there are nontorrent files, don't delete them...
2752 * 3. ...unless the other files are "junk", such as .DS_Store
2755 deleteLocalData (tr_torrent
* tor
, tr_fileFunc func
)
2761 char * tmpdir
= NULL
;
2762 tr_ptrArray files
= TR_PTR_ARRAY_INIT
;
2763 tr_ptrArray folders
= TR_PTR_ARRAY_INIT
;
2764 const void * const vstrcmp
= strcmp
;
2765 const char * const top
= tor
->currentDir
;
2767 /* if it's a magnet link, there's nothing to move... */
2768 if (!tr_torrentHasMetadata (tor
))
2772 **** Move the local data to a new tmpdir
2775 base
= tr_strdup_printf ("%s__XXXXXX", tr_torrentName (tor
));
2776 tmpdir
= tr_buildPath (top
, base
, NULL
);
2777 tr_mkdtemp (tmpdir
);
2780 for (f
=0; f
<tor
->info
.fileCount
; ++f
)
2782 char * filename
= tr_buildPath (top
, tor
->info
.files
[f
].name
, NULL
);
2783 if (!tr_fileExists (filename
, NULL
)) {
2784 char * partial
= tr_torrentBuildPartial (tor
, f
);
2786 filename
= tr_buildPath (top
, partial
, NULL
);
2788 if (!tr_fileExists (filename
, NULL
)) {
2794 if (filename
!= NULL
)
2796 char * target
= tr_buildPath (tmpdir
, tor
->info
.files
[f
].name
, NULL
);
2797 char * target_dir
= tr_dirname (target
);
2798 tr_mkdirp (target_dir
, 0777);
2799 rename (filename
, target
);
2800 tr_ptrArrayAppend (&files
, target
);
2801 tr_free (target_dir
);
2809 **** Try deleting the top-level files & folders to preserve
2810 **** the directory hierarchy in the recycle bin.
2811 **** If case that fails -- for example, rmdir () doesn't
2812 **** delete nonempty folders -- go from the bottom up too.
2815 /* try deleting the local data's top-level files & folders */
2816 if ((odir
= opendir (tmpdir
)))
2819 while ((d
= readdir (odir
)))
2821 if (strcmp (d
->d_name
, ".") && strcmp (d
->d_name
, ".."))
2823 char * file
= tr_buildPath (tmpdir
, d
->d_name
, NULL
);
2831 /* go from the bottom up */
2832 for (i
=0, n
=tr_ptrArraySize (&files
); i
<n
; ++i
)
2834 char * walk
= tr_strdup (tr_ptrArrayNth (&files
, i
));
2835 while (tr_fileExists (walk
, NULL
) && !tr_is_same_file (tmpdir
, walk
))
2837 char * tmp
= tr_dirname (walk
);
2846 **** The local data has been removed.
2847 **** What's left in top are empty folders, junk, and user-generated files.
2848 **** Remove the first two categories and leave the third.
2851 /* build a list of 'top's child directories that belong to this torrent */
2852 for (f
=0; f
<tor
->info
.fileCount
; ++f
)
2854 /* get the directory that this file goes in... */
2855 char * filename
= tr_buildPath (top
, tor
->info
.files
[f
].name
, NULL
);
2856 char * dir
= tr_dirname (filename
);
2857 if (!tr_is_same_file (top
, dir
) && strcmp (top
, dir
)) {
2859 char * parent
= tr_dirname (dir
);
2860 if (tr_is_same_file (top
, parent
) || !strcmp (top
, parent
)) {
2861 if (tr_ptrArrayFindSorted (&folders
, dir
, vstrcmp
) == NULL
) {
2862 tr_ptrArrayInsertSorted (&folders
, tr_strdup (dir
), vstrcmp
);
2873 for (i
=0, n
=tr_ptrArraySize (&folders
); i
<n
; ++i
)
2874 removeEmptyFoldersAndJunkFiles (tr_ptrArrayNth (&folders
, i
));
2879 tr_ptrArrayDestruct (&folders
, tr_free
);
2880 tr_ptrArrayDestruct (&files
, tr_free
);
2884 tr_torrentDeleteLocalData (tr_torrent
* tor
, tr_fileFunc func
)
2886 assert (tr_isTorrent (tor
));
2891 /* close all the files because we're about to delete them */
2892 tr_cacheFlushTorrent (tor
->session
->cache
, tor
);
2893 tr_fdTorrentClose (tor
->session
, tor
->uniqueId
);
2895 deleteLocalData (tor
, func
);
2904 bool move_from_old_location
;
2905 volatile int * setme_state
;
2906 volatile double * setme_progress
;
2912 setLocation (void * vdata
)
2915 struct LocationData
* data
= vdata
;
2916 tr_torrent
* tor
= data
->tor
;
2917 const bool do_move
= data
->move_from_old_location
;
2918 const char * location
= data
->location
;
2919 double bytesHandled
= 0;
2921 assert (tr_isTorrent (tor
));
2923 tr_dbg ("Moving \"%s\" location from currentDir \"%s\" to \"%s\"",
2924 tr_torrentName (tor
), tor
->currentDir
, location
);
2926 tr_mkdirp (location
, 0777);
2928 if (!tr_is_same_file (location
, tor
->currentDir
))
2932 /* bad idea to move files while they're being verified... */
2933 tr_verifyRemove (tor
);
2935 /* try to move the files.
2936 * FIXME: there are still all kinds of nasty cases, like what
2937 * if the target directory runs out of space halfway through... */
2938 for (i
=0; !err
&& i
<tor
->info
.fileCount
; ++i
)
2940 const tr_file
* f
= &tor
->info
.files
[i
];
2941 const char * oldbase
;
2943 if (tr_torrentFindFile2 (tor
, i
, &oldbase
, &sub
, NULL
))
2945 char * oldpath
= tr_buildPath (oldbase
, sub
, NULL
);
2946 char * newpath
= tr_buildPath (location
, sub
, NULL
);
2948 tr_dbg ("Found file #%d: %s", (int)i
, oldpath
);
2950 if (do_move
&& !tr_is_same_file (oldpath
, newpath
))
2952 bool renamed
= false;
2954 tr_torinf (tor
, "moving \"%s\" to \"%s\"", oldpath
, newpath
);
2955 if (tr_moveFile (oldpath
, newpath
, &renamed
))
2958 tr_torerr (tor
, "error moving \"%s\" to \"%s\": %s",
2959 oldpath
, newpath
, tr_strerror (errno
));
2968 if (data
->setme_progress
)
2970 bytesHandled
+= f
->length
;
2971 *data
->setme_progress
= bytesHandled
/ tor
->info
.totalSize
;
2977 /* blow away the leftover subdirectories in the old location */
2979 tr_torrentDeleteLocalData (tor
, remove
);
2981 /* set the new location and reverify */
2982 tr_torrentSetDownloadDir (tor
, location
);
2986 if (!err
&& do_move
)
2988 tr_free (tor
->incompleteDir
);
2989 tor
->incompleteDir
= NULL
;
2990 tor
->currentDir
= tor
->downloadDir
;
2993 if (data
->setme_state
)
2994 *data
->setme_state
= err
? TR_LOC_ERROR
: TR_LOC_DONE
;
2997 tr_free (data
->location
);
3002 tr_torrentSetLocation (tr_torrent
* tor
,
3003 const char * location
,
3004 bool move_from_old_location
,
3005 volatile double * setme_progress
,
3006 volatile int * setme_state
)
3008 struct LocationData
* data
;
3010 assert (tr_isTorrent (tor
));
3013 *setme_state
= TR_LOC_MOVING
;
3015 *setme_progress
= 0;
3017 /* run this in the libtransmission thread */
3018 data
= tr_new (struct LocationData
, 1);
3020 data
->location
= tr_strdup (location
);
3021 data
->move_from_old_location
= move_from_old_location
;
3022 data
->setme_state
= setme_state
;
3023 data
->setme_progress
= setme_progress
;
3024 tr_runInEventThread (tor
->session
, setLocation
, data
);
3032 tr_torrentFileCompleted (tr_torrent
* tor
, tr_file_index_t fileNum
)
3036 const tr_info
* inf
= &tor
->info
;
3037 const tr_file
* f
= &inf
->files
[fileNum
];
3039 const tr_piece
* pend
;
3040 const time_t now
= tr_time ();
3042 /* close the file so that we can reopen in read-only mode as needed */
3043 tr_fdFileClose (tor
->session
, tor
, fileNum
);
3045 /* now that the file is complete and closed, we can start watching its
3046 * mtime timestamp for changes to know if we need to reverify pieces */
3047 for (p
=&inf
->pieces
[f
->firstPiece
], pend
=&inf
->pieces
[f
->lastPiece
]; p
!=pend
; ++p
)
3048 p
->timeChecked
= now
;
3050 /* if the torrent's current filename isn't the same as the one in the
3051 * metadata -- for example, if it had the ".part" suffix appended to
3052 * it until now -- then rename it to match the one in the metadata */
3053 if (tr_torrentFindFile2 (tor
, fileNum
, &base
, &sub
, NULL
))
3055 if (strcmp (sub
, f
->name
))
3057 char * oldpath
= tr_buildPath (base
, sub
, NULL
);
3058 char * newpath
= tr_buildPath (base
, f
->name
, NULL
);
3060 if (rename (oldpath
, newpath
))
3061 tr_torerr (tor
, "Error moving \"%s\" to \"%s\": %s", oldpath
, newpath
, tr_strerror (errno
));
3076 tr_torrentFindFile2 (const tr_torrent
* tor
, tr_file_index_t fileNum
,
3077 const char ** base
, char ** subpath
, time_t * mtime
)
3080 const tr_file
* file
;
3081 const char * b
= NULL
;
3082 const char * s
= NULL
;
3084 assert (tr_isTorrent (tor
));
3085 assert (fileNum
< tor
->info
.fileCount
);
3087 file
= &tor
->info
.files
[fileNum
];
3090 char * filename
= tr_buildPath (tor
->downloadDir
, file
->name
, NULL
);
3091 if (tr_fileExists (filename
, mtime
)) {
3092 b
= tor
->downloadDir
;
3098 if ((b
== NULL
) && (tor
->incompleteDir
!= NULL
)) {
3099 char * filename
= tr_buildPath (tor
->incompleteDir
, file
->name
, NULL
);
3100 if (tr_fileExists (filename
, mtime
)) {
3101 b
= tor
->incompleteDir
;
3108 part
= tr_torrentBuildPartial (tor
, fileNum
);
3110 if ((b
== NULL
) && (tor
->incompleteDir
!= NULL
)) {
3111 char * filename
= tr_buildPath (tor
->incompleteDir
, part
, NULL
);
3112 if (tr_fileExists (filename
, mtime
)) {
3113 b
= tor
->incompleteDir
;
3120 char * filename
= tr_buildPath (tor
->downloadDir
, part
, NULL
);
3121 if (tr_fileExists (filename
, mtime
)) {
3122 b
= tor
->downloadDir
;
3130 if (subpath
!= NULL
)
3131 *subpath
= tr_strdup (s
);
3138 tr_torrentFindFile (const tr_torrent
* tor
, tr_file_index_t fileNum
)
3144 if (tr_torrentFindFile2 (tor
, fileNum
, &base
, &subpath
, NULL
))
3146 ret
= tr_buildPath (base
, subpath
, NULL
);
3153 /* Decide whether we should be looking for files in downloadDir or incompleteDir. */
3155 refreshCurrentDir (tr_torrent
* tor
)
3157 const char * dir
= NULL
;
3159 if (tor
->incompleteDir
== NULL
)
3160 dir
= tor
->downloadDir
;
3161 else if (!tr_torrentHasMetadata (tor
)) /* no files to find */
3162 dir
= tor
->incompleteDir
;
3163 else if (!tr_torrentFindFile2 (tor
, 0, &dir
, NULL
, NULL
))
3164 dir
= tor
->incompleteDir
;
3166 assert (dir
!= NULL
);
3167 assert ((dir
== tor
->downloadDir
) || (dir
== tor
->incompleteDir
));
3168 tor
->currentDir
= dir
;
3172 tr_torrentBuildPartial (const tr_torrent
* tor
, tr_file_index_t fileNum
)
3174 return tr_strdup_printf ("%s.part", tor
->info
.files
[fileNum
].name
);
3182 compareTorrentByQueuePosition (const void * va
, const void * vb
)
3184 const tr_torrent
* a
= * (const tr_torrent
**) va
;
3185 const tr_torrent
* b
= * (const tr_torrent
**) vb
;
3187 return a
->queuePosition
- b
->queuePosition
;
3192 queueIsSequenced (tr_session
* session
)
3196 bool is_sequenced
= true;
3198 tr_torrent
** tmp
= tr_new (tr_torrent
*, session
->torrentCount
);
3200 /* get all the torrents */
3203 while ((tor
= tr_torrentNext (session
, tor
)))
3206 /* sort them by position */
3207 qsort (tmp
, n
, sizeof (tr_torrent
*), compareTorrentByQueuePosition
);
3210 fprintf (stderr
, "%s", "queue: ");
3212 fprintf (stderr
, "%d ", tmp
[i
]->queuePosition
);
3213 fputc ('\n', stderr
);
3217 for (i
=0; is_sequenced
&& i
<n
; ++i
)
3218 if (tmp
[i
]->queuePosition
!= i
)
3219 is_sequenced
= false;
3222 return is_sequenced
;
3227 tr_torrentGetQueuePosition (const tr_torrent
* tor
)
3229 return tor
->queuePosition
;
3233 tr_torrentSetQueuePosition (tr_torrent
* tor
, int pos
)
3237 const int old_pos
= tor
->queuePosition
;
3238 const time_t now
= tr_time ();
3243 tor
->queuePosition
= -1;
3246 while ((walk
= tr_torrentNext (tor
->session
, walk
)))
3248 if (old_pos
< pos
) {
3249 if ((old_pos
<= walk
->queuePosition
) && (walk
->queuePosition
<= pos
)) {
3250 walk
->queuePosition
--;
3251 walk
->anyDate
= now
;
3255 if (old_pos
> pos
) {
3256 if ((pos
<= walk
->queuePosition
) && (walk
->queuePosition
< old_pos
)) {
3257 walk
->queuePosition
++;
3258 walk
->anyDate
= now
;
3262 if (back
< walk
->queuePosition
)
3263 back
= walk
->queuePosition
;
3266 tor
->queuePosition
= MIN (pos
, (back
+1));
3269 assert (queueIsSequenced (tor
->session
));
3273 tr_torrentsQueueMoveTop (tr_torrent
** torrents_in
, int n
)
3276 tr_torrent
** torrents
= tr_memdup (torrents_in
, sizeof (tr_torrent
*) * n
);
3277 qsort (torrents
, n
, sizeof (tr_torrent
*), compareTorrentByQueuePosition
);
3278 for (i
=n
-1; i
>=0; --i
)
3279 tr_torrentSetQueuePosition (torrents
[i
], 0);
3284 tr_torrentsQueueMoveUp (tr_torrent
** torrents_in
, int n
)
3287 tr_torrent
** torrents
= tr_memdup (torrents_in
, sizeof (tr_torrent
*) * n
);
3288 qsort (torrents
, n
, sizeof (tr_torrent
*), compareTorrentByQueuePosition
);
3290 tr_torrentSetQueuePosition (torrents
[i
], torrents
[i
]->queuePosition
- 1);
3295 tr_torrentsQueueMoveDown (tr_torrent
** torrents_in
, int n
)
3298 tr_torrent
** torrents
= tr_memdup (torrents_in
, sizeof (tr_torrent
*) * n
);
3299 qsort (torrents
, n
, sizeof (tr_torrent
*), compareTorrentByQueuePosition
);
3300 for (i
=n
-1; i
>=0; --i
)
3301 tr_torrentSetQueuePosition (torrents
[i
], torrents
[i
]->queuePosition
+ 1);
3306 tr_torrentsQueueMoveBottom (tr_torrent
** torrents_in
, int n
)
3309 tr_torrent
** torrents
= tr_memdup (torrents_in
, sizeof (tr_torrent
*) * n
);
3310 qsort (torrents
, n
, sizeof (tr_torrent
*), compareTorrentByQueuePosition
);
3312 tr_torrentSetQueuePosition (torrents
[i
], INT_MAX
);
3317 torrentSetQueued (tr_torrent
* tor
, bool queued
)
3319 assert (tr_isTorrent (tor
));
3320 assert (tr_isBool (queued
));
3322 if (tr_torrentIsQueued (tor
) != queued
)
3324 tor
->isQueued
= queued
;
3325 tor
->anyDate
= tr_time ();
3330 tr_torrentSetQueueStartCallback (tr_torrent
* torrent
, void (*callback
)(tr_torrent
*, void *), void * user_data
)
3332 torrent
->queue_started_callback
= callback
;
3333 torrent
->queue_started_user_data
= user_data
;