source: trunk/libtransmission/session.c @ 7366

Last change on this file since 7366 was 7366, checked in by charles, 12 years ago

(trunk libT) #1593: Setting upload to 0 kills all download

  • Property svn:keywords set to Date Rev Author Id
File size: 31.6 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 7366 2008-12-13 22:52:15Z 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#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_sessionSetSpeedLimit       ( h, TR_UP,   uploadLimit );
291    tr_sessionSetSpeedLimitEnabled( h, TR_UP,   useUploadLimit );
292    tr_sessionSetSpeedLimit       ( h, TR_DOWN, downloadLimit );
293    tr_sessionSetSpeedLimitEnabled( h, 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
459static void
460updateBandwidth( tr_session * session, tr_direction dir )
461{
462    const tr_bool zeroCase = session->speedLimit[dir] < 1 && session->isSpeedLimited[dir];
463
464    tr_bandwidthSetLimited( session->bandwidth, dir, session->isSpeedLimited[dir] && !zeroCase );
465
466    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, session->speedLimit[dir] );
467}
468
469void
470tr_sessionSetSpeedLimitEnabled( tr_session      * session,
471                                tr_direction      dir,
472                                tr_bool           isLimited )
473{
474    assert( session );
475    assert( dir==TR_UP || dir==TR_DOWN );
476
477    session->isSpeedLimited[dir] = isLimited;
478    updateBandwidth( session, dir );
479}
480
481void
482tr_sessionSetSpeedLimit( tr_session    * session,
483                         tr_direction    dir,
484                         int             desiredSpeed )
485{
486    assert( session );
487    assert( dir==TR_UP || dir==TR_DOWN );
488
489    session->speedLimit[dir] = desiredSpeed;
490    updateBandwidth( session, dir );
491}
492
493tr_bool
494tr_sessionIsSpeedLimitEnabled( const tr_session  * session,
495                               tr_direction        dir )
496{
497    assert( session );
498    assert( dir==TR_UP || dir==TR_DOWN );
499
500    return session->isSpeedLimited[dir];
501}
502
503int
504tr_sessionGetSpeedLimit( const tr_session  * session,
505                         tr_direction        dir )
506{
507    assert( session );
508    assert( dir==TR_UP || dir==TR_DOWN );
509
510    return session->speedLimit[dir];
511}
512
513/***
514****
515***/
516
517void
518tr_sessionSetPeerLimit( tr_handle * handle UNUSED,
519                        uint16_t           maxGlobalPeers )
520{
521    tr_fdSetPeerLimit( maxGlobalPeers );
522}
523
524uint16_t
525tr_sessionGetPeerLimit( const tr_handle * handle UNUSED )
526{
527    return tr_fdGetPeerLimit( );
528}
529
530/***
531****
532***/
533
534double
535tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
536{
537    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
538}
539
540double
541tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
542{
543    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
544}
545
546int
547tr_sessionCountTorrents( const tr_handle * h )
548{
549    return h->torrentCount;
550}
551
552static int
553compareTorrentByCur( const void * va,
554                     const void * vb )
555{
556    const tr_torrent * a = *(const tr_torrent**)va;
557    const tr_torrent * b = *(const tr_torrent**)vb;
558    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
559    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
560
561    if( aCur != bCur )
562        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
563
564    return 0;
565}
566
567static void
568tr_closeAllConnections( void * vsession )
569{
570    tr_handle *   session = vsession;
571    tr_torrent *  tor;
572    int           i, n;
573    tr_torrent ** torrents;
574
575    tr_statsClose( session );
576    tr_sharedShuttingDown( session->shared );
577    tr_rpcClose( &session->rpcServer );
578
579    /* close the torrents.  get the most active ones first so that
580     * if we can't get them all closed in a reasonable amount of time,
581     * at least we get the most important ones first. */
582    tor = NULL;
583    n = session->torrentCount;
584    torrents = tr_new( tr_torrent *, session->torrentCount );
585    for( i = 0; i < n; ++i )
586        torrents[i] = tor = tr_torrentNext( session, tor );
587    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
588    for( i = 0; i < n; ++i )
589        tr_torrentFree( torrents[i] );
590    tr_free( torrents );
591
592    tr_peerMgrFree( session->peerMgr );
593
594    tr_trackerSessionClose( session );
595    tr_list_free( &session->blocklists,
596                  (TrListForeachFunc)_tr_blocklistFree );
597    tr_webClose( &session->web );
598
599    session->isClosed = TRUE;
600}
601
602static int
603deadlineReached( const uint64_t deadline )
604{
605    return tr_date( ) >= deadline;
606}
607
608#define SHUTDOWN_MAX_SECONDS 30
609
610#define dbgmsg( ... ) \
611    do { \
612        if( tr_deepLoggingIsActive( ) ) \
613            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
614    } while( 0 )
615
616void
617tr_sessionClose( tr_handle * session )
618{
619    int            i;
620    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
621    const uint64_t deadline = tr_date( ) + maxwait_msec;
622
623    dbgmsg( "shutting down transmission session %p", session );
624
625    /* close the session */
626    tr_runInEventThread( session, tr_closeAllConnections, session );
627    while( !session->isClosed && !deadlineReached( deadline ) )
628    {
629        dbgmsg(
630            "waiting for the shutdown commands to run in the main thread" );
631        tr_wait( 100 );
632    }
633
634    /* "shared" and "tracker" have live sockets,
635     * so we need to keep the transmission thread alive
636     * for a bit while they tell the router & tracker
637     * that we're closing now */
638    while( ( session->shared
639           || session->tracker ) && !deadlineReached( deadline ) )
640    {
641        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
642                session->shared, session->tracker );
643        tr_wait( 100 );
644    }
645
646    tr_fdClose( );
647
648    /* close the libtransmission thread */
649    tr_eventClose( session );
650    while( session->events && !deadlineReached( deadline ) )
651    {
652        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
653        tr_wait( 100 );
654    }
655
656    /* free the session memory */
657    tr_bandwidthFree( session->bandwidth );
658    tr_lockFree( session->lock );
659    for( i = 0; i < session->metainfoLookupCount; ++i )
660        tr_free( session->metainfoLookup[i].filename );
661    tr_free( session->metainfoLookup );
662    tr_free( session->tag );
663    tr_free( session->configDir );
664    tr_free( session->resumeDir );
665    tr_free( session->torrentDir );
666    tr_free( session->downloadDir );
667    tr_free( session->proxy );
668    tr_free( session->proxyUsername );
669    tr_free( session->proxyPassword );
670    tr_free( session );
671}
672
673tr_torrent **
674tr_sessionLoadTorrents( tr_handle * h,
675                        tr_ctor *   ctor,
676                        int *       setmeCount )
677{
678    int           i, n = 0;
679    struct stat   sb;
680    DIR *         odir = NULL;
681    const char *  dirname = tr_getTorrentDir( h );
682    tr_torrent ** torrents;
683    tr_list *     l = NULL, *list = NULL;
684
685    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
686
687    if( !stat( dirname, &sb )
688      && S_ISDIR( sb.st_mode )
689      && ( ( odir = opendir ( dirname ) ) ) )
690    {
691        struct dirent *d;
692        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
693        {
694            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
695                                                     */
696            {
697                tr_torrent * tor;
698                char * path = tr_buildPath( dirname, d->d_name, NULL );
699                tr_ctorSetMetainfoFromFile( ctor, path );
700                if(( tor = tr_torrentNew( h, ctor, NULL )))
701                {
702                    tr_list_append( &list, tor );
703                    ++n;
704                }
705                tr_free( path );
706            }
707        }
708        closedir( odir );
709    }
710
711    torrents = tr_new( tr_torrent *, n );
712    for( i = 0, l = list; l != NULL; l = l->next )
713        torrents[i++] = (tr_torrent*) l->data;
714    assert( i == n );
715
716    tr_list_free( &list, NULL );
717
718    if( n )
719        tr_inf( _( "Loaded %d torrents" ), n );
720
721    if( setmeCount )
722        *setmeCount = n;
723    return torrents;
724}
725
726/***
727****
728***/
729
730void
731tr_sessionSetPexEnabled( tr_session * session,
732                         tr_bool      enabled )
733{
734    session->isPexEnabled = enabled != 0;
735}
736
737tr_bool
738tr_sessionIsPexEnabled( const tr_session * session )
739{
740    return session->isPexEnabled;
741}
742
743/***
744****
745***/
746
747void
748tr_sessionSetLazyBitfieldEnabled( tr_session * session,
749                                  tr_bool      enabled )
750{
751    session->useLazyBitfield = enabled != 0;
752}
753
754tr_bool
755tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
756{
757    return session->useLazyBitfield;
758}
759
760/***
761****
762***/
763
764void
765tr_sessionSetPortForwardingEnabled( tr_session  * session,
766                                    tr_bool       enabled )
767{
768    tr_globalLock( session );
769    tr_sharedTraversalEnable( session->shared, enabled );
770    tr_globalUnlock( session );
771}
772
773tr_bool
774tr_sessionIsPortForwardingEnabled( const tr_handle * h )
775{
776    return tr_sharedTraversalIsEnabled( h->shared );
777}
778
779/***
780****
781***/
782
783int
784tr_blocklistGetRuleCount( const tr_session * session )
785{
786    int       n = 0;
787    tr_list * l;
788
789    for( l = session->blocklists; l; l = l->next )
790        n += _tr_blocklistGetRuleCount( l->data );
791    return n;
792}
793
794tr_bool
795tr_blocklistIsEnabled( const tr_session * session )
796{
797    return session->isBlocklistEnabled;
798}
799
800void
801tr_blocklistSetEnabled( tr_session * session,
802                        tr_bool      isEnabled )
803{
804    tr_list * l;
805
806    session->isBlocklistEnabled = isEnabled != 0;
807
808    for( l=session->blocklists; l!=NULL; l=l->next )
809        _tr_blocklistSetEnabled( l->data, isEnabled );
810}
811
812tr_bool
813tr_blocklistExists( const tr_session * session )
814{
815    return session->blocklists != NULL;
816}
817
818int
819tr_blocklistSetContent( tr_session * session,
820                        const char * contentFilename )
821{
822    tr_list *      l;
823    tr_blocklist * b;
824    const char *   defaultName = "level1.bin";
825
826    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
827        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
828                               defaultName ) )
829            b = l->data;
830
831    if( !b )
832    {
833        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
834        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
835        tr_list_append( &session->blocklists, b );
836        tr_free( path );
837    }
838
839    return _tr_blocklistSetContent( b, contentFilename );
840}
841
842tr_bool
843tr_sessionIsAddressBlocked( const tr_session * session,
844                            const tr_address * addr )
845{
846    tr_list * l;
847
848    for( l = session->blocklists; l; l = l->next )
849        if( _tr_blocklistHasAddress( l->data, addr ) )
850            return TRUE;
851    return FALSE;
852}
853
854/***
855****
856***/
857
858static int
859compareLookupEntries( const void * va,
860                      const void * vb )
861{
862    const struct tr_metainfo_lookup * a = va;
863    const struct tr_metainfo_lookup * b = vb;
864
865    return strcmp( a->hashString, b->hashString );
866}
867
868static void
869metainfoLookupResort( tr_handle * h )
870{
871    qsort( h->metainfoLookup,
872           h->metainfoLookupCount,
873           sizeof( struct tr_metainfo_lookup ),
874           compareLookupEntries );
875}
876
877static int
878compareHashStringToLookupEntry( const void * va,
879                                const void * vb )
880{
881    const char *                      a = va;
882    const struct tr_metainfo_lookup * b = vb;
883
884    return strcmp( a, b->hashString );
885}
886
887const char*
888tr_sessionFindTorrentFile( const tr_handle * h,
889                           const char *      hashStr )
890{
891    struct tr_metainfo_lookup * l = bsearch( hashStr,
892                                             h->metainfoLookup,
893                                             h->metainfoLookupCount,
894                                             sizeof( struct
895                                                     tr_metainfo_lookup ),
896                                             compareHashStringToLookupEntry );
897
898    return l ? l->filename : NULL;
899}
900
901static void
902metainfoLookupRescan( tr_handle * h )
903{
904    int          i;
905    int          n;
906    struct stat  sb;
907    const char * dirname = tr_getTorrentDir( h );
908    DIR *        odir = NULL;
909    tr_ctor *    ctor = NULL;
910    tr_list *    list = NULL;
911
912    /* walk through the directory and find the mappings */
913    ctor = tr_ctorNew( h );
914    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
915    if( !stat( dirname,
916               &sb ) && S_ISDIR( sb.st_mode )
917      && ( ( odir = opendir( dirname ) ) ) )
918    {
919        struct dirent *d;
920        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
921        {
922            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
923                                                     */
924            {
925                tr_info inf;
926                char * path = tr_buildPath( dirname, d->d_name, NULL );
927                tr_ctorSetMetainfoFromFile( ctor, path );
928                if( !tr_torrentParse( h, ctor, &inf ) )
929                {
930                    tr_list_append( &list, tr_strdup( inf.hashString ) );
931                    tr_list_append( &list, tr_strdup( path ) );
932                    tr_metainfoFree( &inf );
933                }
934                tr_free( path );
935            }
936        }
937        closedir( odir );
938    }
939    tr_ctorFree( ctor );
940
941    n = tr_list_size( list ) / 2;
942    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
943    h->metainfoLookupCount = n;
944    for( i = 0; i < n; ++i )
945    {
946        char * hashString = tr_list_pop_front( &list );
947        char * filename = tr_list_pop_front( &list );
948
949        memcpy( h->metainfoLookup[i].hashString, hashString,
950                2 * SHA_DIGEST_LENGTH + 1 );
951        tr_free( hashString );
952        h->metainfoLookup[i].filename = filename;
953    }
954
955    metainfoLookupResort( h );
956    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
957}
958
959void
960tr_sessionSetTorrentFile( tr_handle *  h,
961                          const char * hashString,
962                          const char * filename )
963{
964    struct tr_metainfo_lookup * l = bsearch( hashString,
965                                             h->metainfoLookup,
966                                             h->metainfoLookupCount,
967                                             sizeof( struct
968                                                     tr_metainfo_lookup ),
969                                             compareHashStringToLookupEntry );
970
971    if( l )
972    {
973        if( l->filename != filename )
974        {
975            tr_free( l->filename );
976            l->filename = tr_strdup( filename );
977        }
978    }
979    else
980    {
981        const int                   n = h->metainfoLookupCount++;
982        struct tr_metainfo_lookup * node;
983        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
984                                      h->metainfoLookup,
985                                      h->metainfoLookupCount );
986        node = h->metainfoLookup + n;
987        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
988        node->filename = tr_strdup( filename );
989        metainfoLookupResort( h );
990    }
991}
992
993tr_torrent*
994tr_torrentNext( tr_handle *  session,
995                tr_torrent * tor )
996{
997    return tor ? tor->next : session->torrentList;
998}
999
1000/***
1001****
1002***/
1003
1004void
1005tr_sessionSetRPCEnabled( tr_session * session,
1006                         int          isEnabled )
1007{
1008    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1009}
1010
1011int
1012tr_sessionIsRPCEnabled( const tr_session * session )
1013{
1014    return tr_rpcIsEnabled( session->rpcServer );
1015}
1016
1017void
1018tr_sessionSetRPCPort( tr_session * session,
1019                      tr_port      port )
1020{
1021    tr_rpcSetPort( session->rpcServer, port );
1022}
1023
1024tr_port
1025tr_sessionGetRPCPort( const tr_session * session )
1026{
1027    return tr_rpcGetPort( session->rpcServer );
1028}
1029
1030void
1031tr_sessionSetRPCCallback( tr_session * session,
1032                          tr_rpc_func  func,
1033                          void *       user_data )
1034{
1035    session->rpc_func = func;
1036    session->rpc_func_user_data = user_data;
1037}
1038
1039void
1040tr_sessionSetRPCWhitelist( tr_session * session,
1041                           const char * whitelist )
1042{
1043    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1044}
1045
1046char*
1047tr_sessionGetRPCWhitelist( const tr_session * session )
1048{
1049    return tr_rpcGetWhitelist( session->rpcServer );
1050}
1051
1052void
1053tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1054                                  int          isEnabled )
1055{
1056    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1057}
1058
1059int
1060tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1061{
1062    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1063}
1064
1065
1066void
1067tr_sessionSetRPCPassword( tr_session * session,
1068                          const char * password )
1069{
1070    tr_rpcSetPassword( session->rpcServer, password );
1071}
1072
1073char*
1074tr_sessionGetRPCPassword( const tr_session * session )
1075{
1076    return tr_rpcGetPassword( session->rpcServer );
1077}
1078
1079void
1080tr_sessionSetRPCUsername( tr_session * session,
1081                          const char * username )
1082{
1083    tr_rpcSetUsername( session->rpcServer, username );
1084}
1085
1086char*
1087tr_sessionGetRPCUsername( const tr_session * session )
1088{
1089    return tr_rpcGetUsername( session->rpcServer );
1090}
1091
1092void
1093tr_sessionSetRPCPasswordEnabled( tr_session * session,
1094                                 int          isEnabled )
1095{
1096    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1097}
1098
1099int
1100tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1101{
1102    return tr_rpcIsPasswordEnabled( session->rpcServer );
1103}
1104
1105/***
1106****
1107***/
1108
1109int
1110tr_sessionIsProxyEnabled( const tr_session * session )
1111{
1112    return session->isProxyEnabled;
1113}
1114
1115void
1116tr_sessionSetProxyEnabled( tr_session * session,
1117                           tr_bool      isEnabled )
1118{
1119    session->isProxyEnabled = isEnabled != 0;
1120}
1121
1122tr_proxy_type
1123tr_sessionGetProxyType( const tr_session * session )
1124{
1125    return session->proxyType;
1126}
1127
1128void
1129tr_sessionSetProxyType( tr_session *  session,
1130                        tr_proxy_type type )
1131{
1132    session->proxyType = type;
1133}
1134
1135const char*
1136tr_sessionGetProxy( const tr_session * session )
1137{
1138    return session->proxy;
1139}
1140
1141int
1142tr_sessionGetProxyPort( const tr_session * session )
1143{
1144    return session->proxyPort;
1145}
1146
1147void
1148tr_sessionSetProxy( tr_session * session,
1149                    const char * proxy )
1150{
1151    if( proxy != session->proxy )
1152    {
1153        tr_free( session->proxy );
1154        session->proxy = tr_strdup( proxy );
1155    }
1156}
1157
1158void
1159tr_sessionSetProxyPort( tr_session * session,
1160                        tr_port      port )
1161{
1162    session->proxyPort = port;
1163}
1164
1165int
1166tr_sessionIsProxyAuthEnabled( const tr_session * session )
1167{
1168    return session->isProxyAuthEnabled;
1169}
1170
1171void
1172tr_sessionSetProxyAuthEnabled( tr_session * session,
1173                               tr_bool      isEnabled )
1174{
1175    session->isProxyAuthEnabled = isEnabled != 0;
1176}
1177
1178const char*
1179tr_sessionGetProxyUsername( const tr_session * session )
1180{
1181    return session->proxyUsername;
1182}
1183
1184void
1185tr_sessionSetProxyUsername( tr_session * session,
1186                            const char * username )
1187{
1188    if( username != session->proxyUsername )
1189    {
1190        tr_free( session->proxyUsername );
1191        session->proxyUsername = tr_strdup( username );
1192    }
1193}
1194
1195const char*
1196tr_sessionGetProxyPassword( const tr_session * session )
1197{
1198    return session->proxyPassword;
1199}
1200
1201void
1202tr_sessionSetProxyPassword( tr_session * session,
1203                            const char * password )
1204{
1205    if( password != session->proxyPassword )
1206    {
1207        tr_free( session->proxyPassword );
1208        session->proxyPassword = tr_strdup( password );
1209    }
1210}
1211
Note: See TracBrowser for help on using the repository browser.