source: trunk/libtransmission/torrent.c @ 1868

Last change on this file since 1868 was 1868, checked in by livings124, 15 years ago

separate code for determining if there is a download with same name and location

  • Property svn:keywords set to Date Rev Author Id
File size: 23.1 KB
Line 
1/******************************************************************************
2 * $Id: torrent.c 1868 2007-05-11 18:56:59Z livings124 $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include "transmission.h"
26#include "shared.h"
27
28/***********************************************************************
29 * Local prototypes
30 **********************************************************************/
31static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor,
32                                       uint8_t *, int flags, int * error );
33static void torrentReallyStop( tr_torrent_t * );
34static void downloadLoop( void * );
35
36void tr_setUseCustomUpload( tr_torrent_t * tor, int limit )
37{
38    tor->customUploadLimit = limit;
39}
40
41void tr_setUseCustomDownload( tr_torrent_t * tor, int limit )
42{
43    tor->customDownloadLimit = limit;
44}
45
46void tr_setUploadLimit( tr_torrent_t * tor, int limit )
47{
48    tr_rcSetLimit( tor->upload, limit );
49}
50
51void tr_setDownloadLimit( tr_torrent_t * tor, int limit )
52{
53    tr_rcSetLimit( tor->download, limit );
54}
55
56tr_torrent_t *
57tr_torrentInit( tr_handle_t * h, const char * path,
58                uint8_t * hash, int flags, int * error )
59{
60    tr_torrent_t * tor;
61
62    tor  = calloc( 1, sizeof *tor );
63    if( NULL == tor )
64    {
65        *error = TR_EOTHER;
66        return NULL;
67    }
68
69    /* Parse torrent file */
70    if( tr_metainfoParseFile( &tor->info, h->tag, path,
71                              TR_FLAG_SAVE & flags ) )
72    {
73        *error = TR_EINVALID;
74        free( tor );
75        return NULL;
76    }
77
78    return torrentRealInit( h, tor, hash, flags, error );
79}
80
81tr_torrent_t *
82tr_torrentInitData( tr_handle_t * h, uint8_t * data, size_t size,
83                    uint8_t * hash, int flags, int * error )
84{
85    tr_torrent_t * tor;
86
87    tor  = calloc( 1, sizeof *tor );
88    if( NULL == tor )
89    {
90        *error = TR_EOTHER;
91        return NULL;
92    }
93
94    /* Parse torrent file */
95    if( tr_metainfoParseData( &tor->info, h->tag, data, size,
96                              TR_FLAG_SAVE & flags ) )
97    {
98        *error = TR_EINVALID;
99        free( tor );
100        return NULL;
101    }
102
103    return torrentRealInit( h, tor, hash, flags, error );
104}
105
106tr_torrent_t *
107tr_torrentInitSaved( tr_handle_t * h, const char * hashStr,
108                     int flags, int * error )
109{
110    tr_torrent_t * tor;
111
112    tor  = calloc( 1, sizeof *tor );
113    if( NULL == tor )
114    {
115        *error = TR_EOTHER;
116        return NULL;
117    }
118
119    /* Parse torrent file */
120    if( tr_metainfoParseHash( &tor->info, h->tag, hashStr ) )
121    {
122        *error = TR_EINVALID;
123        free( tor );
124        return NULL;
125    }
126
127    return torrentRealInit( h, tor, NULL, ( TR_FLAG_SAVE | flags ), error );
128}
129
130/***********************************************************************
131 * tr_torrentInit
132 ***********************************************************************
133 * Allocates a tr_torrent_t structure, then relies on tr_metainfoParse
134 * to fill it.
135 **********************************************************************/
136static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor,
137                                       uint8_t * hash, int flags, int * error )
138{
139    tr_torrent_t  * tor_tmp;
140    tr_info_t     * inf;
141    int             i;
142   
143    inf         = &tor->info;
144    inf->flags |= flags;
145
146    tr_sharedLock( h->shared );
147
148    /* Make sure this torrent is not already open */
149    for( tor_tmp = h->torrentList; tor_tmp; tor_tmp = tor_tmp->next )
150    {
151        if( !memcmp( tor->info.hash, tor_tmp->info.hash,
152                     SHA_DIGEST_LENGTH ) )
153        {
154            if( NULL != hash )
155            {
156                memcpy( hash, tor->info.hash, SHA_DIGEST_LENGTH );
157            }
158            *error = TR_EDUPLICATE;
159            tr_metainfoFree( &tor->info );
160            free( tor );
161            tr_sharedUnlock( h->shared );
162            return NULL;
163        }
164    }
165
166    tor->handle   = h;
167    tor->status   = TR_STATUS_PAUSE;
168    tor->id       = h->id;
169    tor->key      = h->key;
170    tor->azId     = h->azId;
171    tor->finished = 0;
172
173    /* Escaped info hash for HTTP queries */
174    for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
175    {
176        snprintf( &tor->escapedHashString[3*i],
177                  sizeof( tor->escapedHashString ) - 3 * i,
178                  "%%%02x", inf->hash[i] );
179    }
180
181    tor->pexDisabled = 0;
182
183    /* Block size: usually 16 ko, or less if we have to */
184    tor->blockSize  = MIN( inf->pieceSize, 1 << 14 );
185    tor->blockCount = ( inf->totalSize + tor->blockSize - 1 ) /
186                        tor->blockSize;
187    tor->completion = tr_cpInit( tor );
188
189    tr_lockInit( &tor->lock );
190    tr_condInit( &tor->cond );
191
192    tor->upload         = tr_rcInit();
193    tor->download       = tr_rcInit();
194    tor->swarmspeed     = tr_rcInit();
195 
196    /* We have a new torrent */
197    tor->publicPort = tr_sharedGetPublicPort( h->shared );
198    tor->prev       = NULL;
199    tor->next       = h->torrentList;
200    if( tor->next )
201    {
202        tor->next->prev = tor;
203    }
204    h->torrentList = tor;
205    (h->torrentCount)++;
206
207    tr_sharedUnlock( h->shared );
208
209    if( !h->isPortSet )
210    {
211        tr_setBindPort( h, TR_DEFAULT_PORT );
212    }
213
214    return tor;
215}
216
217tr_info_t * tr_torrentInfo( tr_torrent_t * tor )
218{
219    return &tor->info;
220}
221
222/***********************************************************************
223 * tr_torrentScrape     
224 **********************************************************************/
225int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l, int * d )
226{
227    return tr_trackerScrape( tor, s, l, d );
228}
229
230void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
231{
232    tor->destination = strdup( path );
233    tr_ioLoadResume( tor );
234}
235
236char * tr_torrentGetFolder( tr_torrent_t * tor )
237{
238    return tor->destination;
239}
240
241int tr_torrentDuplicateDownload( tr_torrent_t * tor )
242{
243    tr_torrent_t * current, * next;
244   
245    /* Check if a torrent with the same name and destination is already active */
246    for( current = tor->handle->torrentList; current; current = current->next )
247    {
248        if( current != tor && current->status != TR_STATUS_PAUSE
249            && !strcmp( tor->destination, current->destination )
250            && !strcmp( tor->info.name, current->info.name ) )
251        {
252            return 1;
253        }
254    }
255    return 0;
256}
257
258void tr_torrentStart( tr_torrent_t * tor )
259{
260    char name[32];
261   
262    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
263    {
264        /* Join the thread first */
265        torrentReallyStop( tor );
266    }
267   
268    /* Don't start if a torrent with the same name and destination is already active */
269    if( tr_torrentDuplicateDownload( tor ) )
270    {
271        tor->error = TR_ERROR_IO_DUP_DOWNLOAD;
272        snprintf( tor->errorString, sizeof( tor->errorString ),
273                    "%s", tr_errorString( TR_ERROR_IO_DUP_DOWNLOAD ) );
274        return;
275    }
276
277    tr_lockLock( &tor->lock );
278
279    tor->downloadedPrev += tor->downloadedCur;
280    tor->downloadedCur   = 0;
281    tor->uploadedPrev   += tor->uploadedCur;
282    tor->uploadedCur     = 0;
283
284    tor->status  = TR_STATUS_CHECK;
285    tor->error   = TR_OK;
286    tor->tracker = tr_trackerInit( tor );
287
288    tor->date = tr_date();
289    tor->die = 0;
290    snprintf( name, sizeof( name ), "torrent %p", tor );
291
292    tr_lockUnlock( &tor->lock );
293
294    tr_threadCreate( &tor->thread, downloadLoop, tor, name );
295}
296
297static void torrentStop( tr_torrent_t * tor )
298{
299    tr_trackerStopped( tor->tracker );
300    tr_rcReset( tor->download );
301    tr_rcReset( tor->upload );
302    tr_rcReset( tor->swarmspeed );
303    tor->status = TR_STATUS_STOPPING;
304    tor->stopDate = tr_date();
305}
306
307void tr_torrentStop( tr_torrent_t * tor )
308{
309    tr_lockLock( &tor->lock );
310    torrentStop( tor );
311
312    /* Don't return until the files are closed, so the UI can trash
313     * them if requested */
314    tr_condWait( &tor->cond, &tor->lock );
315    tr_lockUnlock( &tor->lock );
316}
317
318/***********************************************************************
319 * torrentReallyStop
320 ***********************************************************************
321 * Joins the download thread and frees/closes everything related to it.
322 **********************************************************************/
323static void torrentReallyStop( tr_torrent_t * tor )
324{
325    int i;
326
327    tor->die = 1;
328    tr_threadJoin( &tor->thread );
329
330    tr_trackerClose( tor->tracker );
331    tor->tracker = NULL;
332
333    tr_lockLock( &tor->lock );
334    for( i = 0; i < tor->peerCount; i++ )
335    {
336        tr_peerDestroy( tor->peers[i] );
337    }
338    tor->peerCount = 0;
339    tr_lockUnlock( &tor->lock );
340}
341
342void tr_torrentDisablePex( tr_torrent_t * tor, int disable )
343{
344    int ii;
345
346    if( TR_FLAG_PRIVATE & tor->info.flags )
347    {
348        return;
349    }
350
351    tr_lockLock( &tor->lock );
352
353    if( tor->pexDisabled == disable )
354    {
355        tr_lockUnlock( &tor->lock );
356        return;
357    }
358
359    tor->pexDisabled = disable;
360    for( ii = 0; ii < tor->peerCount; ii++ )
361    {
362        tr_peerSetPrivate( tor->peers[ii], disable );
363    }
364
365    tr_lockUnlock( &tor->lock );
366}
367
368int tr_getFinished( tr_torrent_t * tor )
369{
370    if( tor->finished )
371    {
372        tor->finished = 0;
373        return 1;
374    }
375    return 0;
376}
377
378void tr_manualUpdate( tr_torrent_t * tor )
379{
380    int peerCount, new;
381    uint8_t * peerCompact;
382
383    if( !( tor->status & TR_STATUS_ACTIVE ) )
384        return;
385   
386    tr_lockLock( &tor->lock );
387    tr_trackerAnnouncePulse( tor->tracker, &peerCount, &peerCompact, 1 );
388    new = 0;
389    if( peerCount > 0 )
390    {
391        new = tr_torrentAddCompact( tor, TR_PEER_FROM_TRACKER,
392                              peerCompact, peerCount );
393        free( peerCompact );
394    }
395    tr_dbg( "got %i peers from manual announce, used %i", peerCount, new );
396    tr_lockUnlock( &tor->lock );
397}
398
399tr_stat_t * tr_torrentStat( tr_torrent_t * tor )
400{
401    tr_stat_t * s;
402    tr_peer_t * peer;
403    tr_info_t * inf = &tor->info;
404    tr_tracker_t * tc;
405    int i;
406
407    tor->statCur = ( tor->statCur + 1 ) % 2;
408    s = &tor->stats[tor->statCur];
409
410    if( ( tor->status & TR_STATUS_STOPPED ) ||
411        ( ( tor->status & TR_STATUS_STOPPING ) &&
412          tr_date() > tor->stopDate + 60000 ) )
413    {
414        torrentReallyStop( tor );
415        tor->status = TR_STATUS_PAUSE;
416    }
417
418    tr_lockLock( &tor->lock );
419
420    s->status = tor->status;
421    s->error  = tor->error;
422    memcpy( s->errorString, tor->errorString,
423            sizeof( s->errorString ) );
424
425    tc = tor->tracker;
426    s->cannotConnect = tr_trackerCannotConnect( tc );
427    s->tracker = ( tc ? tr_trackerGet( tc ) : &inf->trackerList[0].list[0] );
428
429    s->peersTotal       = 0;
430    memset( s->peersFrom, 0, sizeof( s->peersFrom ) );
431    s->peersUploading   = 0;
432    s->peersDownloading = 0;
433   
434    for( i = 0; i < tor->peerCount; i++ )
435    {
436        peer = tor->peers[i];
437   
438        if( tr_peerIsConnected( peer ) )
439        {
440            (s->peersTotal)++;
441            (s->peersFrom[ tr_peerIsFrom( peer ) ])++;
442            if( tr_peerAmInterested( peer ) && !tr_peerIsChoking( peer ) )
443            {
444                (s->peersUploading)++;
445            }
446            if( !tr_peerAmChoking( peer ) )
447            {
448                (s->peersDownloading)++;
449            }
450        }
451    }
452
453    s->progress = tr_cpCompletionAsFloat( tor->completion );
454    s->left     = tr_cpLeftBytes( tor->completion );
455    if( tor->status & TR_STATUS_DOWNLOAD )
456    {
457        s->rateDownload = tr_rcRate( tor->download );
458    }
459    else
460    {
461        /* tr_rcRate() doesn't make the difference between 'piece'
462           messages and other messages, which causes a non-zero
463           download rate even tough we are not downloading. So we
464           force it to zero not to confuse the user. */
465        s->rateDownload = 0.0;
466    }
467    s->rateUpload = tr_rcRate( tor->upload );
468   
469    s->seeders  = tr_trackerSeeders( tc );
470    s->leechers = tr_trackerLeechers( tc );
471    s->completedFromTracker = tr_trackerDownloaded( tc );
472
473    s->swarmspeed = tr_rcRate( tor->swarmspeed );
474
475    if( s->rateDownload < 0.1 )
476    {
477        s->eta = -1;
478    }
479    else
480    {
481        s->eta = (float) s->left / s->rateDownload / 1024.0;
482    }
483
484    s->downloaded = tor->downloadedCur + tor->downloadedPrev;
485    s->uploaded   = tor->uploadedCur   + tor->uploadedPrev;
486   
487    if( s->downloaded == 0 && s->progress == 0.0 )
488    {
489        s->ratio = TR_RATIO_NA;
490    }
491    else
492    {
493        s->ratio = (float)s->uploaded / (float)MAX(s->downloaded, inf->totalSize - s->left);
494    }
495   
496    tr_lockUnlock( &tor->lock );
497
498    return s;
499}
500
501tr_peer_stat_t * tr_torrentPeers( tr_torrent_t * tor, int * peerCount )
502{
503    tr_peer_stat_t * peers;
504
505    tr_lockLock( &tor->lock );
506
507    *peerCount = tor->peerCount;
508   
509    peers = (tr_peer_stat_t *) calloc( tor->peerCount, sizeof( tr_peer_stat_t ) );
510    if (peers != NULL)
511    {
512        tr_peer_t * peer;
513        struct in_addr * addr;
514        int i;
515        for( i = 0; i < tor->peerCount; i++ )
516        {
517            peer = tor->peers[i];
518           
519            addr = tr_peerAddress( peer );
520            if( NULL != addr )
521            {
522                tr_netNtop( addr, peers[i].addr,
523                           sizeof( peers[i].addr ) );
524            }
525           
526            peers[i].client        = tr_peerClient( peer );
527            peers[i].isConnected   = tr_peerIsConnected( peer );
528            peers[i].from          = tr_peerIsFrom( peer );
529            peers[i].progress      = tr_peerProgress( peer );
530            peers[i].port          = tr_peerPort( peer );
531           
532            if( ( peers[i].isDownloading = !tr_peerAmChoking( peer ) ) )
533            {
534                peers[i].uploadToRate = tr_peerUploadRate( peer );
535            }
536            if( ( peers[i].isUploading = ( tr_peerAmInterested( peer ) &&
537                                           !tr_peerIsChoking( peer ) ) ) )
538            {
539                peers[i].downloadFromRate = tr_peerDownloadRate( peer );
540            }
541        }
542    }
543   
544    tr_lockUnlock( &tor->lock );
545   
546    return peers;
547}
548
549void tr_torrentPeersFree( tr_peer_stat_t * peers, int peerCount UNUSED )
550{
551    if (peers == NULL)
552        return;
553
554    free( peers );
555}
556
557void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size )
558{
559    int i, j, piece;
560    float interval;
561
562    tr_lockLock( &tor->lock );
563    interval = (float)tor->info.pieceCount / (float)size;
564    for( i = 0; i < size; i++ )
565    {
566        piece = i * interval;
567
568        if( tr_cpPieceIsComplete( tor->completion, piece ) )
569        {
570            tab[i] = -1;
571            continue;
572        }
573
574        tab[i] = 0;
575        for( j = 0; j < tor->peerCount; j++ )
576        {
577            if( tr_peerBitfield( tor->peers[j] ) &&
578                tr_bitfieldHas( tr_peerBitfield( tor->peers[j] ), piece ) )
579            {
580                (tab[i])++;
581            }
582        }
583    }
584    tr_lockUnlock( &tor->lock );
585}
586
587float * tr_torrentCompletion( tr_torrent_t * tor )
588{
589    tr_info_t * inf = &tor->info;
590    int         piece, file;
591    float     * ret, prog, weight;
592    uint64_t    piecemax, piecesize;
593    uint64_t    filestart, fileoff, filelen, blockend, blockused;
594
595    tr_lockLock( &tor->lock );
596
597    ret       = calloc( inf->fileCount, sizeof( float ) );
598    file      = 0;
599    piecemax  = inf->pieceSize;
600    filestart = 0;
601    fileoff   = 0;
602    piece     = 0;
603    while( inf->pieceCount > piece )
604    {
605        assert( file < inf->fileCount );
606        assert( filestart + fileoff < inf->totalSize );
607        filelen    = inf->files[file].length;
608        piecesize  = tr_pieceSize( piece );
609        blockend   = MIN( filestart + filelen, piecemax * piece + piecesize );
610        blockused  = blockend - ( filestart + fileoff );
611        weight     = ( filelen ? ( float )blockused / ( float )filelen : 1.0 );
612        prog       = tr_cpPercentBlocksInPiece( tor->completion, piece );
613        ret[file] += prog * weight;
614        fileoff   += blockused;
615        assert( -0.1 < prog   && 1.1 > prog );
616        assert( -0.1 < weight && 1.1 > weight );
617        if( fileoff == filelen )
618        {
619            ret[file] = MIN( 1.0, ret[file] );
620            ret[file] = MAX( 0.0, ret[file] );
621            filestart += fileoff;
622            fileoff    = 0;
623            file++;
624        }
625        if( filestart + fileoff >= piecemax * piece + piecesize )
626        {
627            piece++;
628        }
629    }
630
631    tr_lockUnlock( &tor->lock );
632
633    return ret;
634}
635
636void tr_torrentAmountFinished( tr_torrent_t * tor, float * tab, int size )
637{
638    int i, piece;
639    float interval;
640
641    tr_lockLock( &tor->lock );
642    interval = (float)tor->info.pieceCount / (float)size;
643    for( i = 0; i < size; i++ )
644    {
645        piece = i * interval;
646        tab[i] = tr_cpPercentBlocksInPiece( tor->completion, piece );
647    }
648    tr_lockUnlock( &tor->lock );
649}
650
651void tr_torrentRemoveSaved( tr_torrent_t * tor )
652{
653    tr_metainfoRemoveSaved( tor->info.hashString, tor->handle->tag );
654}
655
656void tr_torrentRemoveFastResume( tr_torrent_t * tor )
657{
658    tr_ioRemoveResume( tor );
659}
660
661/***********************************************************************
662 * tr_torrentClose
663 ***********************************************************************
664 * Frees memory allocated by tr_torrentInit.
665 **********************************************************************/
666void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor )
667{
668    tr_info_t * inf = &tor->info;
669
670    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
671    {
672        /* Join the thread first */
673        torrentReallyStop( tor );
674    }
675
676    tr_sharedLock( h->shared );
677
678    h->torrentCount--;
679
680    tr_lockClose( &tor->lock );
681    tr_condClose( &tor->cond );
682    tr_cpClose( tor->completion );
683
684    tr_rcClose( tor->upload );
685    tr_rcClose( tor->download );
686    tr_rcClose( tor->swarmspeed );
687
688    if( tor->destination )
689    {
690        free( tor->destination );
691    }
692
693    tr_metainfoFree( inf );
694
695    if( tor->prev )
696    {
697        tor->prev->next = tor->next;
698    }
699    else
700    {
701        h->torrentList = tor->next;
702    }
703    if( tor->next )
704    {
705        tor->next->prev = tor->prev;
706    }
707    free( tor );
708
709    tr_sharedUnlock( h->shared );
710}
711
712int tr_torrentAttachPeer( tr_torrent_t * tor, tr_peer_t * peer )
713{
714    int i;
715    tr_peer_t * otherPeer;
716
717    if( tor->peerCount >= TR_MAX_PEER_COUNT )
718    {
719        tr_peerDestroy(  peer );
720        return 0;
721    }
722
723    /* Don't accept two connections from the same IP */
724    for( i = 0; i < tor->peerCount; i++ )
725    {
726        otherPeer = tor->peers[i];
727        if( !memcmp( tr_peerAddress( peer ), tr_peerAddress( otherPeer ), 4 ) )
728        {
729            tr_peerDestroy(  peer );
730            return 0;
731        }
732    }
733
734    tr_peerSetPrivate( peer, tor->info.flags & TR_FLAG_PRIVATE ||
735                       tor->pexDisabled );
736    tr_peerSetTorrent( peer, tor );
737    tor->peers[tor->peerCount++] = peer;
738
739    return 1;
740}
741
742int tr_torrentAddCompact( tr_torrent_t * tor, int from,
743                           uint8_t * buf, int count )
744{
745    struct in_addr addr;
746    in_port_t port;
747    int i, added;
748    tr_peer_t * peer;
749
750    added = 0;
751    for( i = 0; i < count; i++ )
752    {
753        memcpy( &addr, buf, 4 ); buf += 4;
754        memcpy( &port, buf, 2 ); buf += 2;
755
756        peer = tr_peerInit( addr, port, -1, from );
757        added += tr_torrentAttachPeer( tor, peer );
758    }
759
760    return added;
761}
762
763/***********************************************************************
764 * downloadLoop
765 **********************************************************************/
766static void downloadLoop( void * _tor )
767{
768    tr_torrent_t * tor = _tor;
769    int            i, ret;
770    int            peerCount, used;
771    uint8_t      * peerCompact;
772    tr_peer_t    * peer;
773
774    tr_lockLock( &tor->lock );
775
776    tr_cpReset( tor->completion );
777    tor->io     = tr_ioInit( tor );
778    tor->status = tr_cpIsSeeding( tor->completion ) ?
779                      TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
780
781    while( !tor->die )
782    {
783        tr_lockUnlock( &tor->lock );
784        tr_wait( 20 );
785        tr_lockLock( &tor->lock );
786
787        /* Are we finished ? */
788        if( ( tor->status & TR_STATUS_DOWNLOAD ) &&
789            tr_cpIsSeeding( tor->completion ) )
790        {
791            /* Done */
792            tor->status = TR_STATUS_SEED;
793                        tor->finished = 1;
794            tr_trackerCompleted( tor->tracker );
795            tr_ioSync( tor->io );
796        }
797
798        /* Try to get new peers or to send a message to the tracker */
799        tr_trackerPulse( tor->tracker, &peerCount, &peerCompact );
800        if( peerCount > 0 )
801        {
802            used = tr_torrentAddCompact( tor, TR_PEER_FROM_TRACKER,
803                                         peerCompact, peerCount );
804            free( peerCompact );
805            tr_dbg( "got %i peers from announce, used %i", peerCount, used );
806        }
807        if( tor->status & TR_STATUS_STOPPED )
808        {
809            break;
810        }
811
812        /* Stopping: make sure all files are closed and stop talking
813           to peers */
814        if( tor->status & TR_STATUS_STOPPING )
815        {
816            if( tor->io )
817            {
818                tr_ioClose( tor->io ); tor->io = NULL;
819                tr_condSignal( &tor->cond );
820            }
821            continue;
822        }
823
824        /* Shuffle peers */
825        if( tor->peerCount > 1 )
826        {
827            peer = tor->peers[0];
828            memmove( &tor->peers[0], &tor->peers[1],
829                    ( tor->peerCount - 1 ) * sizeof( void * ) );
830            tor->peers[tor->peerCount - 1] = peer;
831        }
832
833        /* Receive/send messages */
834        for( i = 0; i < tor->peerCount; )
835        {
836            peer = tor->peers[i];
837
838            ret = tr_peerPulse( peer );
839            if( ret & TR_ERROR_IO_MASK )
840            {
841                tr_err( "Fatal error, stopping download (%d)", ret );
842                torrentStop( tor );
843                tor->error = ret;
844                snprintf( tor->errorString, sizeof( tor->errorString ),
845                          "%s", tr_errorString( ret ) );
846                break;
847            }
848            if( ret )
849            {
850                tr_peerDestroy( peer );
851                tor->peerCount--;
852                memmove( &tor->peers[i], &tor->peers[i+1],
853                         ( tor->peerCount - i ) * sizeof( void * ) );
854                continue;
855            }
856            i++;
857        }
858    }
859
860    tr_lockUnlock( &tor->lock );
861
862    if( tor->io )
863    {
864        tr_ioClose( tor->io ); tor->io = NULL;
865        tr_condSignal( &tor->cond );
866    }
867
868    tor->status = TR_STATUS_STOPPED;
869}
870
Note: See TracBrowser for help on using the repository browser.