source: trunk/libtransmission/session.c @ 5635

Last change on this file since 5635 was 5635, checked in by charles, 14 years ago

fix minor memory leak in tr_initFull()

  • Property svn:keywords set to Date Rev Author Id
File size: 17.3 KB
Line 
1/******************************************************************************
2 * $Id: session.c 5635 2008-04-17 18:46:51Z charles $
3 *
4 * Copyright (c) 2005-2008 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 <assert.h>
26#include <stdlib.h>
27#include <string.h> /* memcpy */
28
29#include <signal.h>
30#include <sys/types.h> /* stat */
31#include <sys/stat.h> /* stat */
32#include <unistd.h> /* stat */
33#include <dirent.h> /* opendir */
34
35#include "transmission.h"
36#include "blocklist.h"
37#include "fdlimit.h"
38#include "list.h"
39#include "metainfo.h" /* tr_metainfoFree */
40#include "net.h"
41#include "peer-mgr.h"
42#include "platform.h" /* tr_lock */
43#include "port-forwarding.h"
44#include "ratecontrol.h"
45#include "stats.h"
46#include "torrent.h"
47#include "tracker.h"
48#include "trevent.h"
49#include "utils.h"
50
51/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
52   characters, where x is the major version number, y is the
53   minor version number, z is the maintenance number, and b
54   designates beta (Azureus-style) */
55uint8_t*
56tr_peerIdNew( void )
57{
58    int i;
59    int val;
60    int total = 0;
61    uint8_t * buf = tr_new( uint8_t, 21 );
62    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
63    const int base = 36;
64
65    memcpy( buf, PEERID_PREFIX, 8 );
66
67    for( i=8; i<19; ++i ) {
68        val = tr_rand( base );
69        total += val;
70        buf[i] = pool[val];
71    }
72
73    val = total % base ? base - (total % base) : 0;
74    total += val;
75    buf[19] = pool[val];
76    buf[20] = '\0';
77
78    return buf;
79}
80
81const uint8_t*
82tr_getPeerId( void )
83{
84    static uint8_t * id = NULL;
85    if( id == NULL )
86        id = tr_peerIdNew( );
87    return id;
88}
89
90/***
91****
92***/
93
94tr_encryption_mode
95tr_getEncryptionMode( tr_handle * handle )
96{
97    assert( handle != NULL );
98
99    return handle->encryptionMode;
100}
101
102void
103tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
104{
105    assert( handle != NULL );
106    assert( mode==TR_ENCRYPTION_PREFERRED
107         || mode==TR_ENCRYPTION_REQUIRED
108         || mode==TR_PLAINTEXT_PREFERRED );
109
110    handle->encryptionMode = mode;
111}
112
113/***
114****
115***/
116
117static void metainfoLookupRescan( tr_handle * h );
118
119tr_handle *
120tr_initFull( const char * configDir,
121             const char * tag,
122             int          isPexEnabled,
123             int          isPortForwardingEnabled,
124             int          publicPort,
125             int          encryptionMode,
126             int          isUploadLimitEnabled,
127             int          uploadLimit,
128             int          isDownloadLimitEnabled,
129             int          downloadLimit,
130             int          globalPeerLimit,
131             int          messageLevel,
132             int          isMessageQueueingEnabled,
133             int          isBlocklistEnabled,
134             int          peerSocketTOS )
135{
136    tr_handle * h;
137    char filename[MAX_PATH_LENGTH];
138
139#ifndef WIN32
140    /* Don't exit when writing on a broken socket */
141    signal( SIGPIPE, SIG_IGN );
142#endif
143
144    if( configDir == NULL )
145        configDir = tr_getDefaultConfigDir( );
146
147    tr_msgInit( );
148    tr_setMessageLevel( messageLevel );
149    tr_setMessageQueuing( isMessageQueueingEnabled );
150
151    h = tr_new0( tr_handle, 1 );
152    h->lock = tr_lockNew( );
153    h->isPexEnabled = isPexEnabled ? 1 : 0;
154    h->encryptionMode = encryptionMode;
155    h->peerSocketTOS = peerSocketTOS;
156
157    tr_setConfigDir( h, configDir );
158
159    tr_netInit(); /* must go before tr_eventInit */
160
161    tr_eventInit( h );
162    while( !h->events )
163        tr_wait( 50 );
164
165    h->tag = tr_strdup( tag );
166    h->peerMgr = tr_peerMgrNew( h );
167
168    /* Initialize rate and file descripts controls */
169
170    h->upload = tr_rcInit();
171    tr_rcSetLimit( h->upload, uploadLimit );
172    h->useUploadLimit = isUploadLimitEnabled;
173
174    h->download = tr_rcInit();
175    tr_rcSetLimit( h->download, downloadLimit );
176    h->useDownloadLimit = isDownloadLimitEnabled;
177
178    tr_fdInit( globalPeerLimit );
179    h->shared = tr_sharedInit( h, isPortForwardingEnabled, publicPort );
180    h->isPortSet = publicPort >= 0;
181
182    /* first %s is the application name
183       second %s is the version number */
184    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
185
186    /* initialize the blocklist */
187    tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", NULL );
188    tr_mkdirp( filename, 0777 );
189    tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", "level1.bin", NULL );
190    h->blocklist = _tr_blocklistNew( filename, isBlocklistEnabled );
191
192    tr_statsInit( h );
193
194    metainfoLookupRescan( h );
195
196    return h;
197}
198
199tr_handle *
200tr_init( const char * configDir,
201         const char * tag )
202{
203    return tr_initFull( configDir,
204                        tag,
205                        TR_DEFAULT_PEX_ENABLED,
206                        TR_DEFAULT_PORT_FORWARDING_ENABLED,
207                        -1, /* public port */
208                        TR_ENCRYPTION_PREFERRED, /* encryption mode */
209                        FALSE, /* use upload speed limit? */ 
210                        -1, /* upload speed limit */
211                        FALSE, /* use download speed limit? */
212                        -1, /* download speed limit */
213                        TR_DEFAULT_GLOBAL_PEER_LIMIT,
214                        TR_MSG_INF, /* message level */
215                        FALSE, /* is message queueing enabled? */
216                        FALSE, /* is the blocklist enabled? */
217                        TR_DEFAULT_PEER_SOCKET_TOS );
218}
219
220/***
221****
222***/
223
224void
225tr_globalLock( struct tr_handle * handle )
226{
227    tr_lockLock( handle->lock );
228}
229
230void
231tr_globalUnlock( struct tr_handle * handle )
232{
233    tr_lockUnlock( handle->lock );
234}
235
236int
237tr_globalIsLocked( const struct tr_handle * handle )
238{
239    return handle && tr_lockHave( handle->lock );
240}
241
242/***********************************************************************
243 * tr_setBindPort
244 ***********************************************************************
245 *
246 **********************************************************************/
247
248struct bind_port_data
249{
250    tr_handle * handle;
251    int port;
252};
253
254static void
255tr_setBindPortImpl( void * vdata )
256{
257    struct bind_port_data * data = vdata;
258    tr_handle * handle = data->handle;
259    const int port = data->port;
260
261    handle->isPortSet = 1;
262    tr_sharedSetPort( handle->shared, port );
263
264    tr_free( data );
265}
266
267void
268tr_setBindPort( tr_handle * handle, int port )
269{
270    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
271    data->handle = handle;
272    data->port = port;
273    tr_runInEventThread( handle, tr_setBindPortImpl, data );
274}
275
276int
277tr_getPublicPort( const tr_handle * h )
278{
279    assert( h != NULL );
280    return tr_sharedGetPublicPort( h->shared );
281}
282
283void tr_natTraversalEnable( tr_handle * h, int enable )
284{
285    tr_globalLock( h );
286    tr_sharedTraversalEnable( h->shared, enable );
287    tr_globalUnlock( h );
288}
289
290const tr_handle_status *
291tr_handleStatus( tr_handle * h )
292{
293    tr_handle_status * s;
294
295    h->statCur = ( h->statCur + 1 ) % 2;
296    s = &h->stats[h->statCur];
297
298    tr_globalLock( h );
299
300    s->natTraversalStatus = tr_sharedTraversalStatus( h->shared );
301    s->publicPort = tr_sharedGetPublicPort( h->shared );
302
303    tr_globalUnlock( h );
304
305    return s;
306}
307
308/***
309****
310***/
311
312void
313tr_setUseGlobalSpeedLimit( tr_handle  * h,
314                           int          up_or_down,
315                           int          use_flag )
316{
317    if( up_or_down == TR_UP )
318        h->useUploadLimit = use_flag ? 1 : 0;
319    else
320        h->useDownloadLimit = use_flag ? 1 : 0;
321}
322
323void
324tr_setGlobalSpeedLimit( tr_handle  * h,
325                        int          up_or_down,
326                        int          KiB_sec )
327{
328    if( up_or_down == TR_DOWN )
329        tr_rcSetLimit( h->download, KiB_sec );
330    else
331        tr_rcSetLimit( h->upload, KiB_sec );
332}
333
334void
335tr_getGlobalSpeedLimit( tr_handle  * h,
336                        int          up_or_down,
337                        int        * setme_enabled,
338                        int          * setme_KiBsec )
339{
340    if( setme_enabled != NULL )
341       *setme_enabled = up_or_down==TR_UP ? h->useUploadLimit
342                                          : h->useDownloadLimit;
343    if( setme_KiBsec != NULL )
344       *setme_KiBsec = tr_rcGetLimit( up_or_down==TR_UP ? h->upload
345                                                        : h->download );
346}
347
348
349void
350tr_setGlobalPeerLimit( tr_handle * handle UNUSED,
351                       uint16_t    maxGlobalPeers )
352{
353    tr_fdSetPeerLimit( maxGlobalPeers );
354}
355
356uint16_t
357tr_getGlobalPeerLimit( const tr_handle * handle UNUSED )
358{
359    return tr_fdGetPeerLimit( );
360}
361
362void
363tr_torrentRates( tr_handle * h, float * toClient, float * toPeer )
364{
365    tr_globalLock( h );
366
367    if( toClient )
368        *toClient = tr_rcRate( h->download );
369    if( toPeer )
370        *toPeer = tr_rcRate( h->upload );
371
372    tr_globalUnlock( h );
373}
374
375int
376tr_torrentCount( const tr_handle * h )
377{
378    return h->torrentCount;
379}
380
381static void
382tr_closeImpl( void * vh )
383{
384    tr_handle * h = vh;
385    tr_torrent * t;
386
387    tr_sharedShuttingDown( h->shared );
388    tr_trackerShuttingDown( h );
389
390    _tr_blocklistFree( h->blocklist );
391    h->blocklist = NULL;
392
393    for( t=h->torrentList; t!=NULL; ) {
394        tr_torrent * tmp = t;
395        t = t->next;
396        tr_torrentClose( tmp );
397    }
398
399    tr_peerMgrFree( h->peerMgr );
400
401    tr_rcClose( h->upload );
402    tr_rcClose( h->download );
403   
404    h->isClosed = TRUE;
405}
406
407static int
408deadlineReached( const uint64_t deadline )
409{
410    return tr_date( ) >= deadline;
411}
412
413#define SHUTDOWN_MAX_SECONDS 30
414
415void
416tr_close( tr_handle * h )
417{
418    const int maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
419    const uint64_t deadline = tr_date( ) + maxwait_msec;
420
421    tr_statsClose( h );
422
423    tr_runInEventThread( h, tr_closeImpl, h );
424    while( !h->isClosed && !deadlineReached( deadline ) )
425        tr_wait( 100 );
426
427    tr_eventClose( h );
428    while( h->events && !deadlineReached( deadline ) )
429        tr_wait( 100 );
430
431    tr_fdClose( );
432    tr_lockFree( h->lock );
433    tr_free( h->tag );
434    tr_free( h->configDir );
435    tr_free( h->resumeDir );
436    tr_free( h->torrentDir );
437    free( h );
438}
439
440tr_torrent **
441tr_loadTorrents ( tr_handle   * h,
442                  tr_ctor     * ctor,
443                  int         * setmeCount )
444{
445    int i, n = 0;
446    struct stat sb;
447    DIR * odir = NULL;
448    const char * dirname = tr_getTorrentDir( h );
449    tr_torrent ** torrents;
450    tr_list *l=NULL, *list=NULL;
451
452    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
453
454    if( !stat( dirname, &sb )
455        && S_ISDIR( sb.st_mode )
456        && (( odir = opendir ( dirname ) )) )
457    {
458        struct dirent *d;
459        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
460        {
461            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
462            {
463                tr_torrent * tor;
464                char filename[MAX_PATH_LENGTH];
465                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
466                tr_ctorSetMetainfoFromFile( ctor, filename );
467                tor = tr_torrentNew( h, ctor, NULL );
468                if( tor ) {
469                    tr_list_append( &list, tor );
470                    n++;
471                }
472            }
473        }
474        closedir( odir );
475    }
476
477    torrents = tr_new( tr_torrent*, n );
478    for( i=0, l=list; l!=NULL; l=l->next )
479        torrents[i++] = (tr_torrent*) l->data;
480    assert( i==n );
481
482    tr_list_free( &list, NULL );
483
484    if( n )
485        tr_inf( _( "Loaded %d torrents" ), n );
486
487    *setmeCount = n;
488    return torrents;
489}
490
491/***
492****
493***/
494
495void
496tr_setPexEnabled( tr_handle * handle, int isPexEnabled )
497{
498    handle->isPexEnabled = isPexEnabled ? 1 : 0;
499}
500
501int
502tr_isPexEnabled( const tr_handle * handle )
503{
504    return handle->isPexEnabled;
505}
506
507/***
508****
509***/
510
511int
512tr_blocklistGetRuleCount( tr_handle * handle )
513{
514    return _tr_blocklistGetRuleCount( handle->blocklist );
515}
516
517int
518tr_blocklistIsEnabled( const tr_handle * handle )
519{
520    return _tr_blocklistIsEnabled( handle->blocklist );
521}
522
523void
524tr_blocklistSetEnabled( tr_handle * handle, int isEnabled )
525{
526    _tr_blocklistSetEnabled( handle->blocklist, isEnabled );
527}
528
529int
530tr_blocklistExists( const tr_handle * handle )
531{
532    return _tr_blocklistExists( handle->blocklist );
533}
534
535int
536tr_blocklistSetContent( tr_handle  * handle, const char * filename )
537{
538    return _tr_blocklistSetContent( handle->blocklist, filename );
539}
540
541int
542tr_blocklistHasAddress( tr_handle * handle, const struct in_addr * addr )
543{
544    return _tr_blocklistHasAddress( handle->blocklist, addr );
545}
546
547/***
548****
549***/
550
551static int
552compareLookupEntries( const void * va, const void * vb )
553{
554    const struct tr_metainfo_lookup * a = va;
555    const struct tr_metainfo_lookup * b = vb;
556    return strcmp( a->hashString, b->hashString );
557}
558
559static void
560metainfoLookupResort( tr_handle * h )
561{
562    qsort( h->metainfoLookup, 
563           h->metainfoLookupCount,
564           sizeof( struct tr_metainfo_lookup ),
565           compareLookupEntries );
566}
567
568static int
569compareHashStringToLookupEntry( const void * va, const void * vb )
570{
571    const char * a = va;
572    const struct tr_metainfo_lookup * b = vb;
573    return strcmp( a, b->hashString );
574}
575
576const char*
577tr_sessionFindTorrentFile( const tr_handle  * h,
578                           const char       * hashStr )
579{
580    struct tr_metainfo_lookup * l = bsearch( hashStr,
581                                             h->metainfoLookup,
582                                             h->metainfoLookupCount,
583                                             sizeof( struct tr_metainfo_lookup ),
584                                             compareHashStringToLookupEntry );
585    return l ? l->filename : NULL;
586}
587
588static void
589metainfoLookupRescan( tr_handle * h )
590{
591    int i;
592    int n;
593    struct stat sb;
594    const char * dirname = tr_getTorrentDir( h );
595    DIR * odir = NULL;
596    tr_ctor * ctor = NULL;
597    tr_list * list = NULL;
598
599    /* walk through the directory and find the mappings */
600    ctor = tr_ctorNew( h );
601    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
602    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && (( odir = opendir( dirname ))))
603    {
604        struct dirent *d;
605        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
606        {
607            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
608            {
609                tr_info inf;
610                char filename[MAX_PATH_LENGTH];
611                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
612                tr_ctorSetMetainfoFromFile( ctor, filename );
613                if( !tr_torrentParse( h, ctor, &inf ) )
614                {
615                    tr_list_append( &list, tr_strdup( inf.hashString ) );
616                    tr_list_append( &list, tr_strdup( filename ) );
617                    tr_metainfoFree( &inf );
618                }
619            }
620        }
621        closedir( odir );
622    }
623    tr_ctorFree( ctor );
624
625    n = tr_list_size( list ) / 2;
626    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
627    h->metainfoLookupCount = n;
628    for( i=0; i<n; ++i )
629    {
630        char * hashString = tr_list_pop_front( &list );
631        char * filename = tr_list_pop_front( &list );
632
633        memcpy( h->metainfoLookup[i].hashString, hashString, 2*SHA_DIGEST_LENGTH+1 );
634        tr_free( hashString );
635        h->metainfoLookup[i].filename = filename;
636    }
637
638    metainfoLookupResort( h );
639    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
640}
641
642void
643tr_sessionSetTorrentFile( tr_handle    * h,
644                          const char   * hashString,
645                          const char   * filename )
646{
647    struct tr_metainfo_lookup * l = bsearch( hashString,
648                                             h->metainfoLookup,
649                                             h->metainfoLookupCount,
650                                             sizeof( struct tr_metainfo_lookup ),
651                                             compareHashStringToLookupEntry );
652    if( l != NULL )
653    {
654        if( l->filename != filename )
655        {
656            tr_free( l->filename );
657            l->filename = tr_strdup( filename );
658        }
659    }
660    else
661    {
662        const int n = h->metainfoLookupCount++;
663        struct tr_metainfo_lookup * node;
664        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
665                                      h->metainfoLookup,
666                                      h->metainfoLookupCount );
667        node = h->metainfoLookup + n;
668        memcpy( node->hashString, hashString, 2*SHA_DIGEST_LENGTH+1 );
669        node->filename = tr_strdup( filename );
670        metainfoLookupResort( h );
671    }
672}
Note: See TracBrowser for help on using the repository browser.