source: branches/1.4x/libtransmission/session.c @ 7301

Last change on this file since 7301 was 7301, checked in by charles, 13 years ago

(1.4x libT) #1569: tr_sessionIsSpeedLimitEnabled() returns wrong value

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