source: trunk/libtransmission/torrent.c @ 1614

Last change on this file since 1614 was 1614, checked in by joshe, 15 years ago

Add API function to disable PEX for a torrent.

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