source: trunk/libtransmission/session.c @ 5636

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

fix a couple more minor leaks

  • Property svn:keywords set to Date Rev Author Id
File size: 17.5 KB
Line 
1/******************************************************************************
2 * $Id: session.c 5636 2008-04-17 19:54:22Z 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    int i;
419    const int maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
420    const uint64_t deadline = tr_date( ) + maxwait_msec;
421
422    tr_statsClose( h );
423
424    tr_runInEventThread( h, tr_closeImpl, h );
425    while( !h->isClosed && !deadlineReached( deadline ) )
426        tr_wait( 100 );
427
428    tr_eventClose( h );
429    while( h->events && !deadlineReached( deadline ) )
430        tr_wait( 100 );
431
432    tr_fdClose( );
433    tr_lockFree( h->lock );
434    for( i=0; i<h->metainfoLookupCount; ++i )
435        tr_free( h->metainfoLookup[i].filename );
436    tr_free( h->metainfoLookup );
437    tr_free( h->tag );
438    tr_free( h->configDir );
439    tr_free( h->resumeDir );
440    tr_free( h->torrentDir );
441    free( h );
442}
443
444tr_torrent **
445tr_loadTorrents ( tr_handle   * h,
446                  tr_ctor     * ctor,
447                  int         * setmeCount )
448{
449    int i, n = 0;
450    struct stat sb;
451    DIR * odir = NULL;
452    const char * dirname = tr_getTorrentDir( h );
453    tr_torrent ** torrents;
454    tr_list *l=NULL, *list=NULL;
455
456    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
457
458    if( !stat( dirname, &sb )
459        && S_ISDIR( sb.st_mode )
460        && (( odir = opendir ( dirname ) )) )
461    {
462        struct dirent *d;
463        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
464        {
465            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
466            {
467                tr_torrent * tor;
468                char filename[MAX_PATH_LENGTH];
469                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
470                tr_ctorSetMetainfoFromFile( ctor, filename );
471                tor = tr_torrentNew( h, ctor, NULL );
472                if( tor ) {
473                    tr_list_append( &list, tor );
474                    n++;
475                }
476            }
477        }
478        closedir( odir );
479    }
480
481    torrents = tr_new( tr_torrent*, n );
482    for( i=0, l=list; l!=NULL; l=l->next )
483        torrents[i++] = (tr_torrent*) l->data;
484    assert( i==n );
485
486    tr_list_free( &list, NULL );
487
488    if( n )
489        tr_inf( _( "Loaded %d torrents" ), n );
490
491    *setmeCount = n;
492    return torrents;
493}
494
495/***
496****
497***/
498
499void
500tr_setPexEnabled( tr_handle * handle, int isPexEnabled )
501{
502    handle->isPexEnabled = isPexEnabled ? 1 : 0;
503}
504
505int
506tr_isPexEnabled( const tr_handle * handle )
507{
508    return handle->isPexEnabled;
509}
510
511/***
512****
513***/
514
515int
516tr_blocklistGetRuleCount( tr_handle * handle )
517{
518    return _tr_blocklistGetRuleCount( handle->blocklist );
519}
520
521int
522tr_blocklistIsEnabled( const tr_handle * handle )
523{
524    return _tr_blocklistIsEnabled( handle->blocklist );
525}
526
527void
528tr_blocklistSetEnabled( tr_handle * handle, int isEnabled )
529{
530    _tr_blocklistSetEnabled( handle->blocklist, isEnabled );
531}
532
533int
534tr_blocklistExists( const tr_handle * handle )
535{
536    return _tr_blocklistExists( handle->blocklist );
537}
538
539int
540tr_blocklistSetContent( tr_handle  * handle, const char * filename )
541{
542    return _tr_blocklistSetContent( handle->blocklist, filename );
543}
544
545int
546tr_blocklistHasAddress( tr_handle * handle, const struct in_addr * addr )
547{
548    return _tr_blocklistHasAddress( handle->blocklist, addr );
549}
550
551/***
552****
553***/
554
555static int
556compareLookupEntries( const void * va, const void * vb )
557{
558    const struct tr_metainfo_lookup * a = va;
559    const struct tr_metainfo_lookup * b = vb;
560    return strcmp( a->hashString, b->hashString );
561}
562
563static void
564metainfoLookupResort( tr_handle * h )
565{
566    qsort( h->metainfoLookup, 
567           h->metainfoLookupCount,
568           sizeof( struct tr_metainfo_lookup ),
569           compareLookupEntries );
570}
571
572static int
573compareHashStringToLookupEntry( const void * va, const void * vb )
574{
575    const char * a = va;
576    const struct tr_metainfo_lookup * b = vb;
577    return strcmp( a, b->hashString );
578}
579
580const char*
581tr_sessionFindTorrentFile( const tr_handle  * h,
582                           const char       * hashStr )
583{
584    struct tr_metainfo_lookup * l = bsearch( hashStr,
585                                             h->metainfoLookup,
586                                             h->metainfoLookupCount,
587                                             sizeof( struct tr_metainfo_lookup ),
588                                             compareHashStringToLookupEntry );
589    return l ? l->filename : NULL;
590}
591
592static void
593metainfoLookupRescan( tr_handle * h )
594{
595    int i;
596    int n;
597    struct stat sb;
598    const char * dirname = tr_getTorrentDir( h );
599    DIR * odir = NULL;
600    tr_ctor * ctor = NULL;
601    tr_list * list = NULL;
602
603    /* walk through the directory and find the mappings */
604    ctor = tr_ctorNew( h );
605    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
606    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && (( odir = opendir( dirname ))))
607    {
608        struct dirent *d;
609        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
610        {
611            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
612            {
613                tr_info inf;
614                char filename[MAX_PATH_LENGTH];
615                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
616                tr_ctorSetMetainfoFromFile( ctor, filename );
617                if( !tr_torrentParse( h, ctor, &inf ) )
618                {
619                    tr_list_append( &list, tr_strdup( inf.hashString ) );
620                    tr_list_append( &list, tr_strdup( filename ) );
621                    tr_metainfoFree( &inf );
622                }
623            }
624        }
625        closedir( odir );
626    }
627    tr_ctorFree( ctor );
628
629    n = tr_list_size( list ) / 2;
630    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
631    h->metainfoLookupCount = n;
632    for( i=0; i<n; ++i )
633    {
634        char * hashString = tr_list_pop_front( &list );
635        char * filename = tr_list_pop_front( &list );
636
637        memcpy( h->metainfoLookup[i].hashString, hashString, 2*SHA_DIGEST_LENGTH+1 );
638        tr_free( hashString );
639        h->metainfoLookup[i].filename = filename;
640    }
641
642    metainfoLookupResort( h );
643    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
644}
645
646void
647tr_sessionSetTorrentFile( tr_handle    * h,
648                          const char   * hashString,
649                          const char   * filename )
650{
651    struct tr_metainfo_lookup * l = bsearch( hashString,
652                                             h->metainfoLookup,
653                                             h->metainfoLookupCount,
654                                             sizeof( struct tr_metainfo_lookup ),
655                                             compareHashStringToLookupEntry );
656    if( l != NULL )
657    {
658        if( l->filename != filename )
659        {
660            tr_free( l->filename );
661            l->filename = tr_strdup( filename );
662        }
663    }
664    else
665    {
666        const int n = h->metainfoLookupCount++;
667        struct tr_metainfo_lookup * node;
668        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
669                                      h->metainfoLookup,
670                                      h->metainfoLookupCount );
671        node = h->metainfoLookup + n;
672        memcpy( node->hashString, hashString, 2*SHA_DIGEST_LENGTH+1 );
673        node->filename = tr_strdup( filename );
674        metainfoLookupResort( h );
675    }
676}
Note: See TracBrowser for help on using the repository browser.