source: trunk/libtransmission/transmission.c @ 1288

Last change on this file since 1288 was 1288, checked in by livings124, 16 years ago

support in libT for individual torrent speed caps

  • Property svn:keywords set to Date Rev Author Id
File size: 25.3 KB
Line 
1/******************************************************************************
2 * $Id: transmission.c 1288 2006-12-27 01:04:30Z livings124 $
3 *
4 * Copyright (c) 2005-2006 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
27/***********************************************************************
28 * Local prototypes
29 **********************************************************************/
30static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor,
31                                       int flags, int * error );
32static void torrentReallyStop( tr_torrent_t * );
33static void downloadLoop( void * );
34static void acceptLoop( void * );
35static void acceptStop( tr_handle_t * h );
36
37/***********************************************************************
38 * tr_init
39 ***********************************************************************
40 * Allocates a tr_handle_t structure and initializes a few things
41 **********************************************************************/
42tr_handle_t * tr_init()
43{
44    tr_handle_t * h;
45    int           i, r;
46
47    tr_msgInit();
48    tr_netResolveThreadInit();
49
50    h = calloc( sizeof( tr_handle_t ), 1 );
51
52    /* Generate a peer id : "-TRxxyy-" + 12 random alphanumeric
53       characters, where xx is the major version number and yy the
54       minor version number (Azureus-style) */
55    sprintf( h->id, "-TR%02d%02d-", VERSION_MAJOR, VERSION_MINOR );
56    for( i = 8; i < 20; i++ )
57    {
58        r        = tr_rand( 36 );
59        h->id[i] = ( r < 26 ) ? ( 'a' + r ) : ( '0' + r - 26 ) ;
60    }
61
62    /* Random key */
63    for( i = 0; i < 20; i++ )
64    {
65        r         = tr_rand( 36 );
66        h->key[i] = ( r < 26 ) ? ( 'a' + r ) : ( '0' + r - 26 ) ;
67    }
68
69    /* Don't exit when writing on a broken socket */
70    signal( SIGPIPE, SIG_IGN );
71
72    /* Initialize rate and file descripts controls */
73    h->upload   = tr_rcInit();
74    h->download = tr_rcInit();
75    h->fdlimit  = tr_fdInit();
76    h->choking  = tr_chokingInit( h );
77    h->natpmp   = tr_natpmpInit( h->fdlimit );
78    h->upnp     = tr_upnpInit( h->fdlimit );
79
80    h->bindPort = -1;
81    h->bindSocket = -1;
82
83    h->acceptDie = 0;
84    tr_lockInit( &h->acceptLock );
85    tr_threadCreate( &h->acceptThread, acceptLoop, h );
86
87    return h;
88}
89
90/***********************************************************************
91 * tr_setBindPort
92 ***********************************************************************
93 *
94 **********************************************************************/
95void tr_setBindPort( tr_handle_t * h, int port )
96{
97    int sock = -1;
98    tr_torrent_t * tor;
99
100    if( h->bindPort == port )
101      return;
102
103#ifndef BEOS_NETSERVER
104    /* BeOS net_server seems to be unable to set incoming connections to
105       non-blocking. Too bad. */
106    if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
107    {
108        /* XXX should handle failure here in a better way */
109        sock = tr_netBindTCP( port );
110        if( 0 > sock)
111        {
112            tr_fdSocketClosed( h->fdlimit, 0 );
113        }
114        else
115        {   
116            tr_inf( "Bound listening port %d", port );
117            listen( sock, 5 );
118        }
119    }
120#else
121    return;
122#endif
123
124    tr_lockLock( &h->acceptLock );
125
126    h->bindPort = port;
127
128    for( tor = h->torrentList; tor; tor = tor->next )
129    {
130        tr_lockLock( &tor->lock );
131        if( NULL != tor->tracker )
132        {
133            tr_trackerChangePort( tor->tracker, port );
134        }
135        tr_lockUnlock( &tor->lock );
136    }
137
138    if( h->bindSocket > -1 )
139    {
140        tr_netClose( h->bindSocket );
141        tr_fdSocketClosed( h->fdlimit, 0 );
142    }
143
144    h->bindSocket = sock;
145
146    tr_natpmpForwardPort( h->natpmp, port );
147    tr_upnpForwardPort( h->upnp, port );
148
149    tr_lockUnlock( &h->acceptLock );
150}
151
152void tr_natTraversalEnable( tr_handle_t * h )
153{
154    tr_natpmpStart( h->natpmp );
155    tr_upnpStart( h->upnp );
156}
157
158void tr_natTraversalDisable( tr_handle_t * h )
159{
160    tr_natpmpStop( h->natpmp );
161    tr_upnpStop( h->upnp );
162}
163
164int tr_natTraversalStatus( tr_handle_t * h )
165{
166    int statuses[] = {
167        TR_NAT_TRAVERSAL_MAPPED,
168        TR_NAT_TRAVERSAL_MAPPING,
169        TR_NAT_TRAVERSAL_UNMAPPING,
170        TR_NAT_TRAVERSAL_ERROR,
171        TR_NAT_TRAVERSAL_NOTFOUND,
172        TR_NAT_TRAVERSAL_DISABLED,
173        -1,
174    };
175    int natpmp, upnp, ii;
176
177    natpmp = tr_natpmpStatus( h->natpmp );
178    upnp = tr_upnpStatus( h->upnp );
179
180    for( ii = 0; 0 <= statuses[ii]; ii++ )
181    {
182        if( statuses[ii] == natpmp || statuses[ii] == upnp )
183        {
184            return statuses[ii];
185        }
186    }
187
188    assert( 0 );
189
190    return TR_NAT_TRAVERSAL_ERROR;
191}
192
193void tr_setGlobalUploadLimit( tr_handle_t * h, int limit )
194{
195    tr_rcSetLimit( h->upload, limit );
196    tr_chokingSetLimit( h->choking, limit );
197}
198
199void tr_setGlobalDownloadLimit( tr_handle_t * h, int limit )
200{
201    tr_rcSetLimit( h->download, limit );
202}
203
204void tr_setUploadLimit( tr_torrent_t * tor, int limit )
205{
206    tr_rcSetLimit( tor->upload, limit );
207}
208
209void tr_setDownloadLimit( tr_torrent_t * tor, int limit )
210{
211    tr_rcSetLimit( tor->download, limit );
212}
213
214void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
215{
216    tr_torrent_t * tor;
217
218    *dl = 0.0;
219    *ul = 0.0;
220    for( tor = h->torrentList; tor; tor = tor->next )
221    {
222        tr_lockLock( &tor->lock );
223        if( tor->status & TR_STATUS_DOWNLOAD )
224            *dl += tr_rcRate( tor->download );
225        *ul += tr_rcRate( tor->upload );
226        tr_lockUnlock( &tor->lock );
227    }
228}
229
230tr_torrent_t * tr_torrentInit( tr_handle_t * h, const char * path,
231                               int flags, int * error )
232{
233    tr_torrent_t  * tor = calloc( sizeof( tr_torrent_t ), 1 );
234    int             saveCopy = ( TR_FSAVEPRIVATE & flags );
235
236    /* Parse torrent file */
237    if( tr_metainfoParse( &tor->info, path, NULL, saveCopy ) )
238    {
239        *error = TR_EINVALID;
240        free( tor );
241        return NULL;
242    }
243
244    return torrentRealInit( h, tor, flags, error );
245}
246
247tr_torrent_t * tr_torrentInitSaved( tr_handle_t * h, const char * hashStr,
248                                    int flags, int * error )
249{
250    tr_torrent_t  * tor = calloc( sizeof( tr_torrent_t ), 1 );
251
252    /* Parse torrent file */
253    if( tr_metainfoParse( &tor->info, NULL, hashStr, 0 ) )
254    {
255        *error = TR_EINVALID;
256        free( tor );
257        return NULL;
258    }
259
260    return torrentRealInit( h, tor, ( TR_FSAVEPRIVATE | flags ), error );
261}
262
263/***********************************************************************
264 * tr_torrentInit
265 ***********************************************************************
266 * Allocates a tr_torrent_t structure, then relies on tr_metainfoParse
267 * to fill it.
268 **********************************************************************/
269static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor,
270                                       int flags, int * error )
271{
272    tr_torrent_t  * tor_tmp;
273    tr_info_t     * inf;
274    int             i;
275
276    inf        = &tor->info;
277    inf->flags = flags;
278
279    /* Make sure this torrent is not already open */
280    for( tor_tmp = h->torrentList; tor_tmp; tor_tmp = tor_tmp->next )
281    {
282        if( !memcmp( tor->info.hash, tor_tmp->info.hash,
283                     SHA_DIGEST_LENGTH ) )
284        {
285            *error = TR_EDUPLICATE;
286            tr_metainfoFree( &tor->info );
287            free( tor );
288            return NULL;
289        }
290    }
291
292    tor->status = TR_STATUS_PAUSE;
293    tor->id     = h->id;
294    tor->key    = h->key;
295    tor->bindPort = &h->bindPort;
296        tor->finished = 0;
297
298    /* Escaped info hash for HTTP queries */
299    for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
300    {
301        sprintf( &tor->escapedHashString[3*i], "%%%02x", inf->hash[i] );
302    }
303
304    /* Block size: usually 16 ko, or less if we have to */
305    tor->blockSize  = MIN( inf->pieceSize, 1 << 14 );
306    tor->blockCount = ( inf->totalSize + tor->blockSize - 1 ) /
307                        tor->blockSize;
308    tor->completion = tr_cpInit( tor );
309
310    tr_lockInit( &tor->lock );
311
312    tor->globalUpload   = h->upload;
313    tor->globalDownload = h->download;
314    tor->fdlimit        = h->fdlimit;
315    tor->upload         = tr_rcInit();
316    tor->download       = tr_rcInit();
317    tor->swarmspeed     = tr_rcInit();
318 
319    /* We have a new torrent */
320    tr_lockLock( &h->acceptLock );
321    tor->prev = NULL;
322    tor->next = h->torrentList;
323    if( tor->next )
324    {
325        tor->next->prev = tor;
326    }
327    h->torrentList = tor;
328    (h->torrentCount)++;
329    tr_lockUnlock( &h->acceptLock );
330
331    if( 0 > h->bindPort )
332    {
333        tr_setBindPort( h, TR_DEFAULT_PORT );
334    }
335
336    return tor;
337}
338
339tr_info_t * tr_torrentInfo( tr_torrent_t * tor )
340{
341    return &tor->info;
342}
343
344/***********************************************************************
345 * tr_torrentScrape     
346 **********************************************************************/
347int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l, int * d )
348{
349    return tr_trackerScrape( tor, s, l, d );
350}
351
352void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
353{
354    tor->destination = strdup( path );
355    tr_ioLoadResume( tor );
356}
357
358char * tr_torrentGetFolder( tr_torrent_t * tor )
359{
360    return tor->destination;
361}
362
363void tr_torrentStart( tr_torrent_t * tor )
364{
365    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
366    {
367        /* Join the thread first */
368        torrentReallyStop( tor );
369    }
370
371    tor->downloadedPrev += tor->downloadedCur;
372    tor->downloadedCur   = 0;
373    tor->uploadedPrev   += tor->uploadedCur;
374    tor->uploadedCur     = 0;
375
376    tor->status  = TR_STATUS_CHECK;
377    tor->tracker = tr_trackerInit( tor );
378
379    tor->date = tr_date();
380    tor->die = 0;
381    tr_threadCreate( &tor->thread, downloadLoop, tor );
382}
383
384void tr_torrentStop( tr_torrent_t * tor )
385{
386    tr_lockLock( &tor->lock );
387    tr_trackerStopped( tor->tracker );
388    tr_rcReset( tor->download );
389    tr_rcReset( tor->upload );
390    tr_rcReset( tor->swarmspeed );
391    tor->status = TR_STATUS_STOPPING;
392    tor->stopDate = tr_date();
393    tr_lockUnlock( &tor->lock );
394}
395
396/***********************************************************************
397 * torrentReallyStop
398 ***********************************************************************
399 * Joins the download thread and frees/closes everything related to it.
400 **********************************************************************/
401static void torrentReallyStop( tr_torrent_t * tor )
402{
403    tor->die = 1;
404    tr_threadJoin( &tor->thread );
405    tr_dbg( "Thread joined" );
406
407    tr_trackerClose( tor->tracker );
408    tor->tracker = NULL;
409
410    tr_lockLock( &tor->lock );
411    while( tor->peerCount > 0 )
412    {
413        tr_peerRem( tor, 0 );
414    }
415    tr_lockUnlock( &tor->lock );
416}
417
418/***********************************************************************
419 * tr_torrentCount
420 ***********************************************************************
421 *
422 **********************************************************************/
423int tr_torrentCount( tr_handle_t * h )
424{
425    return h->torrentCount;
426}
427
428void tr_torrentIterate( tr_handle_t * h, tr_callback_t func, void * d )
429{
430    tr_torrent_t * tor, * next;
431
432    for( tor = h->torrentList; tor; tor = next )
433    {
434        next = tor->next;
435        func( tor, d );
436    }
437}
438
439int tr_getFinished( tr_torrent_t * tor )
440{
441    if( tor->finished )
442    {
443        tor->finished = 0;
444        return 1;
445    }
446    return 0;
447}
448
449void tr_manualUpdate( tr_torrent_t * tor )
450{
451    if( !( tor->status & TR_STATUS_ACTIVE ) )
452        return;
453   
454    tr_lockLock( &tor->lock );
455    tr_trackerAnnouncePulse( tor->tracker, 1 );
456    tr_lockUnlock( &tor->lock );
457}
458
459tr_stat_t * tr_torrentStat( tr_torrent_t * tor )
460{
461    tr_stat_t * s;
462    tr_peer_t * peer;
463    tr_info_t * inf = &tor->info;
464    tr_tracker_t * tc;
465    int i;
466
467    tor->statCur = ( tor->statCur + 1 ) % 2;
468    s = &tor->stats[tor->statCur];
469
470    if( ( tor->status & TR_STATUS_STOPPED ) ||
471        ( ( tor->status & TR_STATUS_STOPPING ) &&
472          tr_date() > tor->stopDate + 60000 ) )
473    {
474        torrentReallyStop( tor );
475        tor->status = TR_STATUS_PAUSE;
476    }
477
478    tr_lockLock( &tor->lock );
479
480    s->status = tor->status;
481    s->error  = tor->error;
482    memcpy( s->trackerError, tor->trackerError,
483            sizeof( s->trackerError ) );
484
485    tc = tor->tracker;
486    s->cannotConnect = tr_trackerCannotConnect( tc );
487   
488    if( tc )
489    {
490        s->trackerAddress  = tr_trackerAddress(  tc );
491        s->trackerPort     = tr_trackerPort(     tc );
492        s->trackerAnnounce = tr_trackerAnnounce( tc );
493    }
494    else
495    {
496        s->trackerAddress  = inf->trackerList[0].list[0].address;
497        s->trackerPort     = inf->trackerList[0].list[0].port;
498        s->trackerAnnounce = inf->trackerList[0].list[0].announce;
499    }
500
501    s->peersTotal       = 0;
502    s->peersIncoming    = 0;
503    s->peersUploading   = 0;
504    s->peersDownloading = 0;
505   
506    for( i = 0; i < tor->peerCount; i++ )
507    {
508        peer = tor->peers[i];
509   
510        if( tr_peerIsConnected( peer ) )
511        {
512            (s->peersTotal)++;
513           
514            if( tr_peerIsIncoming( peer ) )
515            {
516                (s->peersIncoming)++;
517            }
518           
519            if( tr_peerIsUploading( peer ) )
520            {
521                (s->peersUploading)++;
522            }
523            if( tr_peerIsDownloading( peer ) )
524            {
525                (s->peersDownloading)++;
526            }
527        }
528    }
529
530    s->progress = tr_cpCompletionAsFloat( tor->completion );
531    if( tor->status & TR_STATUS_DOWNLOAD )
532    {
533        s->rateDownload = tr_rcRate( tor->download );
534    }
535    else
536    {
537        /* tr_rcRate() doesn't make the difference between 'piece'
538           messages and other messages, which causes a non-zero
539           download rate even tough we are not downloading. So we
540           force it to zero not to confuse the user. */
541        s->rateDownload = 0.0;
542    }
543    s->rateUpload = tr_rcRate( tor->upload );
544   
545    s->seeders  = tr_trackerSeeders( tc );
546    s->leechers = tr_trackerLeechers( tc );
547    s->completedFromTracker = tr_trackerDownloaded( tc );
548
549    s->swarmspeed = tr_rcRate( tor->swarmspeed );
550
551    if( s->rateDownload < 0.1 )
552    {
553        s->eta = -1;
554    }
555    else
556    {
557        s->eta = (float) ( 1.0 - s->progress ) *
558            (float) inf->totalSize / s->rateDownload / 1024.0;
559    }
560
561    s->downloaded = tor->downloadedCur + tor->downloadedPrev;
562    s->uploaded   = tor->uploadedCur   + tor->uploadedPrev;
563
564    tr_lockUnlock( &tor->lock );
565
566    return s;
567}
568
569tr_peer_stat_t * tr_torrentPeers( tr_torrent_t * tor, int * peerCount )
570{
571    tr_peer_stat_t * peers;
572
573    tr_lockLock( &tor->lock );
574
575    *peerCount = tor->peerCount;
576   
577    peers = (tr_peer_stat_t *) calloc( tor->peerCount, sizeof( tr_peer_stat_t ) );
578    if (peers != NULL)
579    {
580        tr_peer_t * peer;
581        struct in_addr * addr;
582        int i = 0;
583        for( i = 0; i < tor->peerCount; i++ )
584        {
585            peer = tor->peers[i];
586           
587            addr = tr_peerAddress( peer );
588            if( NULL != addr )
589            {
590                tr_netNtop( addr, peers[i].addr,
591                           sizeof( peers[i].addr ) );
592            }
593           
594            peers[i].client = tr_clientForId(tr_peerId(peer));
595           
596            peers[i].isConnected   = tr_peerIsConnected( peer );
597            peers[i].isIncoming    = tr_peerIsIncoming( peer );
598            peers[i].progress      = tr_peerProgress( peer );
599            peers[i].port          = tr_peerPort( peer );
600           
601            if( ( peers[i].isDownloading = tr_peerIsDownloading( peer ) ) )
602            {
603                peers[i].uploadToRate = tr_peerUploadRate( peer );
604            }
605            if( ( peers[i].isUploading = tr_peerIsUploading( peer ) ) )
606            {
607                peers[i].downloadFromRate = tr_peerDownloadRate( peer );
608            }
609        }
610    }
611   
612    tr_lockUnlock( &tor->lock );
613   
614    return peers;
615}
616
617void tr_torrentPeersFree( tr_peer_stat_t * peers, int peerCount )
618{
619    int i;
620
621    if (peers == NULL)
622        return;
623
624    for (i = 0; i < peerCount; i++)
625        free( peers[i].client );
626
627    free( peers );
628}
629
630void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size )
631{
632    int i, j, piece;
633
634    tr_lockLock( &tor->lock );
635    for( i = 0; i < size; i++ )
636    {
637        piece = i * tor->info.pieceCount / size;
638
639        if( tr_cpPieceIsComplete( tor->completion, piece ) )
640        {
641            tab[i] = -1;
642            continue;
643        }
644
645        tab[i] = 0;
646        for( j = 0; j < tor->peerCount; j++ )
647        {
648            if( tr_peerBitfield( tor->peers[j] ) &&
649                tr_bitfieldHas( tr_peerBitfield( tor->peers[j] ), piece ) )
650            {
651                (tab[i])++;
652            }
653        }
654    }
655    tr_lockUnlock( &tor->lock );
656}
657
658void tr_torrentAmountFinished( tr_torrent_t * tor, float * tab, int size )
659{
660    int i, piece;
661
662    tr_lockLock( &tor->lock );
663    for( i = 0; i < size; i++ )
664    {
665        piece = i * tor->info.pieceCount / size;
666        tab[i] = tr_cpPercentBlocksInPiece( tor->completion, piece );
667    }
668    tr_lockUnlock( &tor->lock );
669}
670
671void tr_torrentRemoveSaved( tr_torrent_t * tor ) {
672    tr_metainfoRemoveSaved( tor->info.hashString );
673}
674
675/***********************************************************************
676 * tr_torrentClose
677 ***********************************************************************
678 * Frees memory allocated by tr_torrentInit.
679 **********************************************************************/
680void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor )
681{
682    tr_info_t * inf = &tor->info;
683
684    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
685    {
686        /* Join the thread first */
687        torrentReallyStop( tor );
688    }
689
690    tr_lockLock( &h->acceptLock );
691
692    h->torrentCount--;
693
694    tr_lockClose( &tor->lock );
695    tr_cpClose( tor->completion );
696
697    tr_rcClose( tor->upload );
698    tr_rcClose( tor->download );
699    tr_rcClose( tor->swarmspeed );
700
701    if( tor->destination )
702    {
703        free( tor->destination );
704    }
705
706    tr_metainfoFree( inf );
707
708    if( tor->prev )
709    {
710        tor->prev->next = tor->next;
711    }
712    else
713    {
714        h->torrentList = tor->next;
715    }
716    if( tor->next )
717    {
718        tor->next->prev = tor->prev;
719    }
720    free( tor );
721
722    tr_lockUnlock( &h->acceptLock );
723}
724
725void tr_close( tr_handle_t * h )
726{
727    acceptStop( h );
728    tr_natpmpClose( h->natpmp );
729    tr_upnpClose( h->upnp );
730    tr_chokingClose( h->choking );
731    tr_fdClose( h->fdlimit );
732    tr_rcClose( h->upload );
733    tr_rcClose( h->download );
734    free( h );
735
736    tr_netResolveThreadClose();
737}
738
739/***********************************************************************
740 * downloadLoop
741 **********************************************************************/
742static void downloadLoop( void * _tor )
743{
744    tr_torrent_t * tor = _tor;
745    uint64_t       date1, date2;
746
747    tr_dbg( "Thread started" );
748
749#ifdef SYS_BEOS
750    /* This is required because on BeOS, SIGINT is sent to each thread,
751       which kills them not nicely */
752    signal( SIGINT, SIG_IGN );
753#endif
754
755    tr_lockLock( &tor->lock );
756
757    tr_cpReset( tor->completion );
758    tor->io     = tr_ioInit( tor );
759    tor->status = tr_cpIsSeeding( tor->completion ) ?
760                      TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
761
762    while( !tor->die )
763    {
764        date1 = tr_date();
765
766        /* Are we finished ? */
767        if( ( tor->status & TR_STATUS_DOWNLOAD ) &&
768            tr_cpIsSeeding( tor->completion ) )
769        {
770            /* Done */
771            tor->status = TR_STATUS_SEED;
772                        tor->finished = 1;
773            tr_trackerCompleted( tor->tracker );
774            tr_ioSaveResume( tor->io );
775#ifndef __AMIGAOS4__
776            sync(); /* KLUDGE: all files should be closed and
777                       re-opened in read-only mode instead */
778#endif
779        }
780
781        /* Receive/send messages */
782        tr_peerPulse( tor );
783
784        /* Try to get new peers or to send a message to the tracker */
785        tr_trackerPulse( tor->tracker );
786
787        if( tor->status & TR_STATUS_STOPPED )
788        {
789            break;
790        }
791
792        /* Wait up to 20 ms */
793        date2 = tr_date();
794        if( date2 < date1 + 20 )
795        {
796            tr_lockUnlock( &tor->lock );
797            tr_wait( date1 + 20 - date2 );
798            tr_lockLock( &tor->lock );
799        }
800    }
801
802    tr_lockUnlock( &tor->lock );
803
804    tr_ioClose( tor->io );
805
806    tor->status = TR_STATUS_STOPPED;
807
808    tr_dbg( "Thread exited" );
809}
810
811/***********************************************************************
812 * acceptLoop
813 **********************************************************************/
814static void acceptLoop( void * _h )
815{
816    tr_handle_t * h = _h;
817    uint64_t      date1, date2, lastchoke = 0;
818    int           ii;
819    uint8_t     * hash;
820    tr_torrent_t * tor;
821
822    tr_dbg( "Accept thread started" );
823
824#ifdef SYS_BEOS
825    /* This is required because on BeOS, SIGINT is sent to each thread,
826       which kills them not nicely */
827    signal( SIGINT, SIG_IGN );
828#endif
829
830    tr_lockLock( &h->acceptLock );
831
832    while( !h->acceptDie )
833    {
834        date1 = tr_date();
835
836        /* do NAT-PMP and UPnP pulses here since there's nowhere better */
837        tr_natpmpPulse( h->natpmp );
838        tr_upnpPulse( h->upnp );
839
840        /* Check for incoming connections */
841        if( h->bindSocket > -1 &&
842            h->acceptPeerCount < TR_MAX_PEER_COUNT &&
843            !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
844        {
845            int            s;
846            struct in_addr addr;
847            in_port_t      port;
848            s = tr_netAccept( h->bindSocket, &addr, &port );
849            if( s > -1 )
850            {
851                h->acceptPeers[h->acceptPeerCount++] = tr_peerInit( addr, port, s );
852            }
853            else
854            {
855                tr_fdSocketClosed( h->fdlimit, 0 );
856            }
857        }
858
859        for( ii = 0; ii < h->acceptPeerCount; )
860        {
861            if( tr_peerRead( NULL, h->acceptPeers[ii] ) )
862            {
863                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
864                goto removePeer;
865            }
866            if( NULL != ( hash = tr_peerHash( h->acceptPeers[ii] ) ) )
867            {
868                for( tor = h->torrentList; tor; tor = tor->next )
869                {
870                    tr_lockLock( &tor->lock );
871                    if( tor->status & TR_STATUS_INACTIVE )
872                    {
873                        tr_lockUnlock( &tor->lock );
874                        continue;
875                    }
876
877                    if( 0 == memcmp( tor->info.hash, hash,
878                                     SHA_DIGEST_LENGTH ) )
879                    {
880                      tr_peerAttach( tor, h->acceptPeers[ii] );
881                      tr_lockUnlock( &tor->lock );
882                      goto removePeer;
883                    }
884                    tr_lockUnlock( &tor->lock );
885                }
886                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
887                goto removePeer;
888            }
889            if( date1 > tr_peerDate( h->acceptPeers[ii] ) + 10000 )
890            {
891                /* Give them 10 seconds to send the handshake */
892                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
893                goto removePeer;
894            }
895            ii++;
896            continue;
897           removePeer:
898            h->acceptPeerCount--;
899            memmove( &h->acceptPeers[ii], &h->acceptPeers[ii+1],
900                     ( h->acceptPeerCount - ii ) * sizeof( tr_peer_t * ) );
901        }
902
903        if( date1 > lastchoke + 2000 )
904        {
905            tr_chokingPulse( h->choking );
906            lastchoke = date1;
907        }
908
909        /* Wait up to 20 ms */
910        date2 = tr_date();
911        if( date2 < date1 + 20 )
912        {
913            tr_lockUnlock( &h->acceptLock );
914            tr_wait( date1 + 20 - date2 );
915            tr_lockLock( &h->acceptLock );
916        }
917    }
918
919    tr_lockUnlock( &h->acceptLock );
920
921    tr_dbg( "Accept thread exited" );
922}
923
924/***********************************************************************
925 * acceptStop
926 ***********************************************************************
927 * Joins the accept thread and frees/closes everything related to it.
928 **********************************************************************/
929static void acceptStop( tr_handle_t * h )
930{
931    int ii;
932
933    h->acceptDie = 1;
934    tr_threadJoin( &h->acceptThread );
935    tr_lockClose( &h->acceptLock );
936    tr_dbg( "Accept thread joined" );
937
938    for( ii = 0; ii < h->acceptPeerCount; ii++ )
939    {
940        tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
941    }
942
943    if( h->bindSocket > -1 )
944    {
945        tr_netClose( h->bindSocket );
946        tr_fdSocketClosed( h->fdlimit, 0 );
947    }
948}
Note: See TracBrowser for help on using the repository browser.