source: trunk/libtransmission/transmission.c @ 1149

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

Merge scrape branch:

Automatically scrape trackers as needed.
If tracker supplies a trackerid then use it (untested).
Use tracker's min interval, clamped to the same range as interval.
Show total completed downloads in the MacOS X frontend.

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