source: trunk/libtransmission/transmission.c @ 791

Last change on this file since 791 was 791, checked in by joshe, 16 years ago

Unbreak BeOS build.

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