source: trunk/libtransmission/session.c @ 6496

Last change on this file since 6496 was 6496, checked in by charles, 13 years ago

readability improvments #1, #2, #3, #4. (muks)

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