source: trunk/libtransmission/session.c @ 7154

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

(libT) yet another stab at getting bandwidth management under control. this version may suck less than previous attempts. It also breaks the mac build until someone adds iobuf.[ch] to xcode...

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