source: trunk/libtransmission/session.c @ 7147

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

(libT) #1468: another stab at getting the peer transfer speeds both fast and a little more consistent.

  • Property svn:keywords set to Date Rev Author Id
File size: 30.7 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 7147 2008-11-24 04:21:23Z 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    h->uploadLimit = uploadLimit;
278    h->useUploadLimit = useUploadLimit;
279    h->downloadLimit = downloadLimit;
280    h->useDownloadLimit = useDownloadLimit;
281
282    tr_fdInit( globalPeerLimit );
283    h->shared = tr_sharedInit( h, isPortForwardingEnabled, publicPort );
284    h->isPortSet = publicPort >= 0;
285
286    h->bandwidth[TR_UP] = tr_bandwidthNew( h );
287    h->bandwidth[TR_DOWN] = tr_bandwidthNew( h );
288
289    /* first %s is the application name
290       second %s is the version number */
291    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
292
293    /* initialize the blocklist */
294    filename = tr_buildPath( h->configDir, "blocklists", NULL );
295    tr_mkdirp( filename, 0777 );
296    tr_free( filename );
297    h->isBlocklistEnabled = isBlocklistEnabled;
298    loadBlocklists( h );
299
300    tr_statsInit( h );
301
302    h->web = tr_webInit( h );
303    h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort,
304                               rpcWhitelistIsEnabled, rpcWhitelist,
305                               rpcAuthIsEnabled, rpcUsername, rpcPassword );
306
307    metainfoLookupRescan( h );
308
309    return h;
310}
311
312tr_handle *
313tr_sessionInit( const char * configDir,
314                const char * tag )
315{
316    return tr_sessionInitFull( configDir,
317                               TR_DEFAULT_DOWNLOAD_DIR,
318                               tag,
319                               TR_DEFAULT_PEX_ENABLED,
320                               TR_DEFAULT_PORT_FORWARDING_ENABLED,
321                               -1, /* public port */
322                               TR_DEFAULT_ENCRYPTION, /* encryption mode */
323                               TR_DEFAULT_LAZY_BITFIELD_ENABLED,
324                               FALSE, /* use upload speed limit? */
325                               -1, /* upload speed limit */
326                               FALSE, /* use download speed limit? */
327                               -1, /* download speed limit */
328                               TR_DEFAULT_GLOBAL_PEER_LIMIT,
329                               TR_MSG_INF, /* message level */
330                               FALSE, /* is message queueing enabled? */
331                               FALSE, /* is the blocklist enabled? */
332                               TR_DEFAULT_PEER_SOCKET_TOS,
333                               TR_DEFAULT_RPC_ENABLED,
334                               TR_DEFAULT_RPC_PORT,
335                               TR_DEFAULT_RPC_WHITELIST_ENABLED,
336                               TR_DEFAULT_RPC_WHITELIST,
337                               FALSE,
338                               "fnord",
339                               "potzrebie",
340                               TR_DEFAULT_PROXY_ENABLED,
341                               TR_DEFAULT_PROXY,
342                               TR_DEFAULT_PROXY_PORT,
343                               TR_DEFAULT_PROXY_TYPE,
344                               TR_DEFAULT_PROXY_AUTH_ENABLED,
345                               TR_DEFAULT_PROXY_USERNAME,
346                               TR_DEFAULT_PROXY_PASSWORD );
347}
348
349/***
350****
351***/
352
353void
354tr_sessionSetDownloadDir( tr_handle *  handle,
355                          const char * dir )
356{
357    if( handle->downloadDir != dir )
358    {
359        tr_free( handle->downloadDir );
360        handle->downloadDir = tr_strdup( dir );
361    }
362}
363
364const char *
365tr_sessionGetDownloadDir( const tr_handle * handle )
366{
367    return handle->downloadDir;
368}
369
370/***
371****
372***/
373
374void
375tr_globalLock( struct tr_handle * handle )
376{
377    tr_lockLock( handle->lock );
378}
379
380void
381tr_globalUnlock( struct tr_handle * handle )
382{
383    tr_lockUnlock( handle->lock );
384}
385
386int
387tr_globalIsLocked( const struct tr_handle * handle )
388{
389    return handle && tr_lockHave( handle->lock );
390}
391
392/***********************************************************************
393 * tr_setBindPort
394 ***********************************************************************
395 *
396 **********************************************************************/
397
398struct bind_port_data
399{
400    tr_handle *  handle;
401    int          port;
402};
403
404static void
405tr_setBindPortImpl( void * vdata )
406{
407    struct bind_port_data * data = vdata;
408    tr_handle *             handle = data->handle;
409    const int               port = data->port;
410
411    handle->isPortSet = 1;
412    tr_sharedSetPort( handle->shared, port );
413
414    tr_free( data );
415}
416
417void
418tr_sessionSetPeerPort( tr_handle * handle,
419                       int         port )
420{
421    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
422
423    data->handle = handle;
424    data->port = port;
425    tr_runInEventThread( handle, tr_setBindPortImpl, data );
426}
427
428int
429tr_sessionGetPeerPort( const tr_handle * h )
430{
431    assert( h );
432    return tr_sharedGetPeerPort( h->shared );
433}
434
435tr_port_forwarding
436tr_sessionGetPortForwarding( const tr_handle * h )
437{
438    return tr_sharedTraversalStatus( h->shared );
439}
440
441/***
442****
443***/
444
445void
446tr_sessionSetSpeedLimitEnabled( tr_handle *  h,
447                                tr_direction direction,
448                                int          use_flag )
449{
450    assert( h );
451    assert( direction == TR_UP || direction == TR_DOWN );
452
453    if( direction == TR_UP )
454        h->useUploadLimit = use_flag ? 1 : 0;
455    else
456        h->useDownloadLimit = use_flag ? 1 : 0;
457}
458
459int
460tr_sessionIsSpeedLimitEnabled( const tr_handle * h,
461                               tr_direction      direction )
462{
463    return direction == TR_UP ? h->useUploadLimit : h->useDownloadLimit;
464}
465
466void
467tr_sessionSetSpeedLimit( tr_handle *  h,
468                         tr_direction direction,
469                         int          KiB_sec )
470{
471    if( direction == TR_DOWN )
472        h->downloadLimit = KiB_sec;
473    else
474        h->uploadLimit = KiB_sec;
475}
476
477int
478tr_sessionGetSpeedLimit( const tr_handle * h,
479                         tr_direction      direction )
480{
481    return direction == TR_UP ? h->uploadLimit : h->downloadLimit;
482}
483
484/***
485****
486***/
487
488void
489tr_sessionSetPeerLimit( tr_handle * handle UNUSED,
490                        uint16_t           maxGlobalPeers )
491{
492    tr_fdSetPeerLimit( maxGlobalPeers );
493}
494
495uint16_t
496tr_sessionGetPeerLimit( const tr_handle * handle UNUSED )
497{
498    return tr_fdGetPeerLimit( );
499}
500
501/***
502****
503***/
504
505double
506tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
507{
508    assert( dir==TR_UP || dir==TR_DOWN );
509
510    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth[dir] ) : 0.0;
511}
512
513double
514tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
515{
516    assert( dir==TR_UP || dir==TR_DOWN );
517
518    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth[dir] ) : 0.0;
519}
520
521int
522tr_sessionCountTorrents( const tr_handle * h )
523{
524    return h->torrentCount;
525}
526
527static int
528compareTorrentByCur( const void * va,
529                     const void * vb )
530{
531    const tr_torrent * a = *(const tr_torrent**)va;
532    const tr_torrent * b = *(const tr_torrent**)vb;
533    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
534    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
535
536    if( aCur != bCur )
537        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
538
539    return 0;
540}
541
542static void
543tr_closeAllConnections( void * vsession )
544{
545    tr_handle *   session = vsession;
546    tr_torrent *  tor;
547    int           i, n;
548    tr_torrent ** torrents;
549
550    tr_statsClose( session );
551    tr_sharedShuttingDown( session->shared );
552    tr_rpcClose( &session->rpcServer );
553
554    /* close the torrents.  get the most active ones first so that
555     * if we can't get them all closed in a reasonable amount of time,
556     * at least we get the most important ones first. */
557    tor = NULL;
558    n = session->torrentCount;
559    torrents = tr_new( tr_torrent *, session->torrentCount );
560    for( i = 0; i < n; ++i )
561        torrents[i] = tor = tr_torrentNext( session, tor );
562    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
563    for( i = 0; i < n; ++i )
564        tr_torrentFree( torrents[i] );
565    tr_free( torrents );
566
567    tr_peerMgrFree( session->peerMgr );
568
569    tr_trackerSessionClose( session );
570    tr_list_free( &session->blocklists,
571                  (TrListForeachFunc)_tr_blocklistFree );
572    tr_webClose( &session->web );
573
574    session->isClosed = TRUE;
575}
576
577static int
578deadlineReached( const uint64_t deadline )
579{
580    return tr_date( ) >= deadline;
581}
582
583#define SHUTDOWN_MAX_SECONDS 30
584
585#define dbgmsg( ... ) \
586    do { \
587        if( tr_deepLoggingIsActive( ) ) \
588            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
589    } while( 0 )
590
591void
592tr_sessionClose( tr_handle * session )
593{
594    int            i;
595    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
596    const uint64_t deadline = tr_date( ) + maxwait_msec;
597
598    dbgmsg( "shutting down transmission session %p", session );
599
600    /* close the session */
601    tr_runInEventThread( session, tr_closeAllConnections, session );
602    while( !session->isClosed && !deadlineReached( deadline ) )
603    {
604        dbgmsg(
605            "waiting for the shutdown commands to run in the main thread" );
606        tr_wait( 100 );
607    }
608
609    /* "shared" and "tracker" have live sockets,
610     * so we need to keep the transmission thread alive
611     * for a bit while they tell the router & tracker
612     * that we're closing now */
613    while( ( session->shared
614           || session->tracker ) && !deadlineReached( deadline ) )
615    {
616        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
617                session->shared, session->tracker );
618        tr_wait( 100 );
619    }
620
621    tr_fdClose( );
622
623    /* close the libtransmission thread */
624    tr_eventClose( session );
625    while( session->events && !deadlineReached( deadline ) )
626    {
627        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
628        tr_wait( 100 );
629    }
630
631    /* free the session memory */
632    tr_bandwidthFree( session->bandwidth[TR_UP] );
633    tr_bandwidthFree( session->bandwidth[TR_DOWN] );
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_handle * handle,
708                         int         enabled )
709{
710    handle->isPexEnabled = enabled ? 1 : 0;
711}
712
713int
714tr_sessionIsPexEnabled( const tr_handle * handle )
715{
716    return handle->isPexEnabled;
717}
718
719/***
720****
721***/
722
723void
724tr_sessionSetLazyBitfieldEnabled( tr_handle * handle,
725                                  int         enabled )
726{
727    handle->useLazyBitfield = enabled ? 1 : 0;
728}
729
730int
731tr_sessionIsLazyBitfieldEnabled( const tr_handle * handle )
732{
733    return handle->useLazyBitfield;
734}
735
736/***
737****
738***/
739
740void
741tr_sessionSetPortForwardingEnabled( tr_handle * h,
742                                    int         enable )
743{
744    tr_globalLock( h );
745    tr_sharedTraversalEnable( h->shared, enable );
746    tr_globalUnlock( h );
747}
748
749int
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
770int
771tr_blocklistIsEnabled( const tr_session * session )
772{
773    return session->isBlocklistEnabled;
774}
775
776void
777tr_blocklistSetEnabled( tr_session * session,
778                        int          isEnabled )
779{
780    tr_list * l;
781
782    session->isBlocklistEnabled = isEnabled ? 1 : 0;
783    for( l = session->blocklists; l; l = l->next )
784        _tr_blocklistSetEnabled( l->data, isEnabled );
785}
786
787int
788tr_blocklistExists( const tr_session * session )
789{
790    return session->blocklists != NULL;
791}
792
793int
794tr_blocklistSetContent( tr_session * session,
795                        const char * contentFilename )
796{
797    tr_list *      l;
798    tr_blocklist * b;
799    const char *   defaultName = "level1.bin";
800
801    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
802        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
803                               defaultName ) )
804            b = l->data;
805
806    if( !b )
807    {
808        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
809        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
810        tr_list_append( &session->blocklists, b );
811        tr_free( path );
812    }
813
814    return _tr_blocklistSetContent( b, contentFilename );
815}
816
817int
818tr_sessionIsAddressBlocked( const tr_session *     session,
819                            const struct in_addr * addr )
820{
821    tr_list * l;
822
823    for( l = session->blocklists; l; l = l->next )
824        if( _tr_blocklistHasAddress( l->data, addr ) )
825            return TRUE;
826    return FALSE;
827}
828
829/***
830****
831***/
832
833static int
834compareLookupEntries( const void * va,
835                      const void * vb )
836{
837    const struct tr_metainfo_lookup * a = va;
838    const struct tr_metainfo_lookup * b = vb;
839
840    return strcmp( a->hashString, b->hashString );
841}
842
843static void
844metainfoLookupResort( tr_handle * h )
845{
846    qsort( h->metainfoLookup,
847           h->metainfoLookupCount,
848           sizeof( struct tr_metainfo_lookup ),
849           compareLookupEntries );
850}
851
852static int
853compareHashStringToLookupEntry( const void * va,
854                                const void * vb )
855{
856    const char *                      a = va;
857    const struct tr_metainfo_lookup * b = vb;
858
859    return strcmp( a, b->hashString );
860}
861
862const char*
863tr_sessionFindTorrentFile( const tr_handle * h,
864                           const char *      hashStr )
865{
866    struct tr_metainfo_lookup * l = bsearch( hashStr,
867                                             h->metainfoLookup,
868                                             h->metainfoLookupCount,
869                                             sizeof( struct
870                                                     tr_metainfo_lookup ),
871                                             compareHashStringToLookupEntry );
872
873    return l ? l->filename : NULL;
874}
875
876static void
877metainfoLookupRescan( tr_handle * h )
878{
879    int          i;
880    int          n;
881    struct stat  sb;
882    const char * dirname = tr_getTorrentDir( h );
883    DIR *        odir = NULL;
884    tr_ctor *    ctor = NULL;
885    tr_list *    list = NULL;
886
887    /* walk through the directory and find the mappings */
888    ctor = tr_ctorNew( h );
889    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
890    if( !stat( dirname,
891               &sb ) && S_ISDIR( sb.st_mode )
892      && ( ( odir = opendir( dirname ) ) ) )
893    {
894        struct dirent *d;
895        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
896        {
897            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
898                                                     */
899            {
900                tr_info inf;
901                char * path = tr_buildPath( dirname, d->d_name, NULL );
902                tr_ctorSetMetainfoFromFile( ctor, path );
903                if( !tr_torrentParse( h, ctor, &inf ) )
904                {
905                    tr_list_append( &list, tr_strdup( inf.hashString ) );
906                    tr_list_append( &list, tr_strdup( path ) );
907                    tr_metainfoFree( &inf );
908                }
909                tr_free( path );
910            }
911        }
912        closedir( odir );
913    }
914    tr_ctorFree( ctor );
915
916    n = tr_list_size( list ) / 2;
917    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
918    h->metainfoLookupCount = n;
919    for( i = 0; i < n; ++i )
920    {
921        char * hashString = tr_list_pop_front( &list );
922        char * filename = tr_list_pop_front( &list );
923
924        memcpy( h->metainfoLookup[i].hashString, hashString,
925                2 * SHA_DIGEST_LENGTH + 1 );
926        tr_free( hashString );
927        h->metainfoLookup[i].filename = filename;
928    }
929
930    metainfoLookupResort( h );
931    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
932}
933
934void
935tr_sessionSetTorrentFile( tr_handle *  h,
936                          const char * hashString,
937                          const char * filename )
938{
939    struct tr_metainfo_lookup * l = bsearch( hashString,
940                                             h->metainfoLookup,
941                                             h->metainfoLookupCount,
942                                             sizeof( struct
943                                                     tr_metainfo_lookup ),
944                                             compareHashStringToLookupEntry );
945
946    if( l )
947    {
948        if( l->filename != filename )
949        {
950            tr_free( l->filename );
951            l->filename = tr_strdup( filename );
952        }
953    }
954    else
955    {
956        const int                   n = h->metainfoLookupCount++;
957        struct tr_metainfo_lookup * node;
958        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
959                                      h->metainfoLookup,
960                                      h->metainfoLookupCount );
961        node = h->metainfoLookup + n;
962        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
963        node->filename = tr_strdup( filename );
964        metainfoLookupResort( h );
965    }
966}
967
968tr_torrent*
969tr_torrentNext( tr_handle *  session,
970                tr_torrent * tor )
971{
972    return tor ? tor->next : session->torrentList;
973}
974
975/***
976****
977***/
978
979void
980tr_sessionSetRPCEnabled( tr_session * session,
981                         int          isEnabled )
982{
983    tr_rpcSetEnabled( session->rpcServer, isEnabled );
984}
985
986int
987tr_sessionIsRPCEnabled( const tr_session * session )
988{
989    return tr_rpcIsEnabled( session->rpcServer );
990}
991
992void
993tr_sessionSetRPCPort( tr_session * session,
994                      uint16_t     port )
995{
996    tr_rpcSetPort( session->rpcServer, port );
997}
998
999uint16_t
1000tr_sessionGetRPCPort( const tr_session * session )
1001{
1002    return tr_rpcGetPort( session->rpcServer );
1003}
1004
1005void
1006tr_sessionSetRPCCallback( tr_session * session,
1007                          tr_rpc_func  func,
1008                          void *       user_data )
1009{
1010    session->rpc_func = func;
1011    session->rpc_func_user_data = user_data;
1012}
1013
1014void
1015tr_sessionSetRPCWhitelist( tr_session * session,
1016                           const char * whitelist )
1017{
1018    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1019}
1020
1021char*
1022tr_sessionGetRPCWhitelist( const tr_session * session )
1023{
1024    return tr_rpcGetWhitelist( session->rpcServer );
1025}
1026
1027void
1028tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1029                                  int          isEnabled )
1030{
1031    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1032}
1033
1034int
1035tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1036{
1037    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1038}
1039
1040
1041void
1042tr_sessionSetRPCPassword( tr_session * session,
1043                          const char * password )
1044{
1045    tr_rpcSetPassword( session->rpcServer, password );
1046}
1047
1048char*
1049tr_sessionGetRPCPassword( const tr_session * session )
1050{
1051    return tr_rpcGetPassword( session->rpcServer );
1052}
1053
1054void
1055tr_sessionSetRPCUsername( tr_session * session,
1056                          const char * username )
1057{
1058    tr_rpcSetUsername( session->rpcServer, username );
1059}
1060
1061char*
1062tr_sessionGetRPCUsername( const tr_session * session )
1063{
1064    return tr_rpcGetUsername( session->rpcServer );
1065}
1066
1067void
1068tr_sessionSetRPCPasswordEnabled( tr_session * session,
1069                                 int          isEnabled )
1070{
1071    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1072}
1073
1074int
1075tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1076{
1077    return tr_rpcIsPasswordEnabled( session->rpcServer );
1078}
1079
1080/***
1081****
1082***/
1083
1084int
1085tr_sessionIsProxyEnabled( const tr_session * session )
1086{
1087    return session->isProxyEnabled;
1088}
1089
1090void
1091tr_sessionSetProxyEnabled( tr_session * session,
1092                           int          isEnabled )
1093{
1094    session->isProxyEnabled = isEnabled ? 1 : 0;
1095}
1096
1097tr_proxy_type
1098tr_sessionGetProxyType( const tr_session * session )
1099{
1100    return session->proxyType;
1101}
1102
1103void
1104tr_sessionSetProxyType( tr_session *  session,
1105                        tr_proxy_type type )
1106{
1107    session->proxyType = type;
1108}
1109
1110const char*
1111tr_sessionGetProxy( const tr_session * session )
1112{
1113    return session->proxy;
1114}
1115
1116int
1117tr_sessionGetProxyPort( const tr_session * session )
1118{
1119    return session->proxyPort;
1120}
1121
1122void
1123tr_sessionSetProxy( tr_session * session,
1124                    const char * proxy )
1125{
1126    if( proxy != session->proxy )
1127    {
1128        tr_free( session->proxy );
1129        session->proxy = tr_strdup( proxy );
1130    }
1131}
1132
1133void
1134tr_sessionSetProxyPort( tr_session * session,
1135                        int          port )
1136{
1137    session->proxyPort = port;
1138}
1139
1140int
1141tr_sessionIsProxyAuthEnabled( const tr_session * session )
1142{
1143    return session->isProxyAuthEnabled;
1144}
1145
1146void
1147tr_sessionSetProxyAuthEnabled( tr_session * session,
1148                               int          isEnabled )
1149{
1150    session->isProxyAuthEnabled = isEnabled ? 1 : 0;
1151}
1152
1153const char*
1154tr_sessionGetProxyUsername( const tr_session * session )
1155{
1156    return session->proxyUsername;
1157}
1158
1159void
1160tr_sessionSetProxyUsername( tr_session * session,
1161                            const char * username )
1162{
1163    if( username != session->proxyUsername )
1164    {
1165        tr_free( session->proxyUsername );
1166        session->proxyUsername = tr_strdup( username );
1167    }
1168}
1169
1170const char*
1171tr_sessionGetProxyPassword( const tr_session * session )
1172{
1173    return session->proxyPassword;
1174}
1175
1176void
1177tr_sessionSetProxyPassword( tr_session * session,
1178                            const char * password )
1179{
1180    if( password != session->proxyPassword )
1181    {
1182        tr_free( session->proxyPassword );
1183        session->proxyPassword = tr_strdup( password );
1184    }
1185}
1186
Note: See TracBrowser for help on using the repository browser.