source: trunk/libtransmission/session.c @ 6424

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

#1126: crash on quit

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