source: trunk/libtransmission/transmission.c @ 788

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

Try to keep track of the overall speed of the swarm.
Patch by Denis Ahrens.

  • Property svn:keywords set to Date Rev Author Id
File size: 22.8 KB
Line 
1/******************************************************************************
2 * $Id: transmission.c 788 2006-08-16 19:21:09Z 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_info_t * inf = &tor->info;
414    int i;
415
416    tor->statCur = ( tor->statCur + 1 ) % 2;
417    s = &tor->stats[tor->statCur];
418
419    if( ( tor->status & TR_STATUS_STOPPED ) ||
420        ( ( tor->status & TR_STATUS_STOPPING ) &&
421          tr_date() > tor->stopDate + 60000 ) )
422    {
423        torrentReallyStop( tor );
424        tor->status = TR_STATUS_PAUSE;
425    }
426
427    tr_lockLock( &tor->lock );
428
429    s->status = tor->status;
430    s->error  = tor->error;
431    memcpy( s->trackerError, tor->trackerError,
432            sizeof( s->trackerError ) );
433
434    s->peersTotal       = 0;
435    s->peersUploading   = 0;
436    s->peersDownloading = 0;
437   
438    tr_peer_t * peer;
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_lockLock( &tor->lock );
498
499    *peerCount = tor->peerCount;
500   
501    tr_peer_stat_t * peers = (tr_peer_stat_t *) calloc( tor->peerCount, sizeof( tr_peer_stat_t ) );
502    if (peers != NULL)
503    {
504        tr_peer_t * peer;
505        struct in_addr * addr;
506        int i = 0;
507        for( i = 0; i < tor->peerCount; i++ )
508        {
509            peer = tor->peers[i];
510           
511            addr = tr_peerAddress( peer );
512            if( NULL != addr )
513            {
514                inet_ntop( AF_INET, addr, peers[i].addr,
515                           sizeof( peers[i].addr ) );
516            }
517           
518            peers[i].client = tr_clientForId(tr_peerId(peer));
519           
520            peers[i].isConnected = tr_peerIsConnected(peer);
521            peers[i].isDownloading = tr_peerIsDownloading(peer);
522            peers[i].isUploading = tr_peerIsUploading(peer);
523        }
524    }
525   
526    tr_lockUnlock( &tor->lock );
527   
528    return peers;
529}
530
531void tr_torrentPeersFree( tr_peer_stat_t * peers, int peerCount )
532{
533    if (peers == NULL)
534        return;
535
536    int i;
537    for (i = 0; i < peerCount; i++)
538        free( peers[i].client );
539
540    free( peers );
541}
542
543void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size )
544{
545    int i, j, piece;
546
547    tr_lockLock( &tor->lock );
548    for( i = 0; i < size; i++ )
549    {
550        piece = i * tor->info.pieceCount / size;
551
552        if( tr_cpPieceIsComplete( tor->completion, piece ) )
553        {
554            tab[i] = -1;
555            continue;
556        }
557
558        tab[i] = 0;
559        for( j = 0; j < tor->peerCount; j++ )
560        {
561            if( tr_peerBitfield( tor->peers[j] ) &&
562                tr_bitfieldHas( tr_peerBitfield( tor->peers[j] ), piece ) )
563            {
564                (tab[i])++;
565            }
566        }
567    }
568    tr_lockUnlock( &tor->lock );
569}
570
571void tr_torrentRemoveSaved( tr_torrent_t * tor ) {
572    tr_metainfoRemoveSaved( tor->info.hashString );
573}
574
575/***********************************************************************
576 * tr_torrentClose
577 ***********************************************************************
578 * Frees memory allocated by tr_torrentInit.
579 **********************************************************************/
580void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor )
581{
582    tr_info_t * inf = &tor->info;
583
584    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
585    {
586        /* Join the thread first */
587        torrentReallyStop( tor );
588    }
589
590    tr_lockLock( &h->acceptLock );
591
592    h->torrentCount--;
593
594    tr_lockClose( &tor->lock );
595    tr_cpClose( tor->completion );
596
597    tr_rcClose( tor->upload );
598    tr_rcClose( tor->download );
599    tr_rcClose( tor->swarmspeed );
600
601    if( tor->destination )
602    {
603        free( tor->destination );
604    }
605    free( inf->pieces );
606    free( inf->files );
607
608    if( tor->prev )
609    {
610        tor->prev->next = tor->next;
611    }
612    else
613    {
614        h->torrentList = tor->next;
615    }
616    if( tor->next )
617    {
618        tor->next->prev = tor->prev;
619    }
620    free( tor );
621
622    tr_lockUnlock( &h->acceptLock );
623}
624
625void tr_close( tr_handle_t * h )
626{
627    acceptStop( h );
628    tr_chokingClose( h->choking );
629    tr_fdClose( h->fdlimit );
630    tr_rcClose( h->upload );
631    tr_rcClose( h->download );
632    free( h );
633
634    tr_netResolveThreadClose();
635}
636
637/***********************************************************************
638 * downloadLoop
639 **********************************************************************/
640static void downloadLoop( void * _tor )
641{
642    tr_torrent_t * tor = _tor;
643    uint64_t       date1, date2;
644
645    tr_dbg( "Thread started" );
646
647#ifdef SYS_BEOS
648    /* This is required because on BeOS, SIGINT is sent to each thread,
649       which kills them not nicely */
650    signal( SIGINT, SIG_IGN );
651#endif
652
653    tr_lockLock( &tor->lock );
654
655    tr_cpReset( tor->completion );
656    tor->io     = tr_ioInit( tor );
657    tor->status = tr_cpIsSeeding( tor->completion ) ?
658                      TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
659
660    while( !tor->die )
661    {
662        date1 = tr_date();
663
664        /* Are we finished ? */
665        if( ( tor->status & TR_STATUS_DOWNLOAD ) &&
666            tr_cpIsSeeding( tor->completion ) )
667        {
668            /* Done */
669            tor->status = TR_STATUS_SEED;
670                        tor->finished = 1;
671            tr_trackerCompleted( tor->tracker );
672            tr_ioSaveResume( tor->io );
673#ifndef __AMIGAOS4__
674            sync(); /* KLUDGE: all files should be closed and
675                       re-opened in read-only mode instead */
676#endif
677        }
678
679        /* Receive/send messages */
680        tr_peerPulse( tor );
681
682        /* Try to get new peers or to send a message to the tracker */
683        tr_trackerPulse( tor->tracker );
684
685        if( tor->status & TR_STATUS_STOPPED )
686        {
687            break;
688        }
689
690        /* Wait up to 20 ms */
691        date2 = tr_date();
692        if( date2 < date1 + 20 )
693        {
694            tr_lockUnlock( &tor->lock );
695            tr_wait( date1 + 20 - date2 );
696            tr_lockLock( &tor->lock );
697        }
698    }
699
700    tr_lockUnlock( &tor->lock );
701
702    tr_ioClose( tor->io );
703
704    tor->status = TR_STATUS_STOPPED;
705
706    tr_dbg( "Thread exited" );
707}
708
709/***********************************************************************
710 * acceptLoop
711 **********************************************************************/
712static void acceptLoop( void * _h )
713{
714    tr_handle_t * h = _h;
715    uint64_t      date1, date2, lastchoke = 0;
716    int           ii;
717    uint8_t     * hash;
718    tr_torrent_t * tor;
719
720    tr_dbg( "Accept thread started" );
721
722#ifdef SYS_BEOS
723    /* This is required because on BeOS, SIGINT is sent to each thread,
724       which kills them not nicely */
725    signal( SIGINT, SIG_IGN );
726#endif
727
728    tr_lockLock( &h->acceptLock );
729
730    while( !h->acceptDie )
731    {
732        date1 = tr_date();
733
734        /* Check for incoming connections */
735        if( h->bindSocket > -1 &&
736            h->acceptPeerCount < TR_MAX_PEER_COUNT &&
737            !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
738        {
739            int            s;
740            struct in_addr addr;
741            in_port_t      port;
742            s = tr_netAccept( h->bindSocket, &addr, &port );
743            if( s > -1 )
744            {
745                h->acceptPeers[h->acceptPeerCount++] = tr_peerInit( addr, port, s );
746            }
747            else
748            {
749                tr_fdSocketClosed( h->fdlimit, 0 );
750            }
751        }
752
753        for( ii = 0; ii < h->acceptPeerCount; )
754        {
755            if( tr_peerRead( NULL, h->acceptPeers[ii] ) )
756            {
757                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
758                goto removePeer;
759            }
760            if( NULL != ( hash = tr_peerHash( h->acceptPeers[ii] ) ) )
761            {
762                for( tor = h->torrentList; tor; tor = tor->next )
763                {
764                    tr_lockLock( &tor->lock );
765                    if( 0 == memcmp( tor->info.hash, hash,
766                                     SHA_DIGEST_LENGTH ) )
767                    {
768                      tr_peerAttach( tor, h->acceptPeers[ii] );
769                      tr_lockUnlock( &tor->lock );
770                      goto removePeer;
771                    }
772                    tr_lockUnlock( &tor->lock );
773                }
774                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
775                goto removePeer;
776            }
777            if( date1 > tr_peerDate( h->acceptPeers[ii] ) + 10000 )
778            {
779                /* Give them 10 seconds to send the handshake */
780                tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
781                goto removePeer;
782            }
783            ii++;
784            continue;
785           removePeer:
786            h->acceptPeerCount--;
787            memmove( &h->acceptPeers[ii], &h->acceptPeers[ii+1],
788                     ( h->acceptPeerCount - ii ) * sizeof( tr_peer_t * ) );
789        }
790
791        if( date1 > lastchoke + 2000 )
792        {
793            tr_chokingPulse( h->choking );
794            lastchoke = date1;
795        }
796
797        /* Wait up to 20 ms */
798        date2 = tr_date();
799        if( date2 < date1 + 20 )
800        {
801            tr_lockUnlock( &h->acceptLock );
802            tr_wait( date1 + 20 - date2 );
803            tr_lockLock( &h->acceptLock );
804        }
805    }
806
807    tr_lockUnlock( &h->acceptLock );
808
809    tr_dbg( "Accept thread exited" );
810}
811
812/***********************************************************************
813 * acceptStop
814 ***********************************************************************
815 * Joins the accept thread and frees/closes everything related to it.
816 **********************************************************************/
817static void acceptStop( tr_handle_t * h )
818{
819    int ii;
820
821    h->acceptDie = 1;
822    tr_threadJoin( &h->acceptThread );
823    tr_lockClose( &h->acceptLock );
824    tr_dbg( "Accept thread joined" );
825
826    for( ii = 0; ii < h->acceptPeerCount; ii++ )
827    {
828        tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
829    }
830
831    if( h->bindSocket > -1 )
832    {
833        tr_netClose( h->bindSocket );
834        tr_fdSocketClosed( h->fdlimit, 0 );
835    }
836}
Note: See TracBrowser for help on using the repository browser.