source: trunk/libtransmission/session.c @ 6801

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

a little more cleanup of the rpc server stuff.

  • Property svn:keywords set to Date Rev Author Id
File size: 30.2 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 6801 2008-09-26 04:41:13Z 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[MAX_PATH_LENGTH];
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    tr_buildPath( dirname, sizeof( dirname ), session->configDir,
133                  "blocklists",
134                  NULL );
135    if( !stat( dirname,
136               &sb ) && S_ISDIR( sb.st_mode )
137      && ( ( odir = opendir( dirname ) ) ) )
138    {
139        struct dirent *d;
140        for( d = readdir( odir ); d; d = readdir( odir ) )
141        {
142            char filename[MAX_PATH_LENGTH];
143
144            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
145                                                      */
146                continue;
147
148            tr_buildPath( filename, sizeof( filename ), dirname, d->d_name,
149                          NULL );
150
151            if( tr_stringEndsWith( filename, ".bin" ) )
152            {
153                /* if we don't already have this blocklist, add it */
154                if( !tr_list_find( list, filename,
155                                   (TrListCompareFunc)strcmp ) )
156                {
157                    tr_list_append( &list,
158                                   _tr_blocklistNew( filename, isEnabled ) );
159                    ++binCount;
160                }
161            }
162            else
163            {
164                /* strip out the file suffix, if there is one, and add ".bin"
165                  instead */
166                tr_blocklist * b;
167                const char *   dot = strrchr( d->d_name, '.' );
168                const int      len = dot ? dot - d->d_name : (int)strlen(
169                    d->d_name );
170                char           tmp[MAX_PATH_LENGTH];
171                tr_snprintf( tmp, sizeof( tmp ),
172                             "%s%c%*.*s.bin", dirname, TR_PATH_DELIMITER,
173                             len, len,
174                             d->d_name );
175                b = _tr_blocklistNew( tmp, isEnabled );
176                _tr_blocklistSetContent( b, filename );
177                tr_list_append( &list, b );
178                ++newCount;
179            }
180        }
181
182        closedir( odir );
183    }
184
185    session->blocklists = list;
186
187    if( binCount )
188        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
189    if( newCount )
190        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, 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                    const char *       rpcACL,
220                    int                rpcAuthIsEnabled,
221                    const char *       rpcUsername,
222                    const char *       rpcPassword,
223                    int                proxyIsEnabled,
224                    const char *       proxy,
225                    int                proxyPort,
226                    tr_proxy_type      proxyType,
227                    int                proxyAuthIsEnabled,
228                    const char *       proxyUsername,
229                    const char *       proxyPassword )
230{
231    tr_handle * h;
232    char        filename[MAX_PATH_LENGTH];
233
234#ifndef WIN32
235    /* Don't exit when writing on a broken socket */
236    signal( SIGPIPE, SIG_IGN );
237#endif
238
239    tr_msgInit( );
240    tr_setMessageLevel( messageLevel );
241    tr_setMessageQueuing( isMessageQueueingEnabled );
242
243    h = tr_new0( tr_handle, 1 );
244    h->lock = tr_lockNew( );
245    h->isPexEnabled = isPexEnabled ? 1 : 0;
246    h->encryptionMode = encryptionMode;
247    h->peerSocketTOS = peerSocketTOS;
248    h->downloadDir = tr_strdup( downloadDir );
249    h->isProxyEnabled = proxyIsEnabled ? 1 : 0;
250    h->proxy = tr_strdup( proxy );
251    h->proxyPort = proxyPort;
252    h->proxyType = proxyType;
253    h->isProxyAuthEnabled = proxyAuthIsEnabled != 0;
254    h->proxyUsername = tr_strdup( proxyUsername );
255    h->proxyPassword = tr_strdup( proxyPassword );
256
257    if( configDir == NULL )
258        configDir = tr_getDefaultConfigDir( );
259    tr_setConfigDir( h, configDir );
260
261    tr_netInit( ); /* must go before tr_eventInit */
262
263    tr_eventInit( h );
264    while( !h->events )
265        tr_wait( 50 );
266
267    h->tag = tr_strdup( tag );
268    h->peerMgr = tr_peerMgrNew( h );
269
270    h->useLazyBitfield = useLazyBitfield != 0;
271
272    /* Initialize rate and file descripts controls */
273
274    h->uploadLimit = uploadLimit;
275    h->useUploadLimit = useUploadLimit;
276    h->downloadLimit = downloadLimit;
277    h->useDownloadLimit = useDownloadLimit;
278
279    tr_fdInit( globalPeerLimit );
280    h->shared = tr_sharedInit( h, isPortForwardingEnabled, publicPort );
281    h->isPortSet = publicPort >= 0;
282
283    /* first %s is the application name
284       second %s is the version number */
285    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
286
287    /* initialize the blocklist */
288    tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists",
289                  NULL );
290    tr_mkdirp( filename, 0777 );
291    h->isBlocklistEnabled = isBlocklistEnabled;
292    loadBlocklists( h );
293
294    tr_statsInit( h );
295
296    h->web = tr_webInit( h );
297    h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort, rpcACL,
298                               rpcAuthIsEnabled, rpcUsername, rpcPassword );
299
300    metainfoLookupRescan( h );
301
302    return h;
303}
304
305tr_handle *
306tr_sessionInit( const char * configDir,
307                const char * downloadDir,
308                const char * tag )
309{
310    return tr_sessionInitFull( configDir,
311                               downloadDir,
312                               tag,
313                               TR_DEFAULT_PEX_ENABLED,
314                               TR_DEFAULT_PORT_FORWARDING_ENABLED,
315                               -1, /* public port */
316                               TR_ENCRYPTION_PREFERRED, /* encryption mode */
317                               TR_DEFAULT_LAZY_BITFIELD_ENABLED,
318                               FALSE, /* use upload speed limit? */
319                               -1, /* upload speed limit */
320                               FALSE, /* use download speed limit? */
321                               -1, /* download speed limit */
322                               TR_DEFAULT_GLOBAL_PEER_LIMIT,
323                               TR_MSG_INF, /* message level */
324                               FALSE, /* is message queueing enabled? */
325                               FALSE, /* is the blocklist enabled? */
326                               TR_DEFAULT_PEER_SOCKET_TOS,
327                               TR_DEFAULT_RPC_ENABLED,
328                               TR_DEFAULT_RPC_PORT,
329                               TR_DEFAULT_RPC_ACL,
330                               FALSE,
331                               "fnord",
332                               "potzrebie",
333                               TR_DEFAULT_PROXY_ENABLED,
334                               TR_DEFAULT_PROXY,
335                               TR_DEFAULT_PROXY_PORT,
336                               TR_DEFAULT_PROXY_TYPE,
337                               TR_DEFAULT_PROXY_AUTH_ENABLED,
338                               TR_DEFAULT_PROXY_USERNAME,
339                               TR_DEFAULT_PROXY_PASSWORD );
340}
341
342/***
343****
344***/
345
346void
347tr_sessionSetDownloadDir( tr_handle *  handle,
348                          const char * dir )
349{
350    if( handle->downloadDir != dir )
351    {
352        tr_free( handle->downloadDir );
353        handle->downloadDir = tr_strdup( dir );
354    }
355}
356
357const char *
358tr_sessionGetDownloadDir( const tr_handle * handle )
359{
360    return handle->downloadDir;
361}
362
363/***
364****
365***/
366
367void
368tr_globalLock( struct tr_handle * handle )
369{
370    tr_lockLock( handle->lock );
371}
372
373void
374tr_globalUnlock( struct tr_handle * handle )
375{
376    tr_lockUnlock( handle->lock );
377}
378
379int
380tr_globalIsLocked( const struct tr_handle * handle )
381{
382    return handle && tr_lockHave( handle->lock );
383}
384
385/***********************************************************************
386 * tr_setBindPort
387 ***********************************************************************
388 *
389 **********************************************************************/
390
391struct bind_port_data
392{
393    tr_handle *  handle;
394    int          port;
395};
396
397static void
398tr_setBindPortImpl( void * vdata )
399{
400    struct bind_port_data * data = vdata;
401    tr_handle *             handle = data->handle;
402    const int               port = data->port;
403
404    handle->isPortSet = 1;
405    tr_sharedSetPort( handle->shared, port );
406
407    tr_free( data );
408}
409
410void
411tr_sessionSetPeerPort( tr_handle * handle,
412                       int         port )
413{
414    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
415
416    data->handle = handle;
417    data->port = port;
418    tr_runInEventThread( handle, tr_setBindPortImpl, data );
419}
420
421int
422tr_sessionGetPeerPort( const tr_handle * h )
423{
424    assert( h );
425    return tr_sharedGetPeerPort( h->shared );
426}
427
428tr_port_forwarding
429tr_sessionGetPortForwarding( const tr_handle * h )
430{
431    return tr_sharedTraversalStatus( h->shared );
432}
433
434/***
435****
436***/
437
438void
439tr_sessionSetSpeedLimitEnabled( tr_handle *  h,
440                                tr_direction direction,
441                                int          use_flag )
442{
443    assert( h );
444    assert( direction == TR_UP || direction == TR_DOWN );
445
446    if( direction == TR_UP )
447        h->useUploadLimit = use_flag ? 1 : 0;
448    else
449        h->useDownloadLimit = use_flag ? 1 : 0;
450}
451
452int
453tr_sessionIsSpeedLimitEnabled( const tr_handle * h,
454                               tr_direction      direction )
455{
456    return direction == TR_UP ? h->useUploadLimit : h->useDownloadLimit;
457}
458
459void
460tr_sessionSetSpeedLimit( tr_handle *  h,
461                         tr_direction direction,
462                         int          KiB_sec )
463{
464    if( direction == TR_DOWN )
465        h->downloadLimit = KiB_sec;
466    else
467        h->uploadLimit = KiB_sec;
468}
469
470int
471tr_sessionGetSpeedLimit( const tr_handle * h,
472                         tr_direction      direction )
473{
474    return direction == TR_UP ? h->uploadLimit : h->downloadLimit;
475}
476
477/***
478****
479***/
480
481void
482tr_sessionSetPeerLimit( tr_handle * handle UNUSED,
483                        uint16_t           maxGlobalPeers )
484{
485    tr_fdSetPeerLimit( maxGlobalPeers );
486}
487
488uint16_t
489tr_sessionGetPeerLimit( const tr_handle * handle UNUSED )
490{
491    return tr_fdGetPeerLimit( );
492}
493
494/***
495****
496***/
497
498void
499tr_sessionGetSpeed( const tr_handle * session,
500                    float *           toClient,
501                    float *           toPeer )
502{
503    if( session && toClient )
504        *toClient = tr_peerMgrGetRate( session->peerMgr, TR_DOWN );
505
506    if( session && toPeer )
507        *toPeer = tr_peerMgrGetRate( session->peerMgr, TR_UP );
508}
509
510int
511tr_sessionCountTorrents( const tr_handle * h )
512{
513    return h->torrentCount;
514}
515
516static int
517compareTorrentByCur( const void * va,
518                     const void * vb )
519{
520    const tr_torrent * a = *(const tr_torrent**)va;
521    const tr_torrent * b = *(const tr_torrent**)vb;
522    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
523    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
524
525    if( aCur != bCur )
526        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
527
528    return 0;
529}
530
531static void
532tr_closeAllConnections( void * vsession )
533{
534    tr_handle *   session = vsession;
535    tr_torrent *  tor;
536    int           i, n;
537    tr_torrent ** torrents;
538
539    tr_statsClose( session );
540    tr_sharedShuttingDown( session->shared );
541    tr_rpcClose( &session->rpcServer );
542
543    /* close the torrents.  get the most active ones first so that
544     * if we can't get them all closed in a reasonable amount of time,
545     * at least we get the most important ones first. */
546    tor = NULL;
547    n = session->torrentCount;
548    torrents = tr_new( tr_torrent *, session->torrentCount );
549    for( i = 0; i < n; ++i )
550        torrents[i] = tor = tr_torrentNext( session, tor );
551    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
552    for( i = 0; i < n; ++i )
553        tr_torrentFree( torrents[i] );
554    tr_free( torrents );
555
556    tr_peerMgrFree( session->peerMgr );
557
558    tr_trackerSessionClose( session );
559    tr_list_free( &session->blocklists,
560                  (TrListForeachFunc)_tr_blocklistFree );
561    tr_webClose( &session->web );
562
563    session->isClosed = TRUE;
564}
565
566static int
567deadlineReached( const uint64_t deadline )
568{
569    return tr_date( ) >= deadline;
570}
571
572#define SHUTDOWN_MAX_SECONDS 30
573
574#define dbgmsg( fmt... ) tr_deepLog( __FILE__, __LINE__, NULL, ## fmt )
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_lockFree( session->lock );
618    for( i = 0; i < session->metainfoLookupCount; ++i )
619        tr_free( session->metainfoLookup[i].filename );
620    tr_free( session->metainfoLookup );
621    tr_free( session->tag );
622    tr_free( session->configDir );
623    tr_free( session->resumeDir );
624    tr_free( session->torrentDir );
625    tr_free( session->downloadDir );
626    tr_free( session->proxy );
627    tr_free( session->proxyUsername );
628    tr_free( session->proxyPassword );
629    tr_free( session );
630}
631
632tr_torrent **
633tr_sessionLoadTorrents( tr_handle * h,
634                        tr_ctor *   ctor,
635                        int *       setmeCount )
636{
637    int           i, n = 0;
638    struct stat   sb;
639    DIR *         odir = NULL;
640    const char *  dirname = tr_getTorrentDir( h );
641    tr_torrent ** torrents;
642    tr_list *     l = NULL, *list = NULL;
643
644    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
645
646    if( !stat( dirname, &sb )
647      && S_ISDIR( sb.st_mode )
648      && ( ( odir = opendir ( dirname ) ) ) )
649    {
650        struct dirent *d;
651        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
652        {
653            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
654                                                     */
655            {
656                tr_torrent * tor;
657                char         filename[MAX_PATH_LENGTH];
658                tr_buildPath( filename, sizeof( filename ), dirname,
659                              d->d_name,
660                              NULL );
661
662                tr_ctorSetMetainfoFromFile( ctor, filename );
663                tor = tr_torrentNew( h, ctor, NULL );
664                if( tor )
665                {
666                    tr_list_append( &list, tor );
667                    ++n;
668                }
669            }
670        }
671        closedir( odir );
672    }
673
674    torrents = tr_new( tr_torrent *, n );
675    for( i = 0, l = list; l != NULL; l = l->next )
676        torrents[i++] = (tr_torrent*) l->data;
677    assert( i == n );
678
679    tr_list_free( &list, NULL );
680
681    if( n )
682        tr_inf( _( "Loaded %d torrents" ), n );
683
684    if( setmeCount )
685        *setmeCount = n;
686    return torrents;
687}
688
689/***
690****
691***/
692
693void
694tr_sessionSetPexEnabled( tr_handle * handle,
695                         int         enabled )
696{
697    handle->isPexEnabled = enabled ? 1 : 0;
698}
699
700int
701tr_sessionIsPexEnabled( const tr_handle * handle )
702{
703    return handle->isPexEnabled;
704}
705
706/***
707****
708***/
709
710void
711tr_sessionSetLazyBitfieldEnabled( tr_handle * handle,
712                                  int         enabled )
713{
714    handle->useLazyBitfield = enabled ? 1 : 0;
715}
716
717int
718tr_sessionIsLazyBitfieldEnabled( const tr_handle * handle )
719{
720    return handle->useLazyBitfield;
721}
722
723/***
724****
725***/
726
727void
728tr_sessionSetPortForwardingEnabled( tr_handle * h,
729                                    int         enable )
730{
731    tr_globalLock( h );
732    tr_sharedTraversalEnable( h->shared, enable );
733    tr_globalUnlock( h );
734}
735
736int
737tr_sessionIsPortForwardingEnabled( const tr_handle * h )
738{
739    return tr_sharedTraversalIsEnabled( h->shared );
740}
741
742/***
743****
744***/
745
746int
747tr_blocklistGetRuleCount( const tr_session * session )
748{
749    int       n = 0;
750    tr_list * l;
751
752    for( l = session->blocklists; l; l = l->next )
753        n += _tr_blocklistGetRuleCount( l->data );
754    return n;
755}
756
757int
758tr_blocklistIsEnabled( const tr_session * session )
759{
760    return session->isBlocklistEnabled;
761}
762
763void
764tr_blocklistSetEnabled( tr_session * session,
765                        int          isEnabled )
766{
767    tr_list * l;
768
769    session->isBlocklistEnabled = isEnabled ? 1 : 0;
770    for( l = session->blocklists; l; l = l->next )
771        _tr_blocklistSetEnabled( l->data, isEnabled );
772}
773
774int
775tr_blocklistExists( const tr_session * session )
776{
777    return session->blocklists != NULL;
778}
779
780int
781tr_blocklistSetContent( tr_session * session,
782                        const char * contentFilename )
783{
784    tr_list *      l;
785    tr_blocklist * b;
786    const char *   defaultName = "level1.bin";
787
788    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
789        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
790                               defaultName ) )
791            b = l->data;
792
793    if( !b )
794    {
795        char filename[MAX_PATH_LENGTH];
796        tr_buildPath( filename, sizeof( filename ), session->configDir,
797                      "blocklists", defaultName,
798                      NULL );
799        b = _tr_blocklistNew( filename, session->isBlocklistEnabled );
800        tr_list_append( &session->blocklists, b );
801    }
802
803    return _tr_blocklistSetContent( b, contentFilename );
804}
805
806int
807tr_sessionIsAddressBlocked( const tr_session *     session,
808                            const struct in_addr * addr )
809{
810    tr_list * l;
811
812    for( l = session->blocklists; l; l = l->next )
813        if( _tr_blocklistHasAddress( l->data, addr ) )
814            return TRUE;
815    return FALSE;
816}
817
818/***
819****
820***/
821
822static int
823compareLookupEntries( const void * va,
824                      const void * vb )
825{
826    const struct tr_metainfo_lookup * a = va;
827    const struct tr_metainfo_lookup * b = vb;
828
829    return strcmp( a->hashString, b->hashString );
830}
831
832static void
833metainfoLookupResort( tr_handle * h )
834{
835    qsort( h->metainfoLookup,
836           h->metainfoLookupCount,
837           sizeof( struct tr_metainfo_lookup ),
838           compareLookupEntries );
839}
840
841static int
842compareHashStringToLookupEntry( const void * va,
843                                const void * vb )
844{
845    const char *                      a = va;
846    const struct tr_metainfo_lookup * b = vb;
847
848    return strcmp( a, b->hashString );
849}
850
851const char*
852tr_sessionFindTorrentFile( const tr_handle * h,
853                           const char *      hashStr )
854{
855    struct tr_metainfo_lookup * l = bsearch( hashStr,
856                                             h->metainfoLookup,
857                                             h->metainfoLookupCount,
858                                             sizeof( struct
859                                                     tr_metainfo_lookup ),
860                                             compareHashStringToLookupEntry );
861
862    return l ? l->filename : NULL;
863}
864
865static void
866metainfoLookupRescan( tr_handle * h )
867{
868    int          i;
869    int          n;
870    struct stat  sb;
871    const char * dirname = tr_getTorrentDir( h );
872    DIR *        odir = NULL;
873    tr_ctor *    ctor = NULL;
874    tr_list *    list = NULL;
875
876    /* walk through the directory and find the mappings */
877    ctor = tr_ctorNew( h );
878    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
879    if( !stat( dirname,
880               &sb ) && S_ISDIR( sb.st_mode )
881      && ( ( odir = opendir( dirname ) ) ) )
882    {
883        struct dirent *d;
884        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
885        {
886            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
887                                                     */
888            {
889                tr_info inf;
890                char    filename[MAX_PATH_LENGTH];
891                tr_buildPath( filename, sizeof( filename ), dirname,
892                              d->d_name,
893                              NULL );
894                tr_ctorSetMetainfoFromFile( ctor, filename );
895                if( !tr_torrentParse( h, ctor, &inf ) )
896                {
897                    tr_list_append( &list, tr_strdup( inf.hashString ) );
898                    tr_list_append( &list, tr_strdup( filename ) );
899                    tr_metainfoFree( &inf );
900                }
901            }
902        }
903        closedir( odir );
904    }
905    tr_ctorFree( ctor );
906
907    n = tr_list_size( list ) / 2;
908    h->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
909    h->metainfoLookupCount = n;
910    for( i = 0; i < n; ++i )
911    {
912        char * hashString = tr_list_pop_front( &list );
913        char * filename = tr_list_pop_front( &list );
914
915        memcpy( h->metainfoLookup[i].hashString, hashString,
916                2 * SHA_DIGEST_LENGTH + 1 );
917        tr_free( hashString );
918        h->metainfoLookup[i].filename = filename;
919    }
920
921    metainfoLookupResort( h );
922    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
923}
924
925void
926tr_sessionSetTorrentFile( tr_handle *  h,
927                          const char * hashString,
928                          const char * filename )
929{
930    struct tr_metainfo_lookup * l = bsearch( hashString,
931                                             h->metainfoLookup,
932                                             h->metainfoLookupCount,
933                                             sizeof( struct
934                                                     tr_metainfo_lookup ),
935                                             compareHashStringToLookupEntry );
936
937    if( l )
938    {
939        if( l->filename != filename )
940        {
941            tr_free( l->filename );
942            l->filename = tr_strdup( filename );
943        }
944    }
945    else
946    {
947        const int                   n = h->metainfoLookupCount++;
948        struct tr_metainfo_lookup * node;
949        h->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
950                                      h->metainfoLookup,
951                                      h->metainfoLookupCount );
952        node = h->metainfoLookup + n;
953        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
954        node->filename = tr_strdup( filename );
955        metainfoLookupResort( h );
956    }
957}
958
959tr_torrent*
960tr_torrentNext( tr_handle *  session,
961                tr_torrent * tor )
962{
963    return tor ? tor->next : session->torrentList;
964}
965
966/***
967****
968***/
969
970void
971tr_sessionSetRPCEnabled( tr_session * session,
972                         int          isEnabled )
973{
974    tr_rpcSetEnabled( session->rpcServer, isEnabled );
975}
976
977int
978tr_sessionIsRPCEnabled( const tr_session * session )
979{
980    return tr_rpcIsEnabled( session->rpcServer );
981}
982
983void
984tr_sessionSetRPCPort( tr_session * session,
985                      uint16_t     port )
986{
987    tr_rpcSetPort( session->rpcServer, port );
988}
989
990uint16_t
991tr_sessionGetRPCPort( const tr_session * session )
992{
993    return tr_rpcGetPort( session->rpcServer );
994}
995
996void
997tr_sessionSetRPCCallback( tr_session * session,
998                          tr_rpc_func  func,
999                          void *       user_data )
1000{
1001    session->rpc_func = func;
1002    session->rpc_func_user_data = user_data;
1003}
1004
1005void
1006tr_sessionSetRPCACL( tr_session * session,
1007                     const char * acl )
1008{
1009    return tr_rpcSetACL( session->rpcServer, acl );
1010}
1011
1012char*
1013tr_sessionGetRPCACL( const tr_session * session )
1014{
1015    return tr_rpcGetACL( session->rpcServer );
1016}
1017
1018void
1019tr_sessionSetRPCPassword( tr_session * session,
1020                          const char * password )
1021{
1022    tr_rpcSetPassword( session->rpcServer, password );
1023}
1024
1025char*
1026tr_sessionGetRPCPassword( const tr_session * session )
1027{
1028    return tr_rpcGetPassword( session->rpcServer );
1029}
1030
1031void
1032tr_sessionSetRPCUsername( tr_session * session,
1033                          const char * username )
1034{
1035    tr_rpcSetUsername( session->rpcServer, username );
1036}
1037
1038char*
1039tr_sessionGetRPCUsername( const tr_session * session )
1040{
1041    return tr_rpcGetUsername( session->rpcServer );
1042}
1043
1044void
1045tr_sessionSetRPCPasswordEnabled( tr_session * session,
1046                                 int          isEnabled )
1047{
1048    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1049}
1050
1051int
1052tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1053{
1054    return tr_rpcIsPasswordEnabled( session->rpcServer );
1055}
1056
1057/***
1058****
1059***/
1060
1061int
1062tr_sessionIsProxyEnabled( const tr_session * session )
1063{
1064    return session->isProxyEnabled;
1065}
1066
1067void
1068tr_sessionSetProxyEnabled( tr_session * session,
1069                           int          isEnabled )
1070{
1071    session->isProxyEnabled = isEnabled ? 1 : 0;
1072}
1073
1074tr_proxy_type
1075tr_sessionGetProxyType( const tr_session * session )
1076{
1077    return session->proxyType;
1078}
1079
1080void
1081tr_sessionSetProxyType( tr_session *  session,
1082                        tr_proxy_type type )
1083{
1084    session->proxyType = type;
1085}
1086
1087const char*
1088tr_sessionGetProxy( const tr_session * session )
1089{
1090    return session->proxy;
1091}
1092
1093int
1094tr_sessionGetProxyPort( const tr_session * session )
1095{
1096    return session->proxyPort;
1097}
1098
1099void
1100tr_sessionSetProxy( tr_session * session,
1101                    const char * proxy )
1102{
1103    if( proxy != session->proxy )
1104    {
1105        tr_free( session->proxy );
1106        session->proxy = tr_strdup( proxy );
1107    }
1108}
1109
1110void
1111tr_sessionSetProxyPort( tr_session * session,
1112                        int          port )
1113{
1114    session->proxyPort = port;
1115}
1116
1117int
1118tr_sessionIsProxyAuthEnabled( const tr_session * session )
1119{
1120    return session->isProxyAuthEnabled;
1121}
1122
1123void
1124tr_sessionSetProxyAuthEnabled( tr_session * session,
1125                               int          isEnabled )
1126{
1127    session->isProxyAuthEnabled = isEnabled ? 1 : 0;
1128}
1129
1130const char*
1131tr_sessionGetProxyUsername( const tr_session * session )
1132{
1133    return session->proxyUsername;
1134}
1135
1136void
1137tr_sessionSetProxyUsername( tr_session * session,
1138                            const char * username )
1139{
1140    if( username != session->proxyUsername )
1141    {
1142        tr_free( session->proxyUsername );
1143        session->proxyUsername = tr_strdup( username );
1144    }
1145}
1146
1147const char*
1148tr_sessionGetProxyPassword( const tr_session * session )
1149{
1150    return session->proxyPassword;
1151}
1152
1153void
1154tr_sessionSetProxyPassword( tr_session * session,
1155                            const char * password )
1156{
1157    if( password != session->proxyPassword )
1158    {
1159        tr_free( session->proxyPassword );
1160        session->proxyPassword = tr_strdup( password );
1161    }
1162}
1163
Note: See TracBrowser for help on using the repository browser.