source: trunk/libtransmission/transmission.c @ 815

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

Rework the message stuff again to be easier on the frontend.

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