source: trunk/libtransmission/session.c @ 7133

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

(libT) define peer connections' sockets' so_sndbuf size in the tr_session struct.

  • Property svn:keywords set to Date Rev Author Id
File size: 30.9 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 7133 2008-11-21 16:32:55Z 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 "blocklist.h"
25#include "fdlimit.h"
26#include "list.h"
27#include "metainfo.h" /* tr_metainfoFree */
28#include "net.h"
29#include "peer-mgr.h"
30#include "platform.h" /* tr_lock */
31#include "port-forwarding.h"
32#include "ratecontrol.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->pieceSpeed[TR_PEER_TO_CLIENT] = tr_rcInit( );
258    h->pieceSpeed[TR_CLIENT_TO_PEER] = tr_rcInit( );
259    h->rawSpeed[TR_PEER_TO_CLIENT] = tr_rcInit( );
260    h->rawSpeed[TR_CLIENT_TO_PEER] = tr_rcInit( );
261    h->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */
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    h->uploadLimit = uploadLimit;
281    h->useUploadLimit = useUploadLimit;
282    h->downloadLimit = downloadLimit;
283    h->useDownloadLimit = useDownloadLimit;
284
285    tr_fdInit( globalPeerLimit );
286    h->shared = tr_sharedInit( h, isPortForwardingEnabled, publicPort );
287    h->isPortSet = publicPort >= 0;
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_rcRate( session->pieceSpeed[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_rcRate( session->rawSpeed[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_rcClose( session->pieceSpeed[TR_PEER_TO_CLIENT] );
633    tr_rcClose( session->pieceSpeed[TR_CLIENT_TO_PEER] );
634    tr_rcClose( session->rawSpeed[TR_PEER_TO_CLIENT] );
635    tr_rcClose( session->rawSpeed[TR_CLIENT_TO_PEER] );
636    tr_lockFree( session->lock );
637    for( i = 0; i < session->metainfoLookupCount; ++i )
638        tr_free( session->metainfoLookup[i].filename );
639    tr_free( session->metainfoLookup );
640    tr_free( session->tag );
641    tr_free( session->configDir );
642    tr_free( session->resumeDir );
643    tr_free( session->torrentDir );
644    tr_free( session->downloadDir );
645    tr_free( session->proxy );
646    tr_free( session->proxyUsername );
647    tr_free( session->proxyPassword );
648    tr_free( session );
649}
650
651tr_torrent **
652tr_sessionLoadTorrents( tr_handle * h,
653                        tr_ctor *   ctor,
654                        int *       setmeCount )
655{
656    int           i, n = 0;
657    struct stat   sb;
658    DIR *         odir = NULL;
659    const char *  dirname = tr_getTorrentDir( h );
660    tr_torrent ** torrents;
661    tr_list *     l = NULL, *list = NULL;
662
663    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
664
665    if( !stat( dirname, &sb )
666      && S_ISDIR( sb.st_mode )
667      && ( ( odir = opendir ( dirname ) ) ) )
668    {
669        struct dirent *d;
670        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
671        {
672            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
673                                                     */
674            {
675                tr_torrent * tor;
676                char * path = tr_buildPath( dirname, d->d_name, NULL );
677                tr_ctorSetMetainfoFromFile( ctor, path );
678                if(( tor = tr_torrentNew( h, ctor, NULL )))
679                {
680                    tr_list_append( &list, tor );
681                    ++n;
682                }
683                tr_free( path );
684            }
685        }
686        closedir( odir );
687    }
688
689    torrents = tr_new( tr_torrent *, n );
690    for( i = 0, l = list; l != NULL; l = l->next )
691        torrents[i++] = (tr_torrent*) l->data;
692    assert( i == n );
693
694    tr_list_free( &list, NULL );
695
696    if( n )
697        tr_inf( _( "Loaded %d torrents" ), n );
698
699    if( setmeCount )
700        *setmeCount = n;
701    return torrents;
702}
703
704/***
705****
706***/
707
708void
709tr_sessionSetPexEnabled( tr_handle * handle,
710                         int         enabled )
711{
712    handle->isPexEnabled = enabled ? 1 : 0;
713}
714
715int
716tr_sessionIsPexEnabled( const tr_handle * handle )
717{
718    return handle->isPexEnabled;
719}
720
721/***
722****
723***/
724
725void
726tr_sessionSetLazyBitfieldEnabled( tr_handle * handle,
727                                  int         enabled )
728{
729    handle->useLazyBitfield = enabled ? 1 : 0;
730}
731
732int
733tr_sessionIsLazyBitfieldEnabled( const tr_handle * handle )
734{
735    return handle->useLazyBitfield;
736}
737
738/***
739****
740***/
741
742void
743tr_sessionSetPortForwardingEnabled( tr_handle * h,
744                                    int         enable )
745{
746    tr_globalLock( h );
747    tr_sharedTraversalEnable( h->shared, enable );
748    tr_globalUnlock( h );
749}
750
751int
752tr_sessionIsPortForwardingEnabled( const tr_handle * h )
753{
754    return tr_sharedTraversalIsEnabled( h->shared );
755}
756
757/***
758****
759***/
760
761int
762tr_blocklistGetRuleCount( const tr_session * session )
763{
764    int       n = 0;
765    tr_list * l;
766
767    for( l = session->blocklists; l; l = l->next )
768        n += _tr_blocklistGetRuleCount( l->data );
769    return n;
770}
771
772int
773tr_blocklistIsEnabled( const tr_session * session )
774{
775    return session->isBlocklistEnabled;
776}
777
778void
779tr_blocklistSetEnabled( tr_session * session,
780                        int          isEnabled )
781{
782    tr_list * l;
783
784    session->isBlocklistEnabled = isEnabled ? 1 : 0;
785    for( l = session->blocklists; l; l = l->next )
786        _tr_blocklistSetEnabled( l->data, isEnabled );
787}
788
789int
790tr_blocklistExists( const tr_session * session )
791{
792    return session->blocklists != NULL;
793}
794
795int
796tr_blocklistSetContent( tr_session * session,
797                        const char * contentFilename )
798{
799    tr_list *      l;
800    tr_blocklist * b;
801    const char *   defaultName = "level1.bin";
802
803    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
804        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
805                               defaultName ) )
806            b = l->data;
807
808    if( !b )
809    {
810        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
811        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
812        tr_list_append( &session->blocklists, b );
813        tr_free( path );
814    }
815
816    return _tr_blocklistSetContent( b, contentFilename );
817}
818
819int
820tr_sessionIsAddressBlocked( const tr_session *     session,
821                            const struct in_addr * addr )
822{
823    tr_list * l;
824
825    for( l = session->blocklists; l; l = l->next )
826        if( _tr_blocklistHasAddress( l->data, addr ) )
827            return TRUE;
828    return FALSE;
829}
830
831/***
832****
833***/
834
835static int
836compareLookupEntries( const void * va,
837                      const void * vb )
838{
839    const struct tr_metainfo_lookup * a = va;
840    const struct tr_metainfo_lookup * b = vb;
841
842    return strcmp( a->hashString, b->hashString );
843}
844
845static void
846metainfoLookupResort( tr_handle * h )
847{
848    qsort( h->metainfoLookup,
849           h->metainfoLookupCount,
850           sizeof( struct tr_metainfo_lookup ),
851           compareLookupEntries );
852}
853
854static int
855compareHashStringToLookupEntry( const void * va,
856                                const void * vb )
857{
858    const char *                      a = va;
859    const struct tr_metainfo_lookup * b = vb;
860
861    return strcmp( a, b->hashString );
862}
863
864const char*
865tr_sessionFindTorrentFile( const tr_handle * h,
866                           const char *      hashStr )
867{
868    struct tr_metainfo_lookup * l = bsearch( hashStr,
869                                             h->metainfoLookup,
870                                             h->metainfoLookupCount,
871                                             sizeof( struct
872                                                     tr_metainfo_lookup ),
873                                             compareHashStringToLookupEntry );
874
875    return l ? l->filename : NULL;
876}
877
878static void
879metainfoLookupRescan( tr_handle * h )
880{
881    int          i;
882    int          n;
883    struct stat  sb;
884    const char * dirname = tr_getTorrentDir( h );
885    DIR *        odir = NULL;
886    tr_ctor *    ctor = NULL;
887    tr_list *    list = NULL;
888
889    /* walk through the directory and find the mappings */
890    ctor = tr_ctorNew( h );
891    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
892    if( !stat( dirname,
893               &sb ) && S_ISDIR( sb.st_mode )
894      && ( ( odir = opendir( dirname ) ) ) )
895    {
896        struct dirent *d;
897        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
898        {
899            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
900                                                     */
901            {
902                tr_info inf;
903                char * path = tr_buildPath( dirname, d->d_name, NULL );
904                tr_ctorSetMetainfoFromFile( ctor, path );
905                if( !tr_torrentParse( h, ctor, &inf ) )
906                {
907                    tr_list_append( &list, tr_strdup( inf.hashString ) );
908                    tr_list_append( &list, tr_strdup( path ) );
909                    tr_metainfoFree( &inf );
910                }
911                tr_free( path );
912            }
913        }
914        closedir( odir );
915    }
916    tr_ctorFree( ctor );
917
918    n = tr_list_size( list ) / 2;
919    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
920    h->metainfoLookupCount = n;
921    for( i = 0; i < n; ++i )
922    {
923        char * hashString = tr_list_pop_front( &list );
924        char * filename = tr_list_pop_front( &list );
925
926        memcpy( h->metainfoLookup[i].hashString, hashString,
927                2 * SHA_DIGEST_LENGTH + 1 );
928        tr_free( hashString );
929        h->metainfoLookup[i].filename = filename;
930    }
931
932    metainfoLookupResort( h );
933    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
934}
935
936void
937tr_sessionSetTorrentFile( tr_handle *  h,
938                          const char * hashString,
939                          const char * filename )
940{
941    struct tr_metainfo_lookup * l = bsearch( hashString,
942                                             h->metainfoLookup,
943                                             h->metainfoLookupCount,
944                                             sizeof( struct
945                                                     tr_metainfo_lookup ),
946                                             compareHashStringToLookupEntry );
947
948    if( l )
949    {
950        if( l->filename != filename )
951        {
952            tr_free( l->filename );
953            l->filename = tr_strdup( filename );
954        }
955    }
956    else
957    {
958        const int                   n = h->metainfoLookupCount++;
959        struct tr_metainfo_lookup * node;
960        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
961                                      h->metainfoLookup,
962                                      h->metainfoLookupCount );
963        node = h->metainfoLookup + n;
964        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
965        node->filename = tr_strdup( filename );
966        metainfoLookupResort( h );
967    }
968}
969
970tr_torrent*
971tr_torrentNext( tr_handle *  session,
972                tr_torrent * tor )
973{
974    return tor ? tor->next : session->torrentList;
975}
976
977/***
978****
979***/
980
981void
982tr_sessionSetRPCEnabled( tr_session * session,
983                         int          isEnabled )
984{
985    tr_rpcSetEnabled( session->rpcServer, isEnabled );
986}
987
988int
989tr_sessionIsRPCEnabled( const tr_session * session )
990{
991    return tr_rpcIsEnabled( session->rpcServer );
992}
993
994void
995tr_sessionSetRPCPort( tr_session * session,
996                      uint16_t     port )
997{
998    tr_rpcSetPort( session->rpcServer, port );
999}
1000
1001uint16_t
1002tr_sessionGetRPCPort( const tr_session * session )
1003{
1004    return tr_rpcGetPort( session->rpcServer );
1005}
1006
1007void
1008tr_sessionSetRPCCallback( tr_session * session,
1009                          tr_rpc_func  func,
1010                          void *       user_data )
1011{
1012    session->rpc_func = func;
1013    session->rpc_func_user_data = user_data;
1014}
1015
1016void
1017tr_sessionSetRPCWhitelist( tr_session * session,
1018                           const char * whitelist )
1019{
1020    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1021}
1022
1023char*
1024tr_sessionGetRPCWhitelist( const tr_session * session )
1025{
1026    return tr_rpcGetWhitelist( session->rpcServer );
1027}
1028
1029void
1030tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1031                                  int          isEnabled )
1032{
1033    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1034}
1035
1036int
1037tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1038{
1039    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1040}
1041
1042
1043void
1044tr_sessionSetRPCPassword( tr_session * session,
1045                          const char * password )
1046{
1047    tr_rpcSetPassword( session->rpcServer, password );
1048}
1049
1050char*
1051tr_sessionGetRPCPassword( const tr_session * session )
1052{
1053    return tr_rpcGetPassword( session->rpcServer );
1054}
1055
1056void
1057tr_sessionSetRPCUsername( tr_session * session,
1058                          const char * username )
1059{
1060    tr_rpcSetUsername( session->rpcServer, username );
1061}
1062
1063char*
1064tr_sessionGetRPCUsername( const tr_session * session )
1065{
1066    return tr_rpcGetUsername( session->rpcServer );
1067}
1068
1069void
1070tr_sessionSetRPCPasswordEnabled( tr_session * session,
1071                                 int          isEnabled )
1072{
1073    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1074}
1075
1076int
1077tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1078{
1079    return tr_rpcIsPasswordEnabled( session->rpcServer );
1080}
1081
1082/***
1083****
1084***/
1085
1086int
1087tr_sessionIsProxyEnabled( const tr_session * session )
1088{
1089    return session->isProxyEnabled;
1090}
1091
1092void
1093tr_sessionSetProxyEnabled( tr_session * session,
1094                           int          isEnabled )
1095{
1096    session->isProxyEnabled = isEnabled ? 1 : 0;
1097}
1098
1099tr_proxy_type
1100tr_sessionGetProxyType( const tr_session * session )
1101{
1102    return session->proxyType;
1103}
1104
1105void
1106tr_sessionSetProxyType( tr_session *  session,
1107                        tr_proxy_type type )
1108{
1109    session->proxyType = type;
1110}
1111
1112const char*
1113tr_sessionGetProxy( const tr_session * session )
1114{
1115    return session->proxy;
1116}
1117
1118int
1119tr_sessionGetProxyPort( const tr_session * session )
1120{
1121    return session->proxyPort;
1122}
1123
1124void
1125tr_sessionSetProxy( tr_session * session,
1126                    const char * proxy )
1127{
1128    if( proxy != session->proxy )
1129    {
1130        tr_free( session->proxy );
1131        session->proxy = tr_strdup( proxy );
1132    }
1133}
1134
1135void
1136tr_sessionSetProxyPort( tr_session * session,
1137                        int          port )
1138{
1139    session->proxyPort = port;
1140}
1141
1142int
1143tr_sessionIsProxyAuthEnabled( const tr_session * session )
1144{
1145    return session->isProxyAuthEnabled;
1146}
1147
1148void
1149tr_sessionSetProxyAuthEnabled( tr_session * session,
1150                               int          isEnabled )
1151{
1152    session->isProxyAuthEnabled = isEnabled ? 1 : 0;
1153}
1154
1155const char*
1156tr_sessionGetProxyUsername( const tr_session * session )
1157{
1158    return session->proxyUsername;
1159}
1160
1161void
1162tr_sessionSetProxyUsername( tr_session * session,
1163                            const char * username )
1164{
1165    if( username != session->proxyUsername )
1166    {
1167        tr_free( session->proxyUsername );
1168        session->proxyUsername = tr_strdup( username );
1169    }
1170}
1171
1172const char*
1173tr_sessionGetProxyPassword( const tr_session * session )
1174{
1175    return session->proxyPassword;
1176}
1177
1178void
1179tr_sessionSetProxyPassword( tr_session * session,
1180                            const char * password )
1181{
1182    if( password != session->proxyPassword )
1183    {
1184        tr_free( session->proxyPassword );
1185        session->proxyPassword = tr_strdup( password );
1186    }
1187}
1188
Note: See TracBrowser for help on using the repository browser.