source: trunk/libtransmission/session.c @ 7055

Last change on this file since 7055 was 7055, checked in by charles, 10 years ago

update NEWS

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