source: trunk/libtransmission/session.c @ 7352

Last change on this file since 7352 was 7352, checked in by livings124, 12 years ago

#1157 ability to pick a random port in libtransmission; mac preference to pick a random port on launch and on button click

  • Property svn:keywords set to Date Rev Author Id
File size: 31.0 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: session.c 7352 2008-12-11 04:41:23Z livings124 $
11 */
12
13#include <assert.h>
14#include <stdlib.h>
15#include <string.h> /* memcpy */
16
17#include <signal.h>
18#include <sys/types.h> /* stat */
19#include <sys/stat.h> /* stat */
20#include <unistd.h> /* stat */
21#include <dirent.h> /* opendir */
22
23#include "transmission.h"
24#include "bandwidth.h"
25#include "blocklist.h"
26#include "fdlimit.h"
27#include "list.h"
28#include "metainfo.h" /* tr_metainfoFree */
29#include "net.h"
30#include "peer-mgr.h"
31#include "platform.h" /* tr_lock */
32#include "port-forwarding.h"
33#include "rpc-server.h"
34#include "stats.h"
35#include "torrent.h"
36#include "tracker.h"
37#include "trevent.h"
38#include "utils.h"
39#include "web.h"
40#include "crypto.h"
41
42#define PORT_RANDOM_MIN 1024
43#define PORT_RANDOM_MAX 65535
44
45/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
46   characters, where x is the major version number, y is the
47   minor version number, z is the maintenance number, and b
48   designates beta (Azureus-style) */
49uint8_t*
50tr_peerIdNew( void )
51{
52    int          i;
53    int          val;
54    int          total = 0;
55    uint8_t *    buf = tr_new( uint8_t, 21 );
56    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
57    const int    base = 36;
58
59    memcpy( buf, PEERID_PREFIX, 8 );
60
61    for( i = 8; i < 19; ++i )
62    {
63        val = tr_cryptoRandInt( base );
64        total += val;
65        buf[i] = pool[val];
66    }
67
68    val = total % base ? base - ( total % base ) : 0;
69    buf[19] = pool[val];
70    buf[20] = '\0';
71
72    return buf;
73}
74
75const uint8_t*
76tr_getPeerId( void )
77{
78    static uint8_t * id = NULL;
79
80    if( id == NULL )
81        id = tr_peerIdNew( );
82    return id;
83}
84
85/***
86****
87***/
88
89tr_encryption_mode
90tr_sessionGetEncryption( tr_session * session )
91{
92    assert( session );
93
94    return session->encryptionMode;
95}
96
97void
98tr_sessionSetEncryption( tr_session *       session,
99                         tr_encryption_mode mode )
100{
101    assert( session );
102    assert( mode == TR_ENCRYPTION_PREFERRED
103          || mode == TR_ENCRYPTION_REQUIRED
104          || mode == TR_CLEAR_PREFERRED );
105
106    session->encryptionMode = mode;
107}
108
109/***
110****
111***/
112
113static int
114tr_stringEndsWith( const char * str,
115                   const char * end )
116{
117    const size_t slen = strlen( str );
118    const size_t elen = strlen( end );
119
120    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
121}
122
123static void
124loadBlocklists( tr_session * session )
125{
126    int         binCount = 0;
127    int         newCount = 0;
128    struct stat sb;
129    char      * dirname;
130    DIR *       odir = NULL;
131    tr_list *   list = NULL;
132    const tr_bool   isEnabled = session->isBlocklistEnabled;
133
134    /* walk through the directory and find blocklists */
135    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
136    if( !stat( dirname,
137               &sb ) && S_ISDIR( sb.st_mode )
138      && ( ( odir = opendir( dirname ) ) ) )
139    {
140        struct dirent *d;
141        for( d = readdir( odir ); d; d = readdir( odir ) )
142        {
143            char * filename;
144
145            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
146                                                      */
147                continue;
148
149            filename = tr_buildPath( dirname, d->d_name, NULL );
150
151            if( tr_stringEndsWith( filename, ".bin" ) )
152            {
153                /* if we don't already have this blocklist, add it */
154                if( !tr_list_find( list, filename,
155                                   (TrListCompareFunc)strcmp ) )
156                {
157                    tr_list_append( &list,
158                                   _tr_blocklistNew( filename, isEnabled ) );
159                    ++binCount;
160                }
161            }
162            else
163            {
164                /* strip out the file suffix, if there is one, and add ".bin"
165                  instead */
166                tr_blocklist * b;
167                const char *   dot = strrchr( d->d_name, '.' );
168                const int      len = dot ? dot - d->d_name
169                                         : (int)strlen( d->d_name );
170                char         * tmp = tr_strdup_printf(
171                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
172                                        dirname, len, len, d->d_name );
173                b = _tr_blocklistNew( tmp, isEnabled );
174                _tr_blocklistSetContent( b, filename );
175                tr_list_append( &list, b );
176                ++newCount;
177                tr_free( tmp );
178            }
179
180            tr_free( filename );
181        }
182
183        closedir( odir );
184    }
185
186    session->blocklists = list;
187
188    if( binCount )
189        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
190    if( newCount )
191        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
192
193    tr_free( dirname );
194}
195
196/***
197****
198***/
199
200static void metainfoLookupRescan( tr_handle * h );
201
202tr_handle *
203tr_sessionInitFull( const char *       configDir,
204                    const char *       tag,
205                    const char *       downloadDir,
206                    int                isPexEnabled,
207                    int                isPortForwardingEnabled,
208                    int                publicPort,
209                    tr_encryption_mode encryptionMode,
210                    int                useLazyBitfield,
211                    int                useUploadLimit,
212                    int                uploadLimit,
213                    int                useDownloadLimit,
214                    int                downloadLimit,
215                    int                globalPeerLimit,
216                    int                messageLevel,
217                    int                isMessageQueueingEnabled,
218                    int                isBlocklistEnabled,
219                    int                peerSocketTOS,
220                    int                rpcIsEnabled,
221                    tr_port            rpcPort,
222                    int                rpcWhitelistIsEnabled,
223                    const char *       rpcWhitelist,
224                    int                rpcAuthIsEnabled,
225                    const char *       rpcUsername,
226                    const char *       rpcPassword,
227                    int                proxyIsEnabled,
228                    const char *       proxy,
229                    int                proxyPort,
230                    tr_proxy_type      proxyType,
231                    int                proxyAuthIsEnabled,
232                    const char *       proxyUsername,
233                    const char *       proxyPassword )
234{
235    tr_handle * h;
236    char      * filename;
237
238#ifndef WIN32
239    /* Don't exit when writing on a broken socket */
240    signal( SIGPIPE, SIG_IGN );
241#endif
242
243    tr_msgInit( );
244    tr_setMessageLevel( messageLevel );
245    tr_setMessageQueuing( isMessageQueueingEnabled );
246
247    h = tr_new0( tr_handle, 1 );
248    h->lock = tr_lockNew( );
249    h->isPexEnabled = isPexEnabled ? 1 : 0;
250    h->encryptionMode = encryptionMode;
251    h->peerSocketTOS = peerSocketTOS;
252    h->downloadDir = tr_strdup( downloadDir );
253    h->isProxyEnabled = proxyIsEnabled ? 1 : 0;
254    h->proxy = tr_strdup( proxy );
255    h->proxyPort = proxyPort;
256    h->proxyType = proxyType;
257    h->isProxyAuthEnabled = proxyAuthIsEnabled != 0;
258    h->proxyUsername = tr_strdup( proxyUsername );
259    h->proxyPassword = tr_strdup( proxyPassword );
260    h->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */
261    h->so_rcvbuf = 8192;
262
263    if( configDir == NULL )
264        configDir = tr_getDefaultConfigDir( );
265    tr_setConfigDir( h, configDir );
266
267    tr_netInit( ); /* must go before tr_eventInit */
268
269    tr_eventInit( h );
270    while( !h->events )
271        tr_wait( 50 );
272
273    h->tag = tr_strdup( tag );
274    h->peerMgr = tr_peerMgrNew( h );
275
276    h->useLazyBitfield = useLazyBitfield != 0;
277
278    /* Initialize rate and file descripts controls */
279
280    tr_fdInit( globalPeerLimit );
281   
282    /* random port */
283    if ( publicPort == -1 )
284        publicPort = tr_cryptoWeakRandInt(PORT_RANDOM_MAX - PORT_RANDOM_MIN + 1) + PORT_RANDOM_MIN;
285   
286    h->shared = tr_sharedInit( h, isPortForwardingEnabled, publicPort );
287    h->isPortSet = publicPort >= 0;
288
289    h->bandwidth = tr_bandwidthNew( h, NULL );
290    tr_bandwidthSetDesiredSpeed( h->bandwidth, TR_UP, uploadLimit );
291    tr_bandwidthSetDesiredSpeed( h->bandwidth, TR_DOWN, downloadLimit );
292    tr_bandwidthSetLimited( h->bandwidth, TR_UP, useUploadLimit );
293    tr_bandwidthSetLimited( h->bandwidth, TR_DOWN, useDownloadLimit );
294
295    /* first %s is the application name
296       second %s is the version number */
297    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
298
299    /* initialize the blocklist */
300    filename = tr_buildPath( h->configDir, "blocklists", NULL );
301    tr_mkdirp( filename, 0777 );
302    tr_free( filename );
303    h->isBlocklistEnabled = isBlocklistEnabled;
304    loadBlocklists( h );
305
306    tr_statsInit( h );
307
308    h->web = tr_webInit( h );
309    h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort,
310                               rpcWhitelistIsEnabled, rpcWhitelist,
311                               rpcAuthIsEnabled, rpcUsername, rpcPassword );
312
313    metainfoLookupRescan( h );
314
315    return h;
316}
317
318tr_handle *
319tr_sessionInit( const char * configDir,
320                const char * tag )
321{
322    return tr_sessionInitFull( configDir,
323                               TR_DEFAULT_DOWNLOAD_DIR,
324                               tag,
325                               TR_DEFAULT_PEX_ENABLED,
326                               TR_DEFAULT_PORT_FORWARDING_ENABLED,
327                               -1, /* public port */
328                               TR_DEFAULT_ENCRYPTION, /* encryption mode */
329                               TR_DEFAULT_LAZY_BITFIELD_ENABLED,
330                               FALSE, /* use upload speed limit? */
331                               -1, /* upload speed limit */
332                               FALSE, /* use download speed limit? */
333                               -1, /* download speed limit */
334                               TR_DEFAULT_GLOBAL_PEER_LIMIT,
335                               TR_MSG_INF, /* message level */
336                               FALSE, /* is message queueing enabled? */
337                               FALSE, /* is the blocklist enabled? */
338                               TR_DEFAULT_PEER_SOCKET_TOS,
339                               TR_DEFAULT_RPC_ENABLED,
340                               TR_DEFAULT_RPC_PORT,
341                               TR_DEFAULT_RPC_WHITELIST_ENABLED,
342                               TR_DEFAULT_RPC_WHITELIST,
343                               FALSE,
344                               "fnord",
345                               "potzrebie",
346                               TR_DEFAULT_PROXY_ENABLED,
347                               TR_DEFAULT_PROXY,
348                               TR_DEFAULT_PROXY_PORT,
349                               TR_DEFAULT_PROXY_TYPE,
350                               TR_DEFAULT_PROXY_AUTH_ENABLED,
351                               TR_DEFAULT_PROXY_USERNAME,
352                               TR_DEFAULT_PROXY_PASSWORD );
353}
354
355/***
356****
357***/
358
359void
360tr_sessionSetDownloadDir( tr_handle *  handle,
361                          const char * dir )
362{
363    if( handle->downloadDir != dir )
364    {
365        tr_free( handle->downloadDir );
366        handle->downloadDir = tr_strdup( dir );
367    }
368}
369
370const char *
371tr_sessionGetDownloadDir( const tr_handle * handle )
372{
373    return handle->downloadDir;
374}
375
376/***
377****
378***/
379
380void
381tr_globalLock( struct tr_handle * handle )
382{
383    tr_lockLock( handle->lock );
384}
385
386void
387tr_globalUnlock( struct tr_handle * handle )
388{
389    tr_lockUnlock( handle->lock );
390}
391
392tr_bool
393tr_globalIsLocked( const struct tr_handle * handle )
394{
395    return handle && tr_lockHave( handle->lock );
396}
397
398/***********************************************************************
399 * tr_setBindPort
400 ***********************************************************************
401 *
402 **********************************************************************/
403
404struct bind_port_data
405{
406    tr_session * session;
407    tr_port      port;
408};
409
410static void
411tr_setBindPortImpl( void * vdata )
412{
413    struct bind_port_data * data = vdata;
414    tr_session * session = data->session;
415    const tr_port port = data->port;
416
417    session->isPortSet = 1;
418    tr_sharedSetPort( session->shared, port );
419
420    tr_free( data );
421}
422
423void
424tr_sessionSetPeerPort( tr_session * session,
425                       tr_port      port )
426{
427    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
428
429    data->session = session;
430    data->port = port;
431    tr_runInEventThread( session, tr_setBindPortImpl, data );
432}
433
434tr_port
435tr_sessionSetPeerPortRandom( tr_session * session )
436{
437    const tr_port port = tr_cryptoWeakRandInt(PORT_RANDOM_MAX - PORT_RANDOM_MIN + 1) + PORT_RANDOM_MIN;
438    tr_sessionSetPeerPort( session, port);
439    return port;
440}
441
442tr_port
443tr_sessionGetPeerPort( const tr_handle * h )
444{
445    assert( h );
446    return tr_sharedGetPeerPort( h->shared );
447}
448
449tr_port_forwarding
450tr_sessionGetPortForwarding( const tr_handle * h )
451{
452    return tr_sharedTraversalStatus( h->shared );
453}
454
455/***
456****
457***/
458
459void
460tr_sessionSetSpeedLimitEnabled( tr_session      * session,
461                                tr_direction      dir,
462                                int               isLimited )
463{
464    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited );
465}
466
467int
468tr_sessionIsSpeedLimitEnabled( const tr_session  * session,
469                               tr_direction        dir )
470{
471    return tr_bandwidthIsLimited( session->bandwidth, dir );
472}
473
474void
475tr_sessionSetSpeedLimit( tr_session    * session,
476                         tr_direction    dir,
477                         int             desiredSpeed )
478{
479    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, desiredSpeed );
480}
481
482int
483tr_sessionGetSpeedLimit( const tr_session  * session,
484                         tr_direction        dir )
485{
486    return tr_bandwidthGetDesiredSpeed( session->bandwidth, dir );
487}
488
489/***
490****
491***/
492
493void
494tr_sessionSetPeerLimit( tr_handle * handle UNUSED,
495                        uint16_t           maxGlobalPeers )
496{
497    tr_fdSetPeerLimit( maxGlobalPeers );
498}
499
500uint16_t
501tr_sessionGetPeerLimit( const tr_handle * handle UNUSED )
502{
503    return tr_fdGetPeerLimit( );
504}
505
506/***
507****
508***/
509
510double
511tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
512{
513    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
514}
515
516double
517tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
518{
519    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
520}
521
522int
523tr_sessionCountTorrents( const tr_handle * h )
524{
525    return h->torrentCount;
526}
527
528static int
529compareTorrentByCur( const void * va,
530                     const void * vb )
531{
532    const tr_torrent * a = *(const tr_torrent**)va;
533    const tr_torrent * b = *(const tr_torrent**)vb;
534    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
535    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
536
537    if( aCur != bCur )
538        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
539
540    return 0;
541}
542
543static void
544tr_closeAllConnections( void * vsession )
545{
546    tr_handle *   session = vsession;
547    tr_torrent *  tor;
548    int           i, n;
549    tr_torrent ** torrents;
550
551    tr_statsClose( session );
552    tr_sharedShuttingDown( session->shared );
553    tr_rpcClose( &session->rpcServer );
554
555    /* close the torrents.  get the most active ones first so that
556     * if we can't get them all closed in a reasonable amount of time,
557     * at least we get the most important ones first. */
558    tor = NULL;
559    n = session->torrentCount;
560    torrents = tr_new( tr_torrent *, session->torrentCount );
561    for( i = 0; i < n; ++i )
562        torrents[i] = tor = tr_torrentNext( session, tor );
563    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
564    for( i = 0; i < n; ++i )
565        tr_torrentFree( torrents[i] );
566    tr_free( torrents );
567
568    tr_peerMgrFree( session->peerMgr );
569
570    tr_trackerSessionClose( session );
571    tr_list_free( &session->blocklists,
572                  (TrListForeachFunc)_tr_blocklistFree );
573    tr_webClose( &session->web );
574
575    session->isClosed = TRUE;
576}
577
578static int
579deadlineReached( const uint64_t deadline )
580{
581    return tr_date( ) >= deadline;
582}
583
584#define SHUTDOWN_MAX_SECONDS 30
585
586#define dbgmsg( ... ) \
587    do { \
588        if( tr_deepLoggingIsActive( ) ) \
589            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
590    } while( 0 )
591
592void
593tr_sessionClose( tr_handle * session )
594{
595    int            i;
596    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
597    const uint64_t deadline = tr_date( ) + maxwait_msec;
598
599    dbgmsg( "shutting down transmission session %p", session );
600
601    /* close the session */
602    tr_runInEventThread( session, tr_closeAllConnections, session );
603    while( !session->isClosed && !deadlineReached( deadline ) )
604    {
605        dbgmsg(
606            "waiting for the shutdown commands to run in the main thread" );
607        tr_wait( 100 );
608    }
609
610    /* "shared" and "tracker" have live sockets,
611     * so we need to keep the transmission thread alive
612     * for a bit while they tell the router & tracker
613     * that we're closing now */
614    while( ( session->shared
615           || session->tracker ) && !deadlineReached( deadline ) )
616    {
617        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
618                session->shared, session->tracker );
619        tr_wait( 100 );
620    }
621
622    tr_fdClose( );
623
624    /* close the libtransmission thread */
625    tr_eventClose( session );
626    while( session->events && !deadlineReached( deadline ) )
627    {
628        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
629        tr_wait( 100 );
630    }
631
632    /* free the session memory */
633    tr_bandwidthFree( session->bandwidth );
634    tr_lockFree( session->lock );
635    for( i = 0; i < session->metainfoLookupCount; ++i )
636        tr_free( session->metainfoLookup[i].filename );
637    tr_free( session->metainfoLookup );
638    tr_free( session->tag );
639    tr_free( session->configDir );
640    tr_free( session->resumeDir );
641    tr_free( session->torrentDir );
642    tr_free( session->downloadDir );
643    tr_free( session->proxy );
644    tr_free( session->proxyUsername );
645    tr_free( session->proxyPassword );
646    tr_free( session );
647}
648
649tr_torrent **
650tr_sessionLoadTorrents( tr_handle * h,
651                        tr_ctor *   ctor,
652                        int *       setmeCount )
653{
654    int           i, n = 0;
655    struct stat   sb;
656    DIR *         odir = NULL;
657    const char *  dirname = tr_getTorrentDir( h );
658    tr_torrent ** torrents;
659    tr_list *     l = NULL, *list = NULL;
660
661    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
662
663    if( !stat( dirname, &sb )
664      && S_ISDIR( sb.st_mode )
665      && ( ( odir = opendir ( dirname ) ) ) )
666    {
667        struct dirent *d;
668        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
669        {
670            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
671                                                     */
672            {
673                tr_torrent * tor;
674                char * path = tr_buildPath( dirname, d->d_name, NULL );
675                tr_ctorSetMetainfoFromFile( ctor, path );
676                if(( tor = tr_torrentNew( h, ctor, NULL )))
677                {
678                    tr_list_append( &list, tor );
679                    ++n;
680                }
681                tr_free( path );
682            }
683        }
684        closedir( odir );
685    }
686
687    torrents = tr_new( tr_torrent *, n );
688    for( i = 0, l = list; l != NULL; l = l->next )
689        torrents[i++] = (tr_torrent*) l->data;
690    assert( i == n );
691
692    tr_list_free( &list, NULL );
693
694    if( n )
695        tr_inf( _( "Loaded %d torrents" ), n );
696
697    if( setmeCount )
698        *setmeCount = n;
699    return torrents;
700}
701
702/***
703****
704***/
705
706void
707tr_sessionSetPexEnabled( tr_session * session,
708                         tr_bool      enabled )
709{
710    session->isPexEnabled = enabled != 0;
711}
712
713tr_bool
714tr_sessionIsPexEnabled( const tr_session * session )
715{
716    return session->isPexEnabled;
717}
718
719/***
720****
721***/
722
723void
724tr_sessionSetLazyBitfieldEnabled( tr_session * session,
725                                  tr_bool      enabled )
726{
727    session->useLazyBitfield = enabled != 0;
728}
729
730tr_bool
731tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
732{
733    return session->useLazyBitfield;
734}
735
736/***
737****
738***/
739
740void
741tr_sessionSetPortForwardingEnabled( tr_session  * session,
742                                    tr_bool       enabled )
743{
744    tr_globalLock( session );
745    tr_sharedTraversalEnable( session->shared, enabled );
746    tr_globalUnlock( session );
747}
748
749tr_bool
750tr_sessionIsPortForwardingEnabled( const tr_handle * h )
751{
752    return tr_sharedTraversalIsEnabled( h->shared );
753}
754
755/***
756****
757***/
758
759int
760tr_blocklistGetRuleCount( const tr_session * session )
761{
762    int       n = 0;
763    tr_list * l;
764
765    for( l = session->blocklists; l; l = l->next )
766        n += _tr_blocklistGetRuleCount( l->data );
767    return n;
768}
769
770tr_bool
771tr_blocklistIsEnabled( const tr_session * session )
772{
773    return session->isBlocklistEnabled;
774}
775
776void
777tr_blocklistSetEnabled( tr_session * session,
778                        tr_bool      isEnabled )
779{
780    tr_list * l;
781
782    session->isBlocklistEnabled = isEnabled != 0;
783
784    for( l=session->blocklists; l!=NULL; l=l->next )
785        _tr_blocklistSetEnabled( l->data, isEnabled );
786}
787
788tr_bool
789tr_blocklistExists( const tr_session * session )
790{
791    return session->blocklists != NULL;
792}
793
794int
795tr_blocklistSetContent( tr_session * session,
796                        const char * contentFilename )
797{
798    tr_list *      l;
799    tr_blocklist * b;
800    const char *   defaultName = "level1.bin";
801
802    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
803        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
804                               defaultName ) )
805            b = l->data;
806
807    if( !b )
808    {
809        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
810        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
811        tr_list_append( &session->blocklists, b );
812        tr_free( path );
813    }
814
815    return _tr_blocklistSetContent( b, contentFilename );
816}
817
818tr_bool
819tr_sessionIsAddressBlocked( const tr_session * session,
820                            const tr_address * addr )
821{
822    tr_list * l;
823
824    for( l = session->blocklists; l; l = l->next )
825        if( _tr_blocklistHasAddress( l->data, addr ) )
826            return TRUE;
827    return FALSE;
828}
829
830/***
831****
832***/
833
834static int
835compareLookupEntries( const void * va,
836                      const void * vb )
837{
838    const struct tr_metainfo_lookup * a = va;
839    const struct tr_metainfo_lookup * b = vb;
840
841    return strcmp( a->hashString, b->hashString );
842}
843
844static void
845metainfoLookupResort( tr_handle * h )
846{
847    qsort( h->metainfoLookup,
848           h->metainfoLookupCount,
849           sizeof( struct tr_metainfo_lookup ),
850           compareLookupEntries );
851}
852
853static int
854compareHashStringToLookupEntry( const void * va,
855                                const void * vb )
856{
857    const char *                      a = va;
858    const struct tr_metainfo_lookup * b = vb;
859
860    return strcmp( a, b->hashString );
861}
862
863const char*
864tr_sessionFindTorrentFile( const tr_handle * h,
865                           const char *      hashStr )
866{
867    struct tr_metainfo_lookup * l = bsearch( hashStr,
868                                             h->metainfoLookup,
869                                             h->metainfoLookupCount,
870                                             sizeof( struct
871                                                     tr_metainfo_lookup ),
872                                             compareHashStringToLookupEntry );
873
874    return l ? l->filename : NULL;
875}
876
877static void
878metainfoLookupRescan( tr_handle * h )
879{
880    int          i;
881    int          n;
882    struct stat  sb;
883    const char * dirname = tr_getTorrentDir( h );
884    DIR *        odir = NULL;
885    tr_ctor *    ctor = NULL;
886    tr_list *    list = NULL;
887
888    /* walk through the directory and find the mappings */
889    ctor = tr_ctorNew( h );
890    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
891    if( !stat( dirname,
892               &sb ) && S_ISDIR( sb.st_mode )
893      && ( ( odir = opendir( dirname ) ) ) )
894    {
895        struct dirent *d;
896        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
897        {
898            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
899                                                     */
900            {
901                tr_info inf;
902                char * path = tr_buildPath( dirname, d->d_name, NULL );
903                tr_ctorSetMetainfoFromFile( ctor, path );
904                if( !tr_torrentParse( h, ctor, &inf ) )
905                {
906                    tr_list_append( &list, tr_strdup( inf.hashString ) );
907                    tr_list_append( &list, tr_strdup( path ) );
908                    tr_metainfoFree( &inf );
909                }
910                tr_free( path );
911            }
912        }
913        closedir( odir );
914    }
915    tr_ctorFree( ctor );
916
917    n = tr_list_size( list ) / 2;
918    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
919    h->metainfoLookupCount = n;
920    for( i = 0; i < n; ++i )
921    {
922        char * hashString = tr_list_pop_front( &list );
923        char * filename = tr_list_pop_front( &list );
924
925        memcpy( h->metainfoLookup[i].hashString, hashString,
926                2 * SHA_DIGEST_LENGTH + 1 );
927        tr_free( hashString );
928        h->metainfoLookup[i].filename = filename;
929    }
930
931    metainfoLookupResort( h );
932    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
933}
934
935void
936tr_sessionSetTorrentFile( tr_handle *  h,
937                          const char * hashString,
938                          const char * filename )
939{
940    struct tr_metainfo_lookup * l = bsearch( hashString,
941                                             h->metainfoLookup,
942                                             h->metainfoLookupCount,
943                                             sizeof( struct
944                                                     tr_metainfo_lookup ),
945                                             compareHashStringToLookupEntry );
946
947    if( l )
948    {
949        if( l->filename != filename )
950        {
951            tr_free( l->filename );
952            l->filename = tr_strdup( filename );
953        }
954    }
955    else
956    {
957        const int                   n = h->metainfoLookupCount++;
958        struct tr_metainfo_lookup * node;
959        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
960                                      h->metainfoLookup,
961                                      h->metainfoLookupCount );
962        node = h->metainfoLookup + n;
963        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
964        node->filename = tr_strdup( filename );
965        metainfoLookupResort( h );
966    }
967}
968
969tr_torrent*
970tr_torrentNext( tr_handle *  session,
971                tr_torrent * tor )
972{
973    return tor ? tor->next : session->torrentList;
974}
975
976/***
977****
978***/
979
980void
981tr_sessionSetRPCEnabled( tr_session * session,
982                         int          isEnabled )
983{
984    tr_rpcSetEnabled( session->rpcServer, isEnabled );
985}
986
987int
988tr_sessionIsRPCEnabled( const tr_session * session )
989{
990    return tr_rpcIsEnabled( session->rpcServer );
991}
992
993void
994tr_sessionSetRPCPort( tr_session * session,
995                      tr_port      port )
996{
997    tr_rpcSetPort( session->rpcServer, port );
998}
999
1000tr_port
1001tr_sessionGetRPCPort( const tr_session * session )
1002{
1003    return tr_rpcGetPort( session->rpcServer );
1004}
1005
1006void
1007tr_sessionSetRPCCallback( tr_session * session,
1008                          tr_rpc_func  func,
1009                          void *       user_data )
1010{
1011    session->rpc_func = func;
1012    session->rpc_func_user_data = user_data;
1013}
1014
1015void
1016tr_sessionSetRPCWhitelist( tr_session * session,
1017                           const char * whitelist )
1018{
1019    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1020}
1021
1022char*
1023tr_sessionGetRPCWhitelist( const tr_session * session )
1024{
1025    return tr_rpcGetWhitelist( session->rpcServer );
1026}
1027
1028void
1029tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1030                                  int          isEnabled )
1031{
1032    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1033}
1034
1035int
1036tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1037{
1038    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1039}
1040
1041
1042void
1043tr_sessionSetRPCPassword( tr_session * session,
1044                          const char * password )
1045{
1046    tr_rpcSetPassword( session->rpcServer, password );
1047}
1048
1049char*
1050tr_sessionGetRPCPassword( const tr_session * session )
1051{
1052    return tr_rpcGetPassword( session->rpcServer );
1053}
1054
1055void
1056tr_sessionSetRPCUsername( tr_session * session,
1057                          const char * username )
1058{
1059    tr_rpcSetUsername( session->rpcServer, username );
1060}
1061
1062char*
1063tr_sessionGetRPCUsername( const tr_session * session )
1064{
1065    return tr_rpcGetUsername( session->rpcServer );
1066}
1067
1068void
1069tr_sessionSetRPCPasswordEnabled( tr_session * session,
1070                                 int          isEnabled )
1071{
1072    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1073}
1074
1075int
1076tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1077{
1078    return tr_rpcIsPasswordEnabled( session->rpcServer );
1079}
1080
1081/***
1082****
1083***/
1084
1085int
1086tr_sessionIsProxyEnabled( const tr_session * session )
1087{
1088    return session->isProxyEnabled;
1089}
1090
1091void
1092tr_sessionSetProxyEnabled( tr_session * session,
1093                           tr_bool      isEnabled )
1094{
1095    session->isProxyEnabled = isEnabled != 0;
1096}
1097
1098tr_proxy_type
1099tr_sessionGetProxyType( const tr_session * session )
1100{
1101    return session->proxyType;
1102}
1103
1104void
1105tr_sessionSetProxyType( tr_session *  session,
1106                        tr_proxy_type type )
1107{
1108    session->proxyType = type;
1109}
1110
1111const char*
1112tr_sessionGetProxy( const tr_session * session )
1113{
1114    return session->proxy;
1115}
1116
1117int
1118tr_sessionGetProxyPort( const tr_session * session )
1119{
1120    return session->proxyPort;
1121}
1122
1123void
1124tr_sessionSetProxy( tr_session * session,
1125                    const char * proxy )
1126{
1127    if( proxy != session->proxy )
1128    {
1129        tr_free( session->proxy );
1130        session->proxy = tr_strdup( proxy );
1131    }
1132}
1133
1134void
1135tr_sessionSetProxyPort( tr_session * session,
1136                        tr_port      port )
1137{
1138    session->proxyPort = port;
1139}
1140
1141int
1142tr_sessionIsProxyAuthEnabled( const tr_session * session )
1143{
1144    return session->isProxyAuthEnabled;
1145}
1146
1147void
1148tr_sessionSetProxyAuthEnabled( tr_session * session,
1149                               tr_bool      isEnabled )
1150{
1151    session->isProxyAuthEnabled = isEnabled != 0;
1152}
1153
1154const char*
1155tr_sessionGetProxyUsername( const tr_session * session )
1156{
1157    return session->proxyUsername;
1158}
1159
1160void
1161tr_sessionSetProxyUsername( tr_session * session,
1162                            const char * username )
1163{
1164    if( username != session->proxyUsername )
1165    {
1166        tr_free( session->proxyUsername );
1167        session->proxyUsername = tr_strdup( username );
1168    }
1169}
1170
1171const char*
1172tr_sessionGetProxyPassword( const tr_session * session )
1173{
1174    return session->proxyPassword;
1175}
1176
1177void
1178tr_sessionSetProxyPassword( tr_session * session,
1179                            const char * password )
1180{
1181    if( password != session->proxyPassword )
1182    {
1183        tr_free( session->proxyPassword );
1184        session->proxyPassword = tr_strdup( password );
1185    }
1186}
1187
Note: See TracBrowser for help on using the repository browser.