source: trunk/libtransmission/transmission.c @ 1286

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

make function names a little more specific

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