source: trunk/libtransmission/session.c @ 7806

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

(trunk libT) another possible fix for the libevent corruption issue -- libevent calls were being invoked from the gui thread at startup via tr_sessionInit()'s call to tr_webInit(). This revision moves those calls into the libtransmission/libevent thread.

  • Property svn:keywords set to Date Rev Author Id
File size: 40.3 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.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 7806 2009-01-26 08:23: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 "session.h"
25#include "bandwidth.h"
26#include "bencode.h"
27#include "blocklist.h"
28#include "fdlimit.h"
29#include "list.h"
30#include "metainfo.h" /* tr_metainfoFree */
31#include "net.h"
32#include "peer-mgr.h"
33#include "platform.h" /* tr_lock */
34#include "port-forwarding.h"
35#include "rpc-server.h"
36#include "stats.h"
37#include "torrent.h"
38#include "tracker.h"
39#include "trevent.h"
40#include "utils.h"
41#include "web.h"
42#include "crypto.h"
43
44#define dbgmsg( ... ) \
45    do { \
46        if( tr_deepLoggingIsActive( ) ) \
47            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
48    } while( 0 )
49
50static tr_port
51getRandomPort( tr_session * s )
52{
53    return tr_cryptoWeakRandInt( s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow;
54}
55
56/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
57   characters, where x is the major version number, y is the
58   minor version number, z is the maintenance number, and b
59   designates beta (Azureus-style) */
60uint8_t*
61tr_peerIdNew( void )
62{
63    int          i;
64    int          val;
65    int          total = 0;
66    uint8_t *    buf = tr_new( uint8_t, 21 );
67    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
68    const int    base = 36;
69
70    memcpy( buf, PEERID_PREFIX, 8 );
71
72    for( i = 8; i < 19; ++i )
73    {
74        val = tr_cryptoRandInt( base );
75        total += val;
76        buf[i] = pool[val];
77    }
78
79    val = total % base ? base - ( total % base ) : 0;
80    buf[19] = pool[val];
81    buf[20] = '\0';
82
83    return buf;
84}
85
86const uint8_t*
87tr_getPeerId( void )
88{
89    static uint8_t * id = NULL;
90
91    if( id == NULL )
92        id = tr_peerIdNew( );
93    return id;
94}
95
96/***
97****
98***/
99
100tr_encryption_mode
101tr_sessionGetEncryption( tr_session * session )
102{
103    assert( session );
104
105    return session->encryptionMode;
106}
107
108void
109tr_sessionSetEncryption( tr_session *       session,
110                         tr_encryption_mode mode )
111{
112    assert( session );
113    assert( mode == TR_ENCRYPTION_PREFERRED
114          || mode == TR_ENCRYPTION_REQUIRED
115          || mode == TR_CLEAR_PREFERRED );
116
117    session->encryptionMode = mode;
118}
119
120/***
121****
122***/
123
124static int
125tr_stringEndsWith( const char * str,
126                   const char * end )
127{
128    const size_t slen = strlen( str );
129    const size_t elen = strlen( end );
130
131    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
132}
133
134static void
135loadBlocklists( tr_session * session )
136{
137    int         binCount = 0;
138    int         newCount = 0;
139    struct stat sb;
140    char      * dirname;
141    DIR *       odir = NULL;
142    tr_list *   list = NULL;
143    const tr_bool   isEnabled = session->isBlocklistEnabled;
144
145    /* walk through the directory and find blocklists */
146    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
147    if( !stat( dirname,
148               &sb ) && S_ISDIR( sb.st_mode )
149      && ( ( odir = opendir( dirname ) ) ) )
150    {
151        struct dirent *d;
152        for( d = readdir( odir ); d; d = readdir( odir ) )
153        {
154            char * filename;
155
156            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
157                                                      */
158                continue;
159
160            filename = tr_buildPath( dirname, d->d_name, NULL );
161
162            if( tr_stringEndsWith( filename, ".bin" ) )
163            {
164                /* if we don't already have this blocklist, add it */
165                if( !tr_list_find( list, filename,
166                                   (TrListCompareFunc)strcmp ) )
167                {
168                    tr_list_append( &list,
169                                   _tr_blocklistNew( filename, isEnabled ) );
170                    ++binCount;
171                }
172            }
173            else
174            {
175                /* strip out the file suffix, if there is one, and add ".bin"
176                  instead */
177                tr_blocklist * b;
178                const char *   dot = strrchr( d->d_name, '.' );
179                const int      len = dot ? dot - d->d_name
180                                         : (int)strlen( d->d_name );
181                char         * tmp = tr_strdup_printf(
182                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
183                                        dirname, len, len, d->d_name );
184                b = _tr_blocklistNew( tmp, isEnabled );
185                _tr_blocklistSetContent( b, filename );
186                tr_list_append( &list, b );
187                ++newCount;
188                tr_free( tmp );
189            }
190
191            tr_free( filename );
192        }
193
194        closedir( odir );
195    }
196
197    session->blocklists = list;
198
199    if( binCount )
200        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
201    if( newCount )
202        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
203
204    tr_free( dirname );
205}
206
207/***
208****
209***/
210
211#ifdef TR_EMBEDDED
212 #define TR_DEFAULT_ENCRYPTION              TR_CLEAR_PREFERRED
213#else
214 #define TR_DEFAULT_ENCRYPTION              TR_ENCRYPTION_PREFERRED
215#endif
216
217void
218tr_sessionGetDefaultSettings( tr_benc * d )
219{
220    assert( tr_bencIsDict( d ) );
221
222    tr_bencDictReserve( d, 30 );
223    tr_bencDictAddInt( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        FALSE );
224    tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR,             tr_getDefaultDownloadDir( ) );
225    tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED,                   100 );
226    tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED_ENABLED,           0 );
227    tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION,               TR_DEFAULT_ENCRYPTION );
228    tr_bencDictAddInt( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
229    tr_bencDictAddInt( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
230    tr_bencDictAddInt( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
231    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
232    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       atoi( TR_DEFAULT_PEER_LIMIT_TORRENT_STR ) );
233    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT,                atoi( TR_DEFAULT_PEER_PORT_STR ) );
234    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, FALSE );
235    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     1024 );
236    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    65535 );
237    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          atoi( TR_DEFAULT_PEER_SOCKET_TOS_STR ) );
238    tr_bencDictAddInt( d, TR_PREFS_KEY_PEX_ENABLED,              TRUE );
239    tr_bencDictAddInt( d, TR_PREFS_KEY_PORT_FORWARDING,          TRUE );
240    tr_bencDictAddInt( d, TR_PREFS_KEY_PREALLOCATION,            TR_PREALLOCATE_SPARSE );
241    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY,                    "" );
242    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       FALSE );
243    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_ENABLED,            FALSE );
244    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_PASSWORD,           "" );
245    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_PORT,               80 );
246    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_TYPE,               TR_PROXY_HTTP );
247    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_USERNAME,           "" );
248    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        FALSE );
249    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_ENABLED,              TRUE );
250    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_PASSWORD,             "" );
251    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_USERNAME,             "" );
252    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_WHITELIST,            TR_DEFAULT_RPC_WHITELIST );
253    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    TRUE );
254    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_PORT,                 atoi( TR_DEFAULT_RPC_PORT_STR ) );
255    tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED,                   100 );
256    tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_ENABLED,           0 );
257    tr_bencDictAddInt( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 );
258}
259
260void
261tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
262{
263    int i, n=0;
264    char * freeme[16];
265
266    assert( tr_bencIsDict( d ) );
267
268    tr_bencDictReserve( d, 30 );
269    tr_bencDictAddInt( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        tr_blocklistIsEnabled( s ) );
270    tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR,             s->downloadDir );
271    tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED,                   tr_sessionGetSpeedLimit( s, TR_DOWN ) );
272    tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED_ENABLED,           tr_sessionIsSpeedLimitEnabled( s, TR_DOWN ) );
273    tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION,               s->encryptionMode );
274    tr_bencDictAddInt( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
275    tr_bencDictAddInt( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
276    tr_bencDictAddInt( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          s->openFileLimit );
277    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        tr_sessionGetPeerLimit( s ) );
278    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       s->peerLimitPerTorrent );
279    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT,                tr_sessionGetPeerPort( s ) );
280    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, s->isPortRandom );
281    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     s->randomPortLow );
282    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    s->randomPortHigh );
283    tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          s->peerSocketTOS );
284    tr_bencDictAddInt( d, TR_PREFS_KEY_PEX_ENABLED,              s->isPexEnabled );
285    tr_bencDictAddInt( d, TR_PREFS_KEY_PORT_FORWARDING,          tr_sessionIsPortForwardingEnabled( s ) );
286    tr_bencDictAddInt( d, TR_PREFS_KEY_PREALLOCATION,            s->preallocationMode );
287    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY,                    s->proxy );
288    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       s->isProxyAuthEnabled );
289    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_ENABLED,            s->isProxyEnabled );
290    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_PASSWORD,           s->proxyPassword );
291    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_PORT,               s->proxyPort );
292    tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_TYPE,               s->proxyType );
293    tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_USERNAME,           s->proxyUsername );
294    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        tr_sessionIsRPCPasswordEnabled( s ) );
295    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_ENABLED,              tr_sessionIsRPCEnabled( s ) );
296    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_PASSWORD,             freeme[n++] = tr_sessionGetRPCPassword( s ) );
297    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_PORT,                 tr_sessionGetRPCPort( s ) );
298    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_USERNAME,             freeme[n++] = tr_sessionGetRPCUsername( s ) );
299    tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_WHITELIST,            freeme[n++] = tr_sessionGetRPCWhitelist( s ) );
300    tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    tr_sessionGetRPCWhitelistEnabled( s ) );
301    tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED,                   tr_sessionGetSpeedLimit( s, TR_UP ) );
302    tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_ENABLED,           tr_sessionIsSpeedLimitEnabled( s, TR_UP ) );
303    tr_bencDictAddInt( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
304
305    for( i=0; i<n; ++i )
306        tr_free( freeme[i] );
307}
308
309void
310tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName )
311{
312    char * filename;
313    tr_benc fileSettings;
314
315    assert( tr_bencIsDict( d ) );
316
317    /* get the defaults */
318    tr_sessionGetDefaultSettings( d );
319
320    /* if caller didn't specify a config dir, use the default */
321    if( !configDir || !*configDir )
322        configDir = tr_getDefaultConfigDir( appName );
323
324    /* file settings override the defaults */
325    filename = tr_buildPath( configDir, "settings.json", NULL );
326    if( !tr_bencLoadJSONFile( filename, &fileSettings ) ) {
327        tr_bencMergeDicts( d, &fileSettings );
328        tr_bencFree( &fileSettings );
329    }
330
331    /* cleanup */
332    tr_free( filename );
333}
334
335void
336tr_sessionSaveSettings( tr_session * session, const char * configDir, tr_benc * settings )
337{
338    tr_benc fileSettings;
339    char * filename;
340
341    assert( tr_bencIsDict( settings ) );
342 
343    filename = tr_buildPath( configDir, "settings.json", NULL );
344
345    tr_sessionGetSettings( session, settings );
346
347    if( tr_bencLoadJSONFile( filename, &fileSettings ) ) {
348        tr_bencSaveJSONFile( filename, settings );
349    } else {
350        tr_bencMergeDicts( &fileSettings, settings );
351        tr_bencSaveJSONFile( filename, &fileSettings );
352        tr_bencFree( &fileSettings );
353    }
354
355    tr_inf( "Saved \"%s\"", filename );
356    tr_free( filename );
357}
358
359static void metainfoLookupRescan( tr_session * );
360static void tr_sessionInitImpl( void * );
361
362tr_session *
363tr_sessionInit( const char  * tag,
364                const char  * configDir,
365                tr_bool       messageQueuingEnabled,
366                tr_benc     * clientSettings )
367{
368    int64_t i;
369    int64_t j;
370    tr_bool found;
371    const char * str;
372    tr_benc settings;
373    tr_session * session;
374    char * filename;
375
376    assert( tr_bencIsDict( clientSettings ) );
377
378    session = tr_new0( tr_session, 1 );
379    session->bandwidth = tr_bandwidthNew( session, NULL );
380    session->lock = tr_lockNew( );
381    session->tag = tr_strdup( tag );
382    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth );
383
384    tr_bencInitDict( &settings, 0 );
385    tr_sessionGetDefaultSettings( &settings );
386    tr_bencMergeDicts( &settings, clientSettings );
387
388#ifndef WIN32
389    /* Don't exit when writing on a broken socket */
390    signal( SIGPIPE, SIG_IGN );
391#endif
392
393    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ); 
394    assert( found ); 
395    session->peerLimitPerTorrent = i; 
396 
397    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i ); 
398    assert( found ); 
399    tr_setMessageLevel( i ); 
400    tr_setMessageQueuing( messageQueuingEnabled ); 
401 
402 
403    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEX_ENABLED, &i ); 
404    assert( found ); 
405    session->isPexEnabled = i != 0; 
406 
407    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i ); 
408    assert( found ); 
409    assert( tr_isEncryptionMode( i ) );
410    session->encryptionMode = i; 
411
412    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i );
413    assert( found );
414    assert( tr_isPreallocationMode( i ) );
415    session->preallocationMode = i;
416 
417    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i ); 
418    assert( found ); 
419    session->peerSocketTOS = i; 
420 
421    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ); 
422    assert( found ); 
423    session->downloadDir = tr_strdup( str ); 
424 
425    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_ENABLED, &i ); 
426    assert( found ); 
427    session->isProxyEnabled = i != 0; 
428 
429    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str ); 
430    assert( found ); 
431    session->proxy = tr_strdup( str ); 
432 
433    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i ); 
434    assert( found ); 
435    session->proxyPort = i; 
436 
437    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i ); 
438    assert( found ); 
439    session->proxyType = i; 
440 
441    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &i ); 
442    assert( found ); 
443    session->isProxyAuthEnabled = i != 0; 
444 
445    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str ); 
446    assert( found ); 
447    session->proxyUsername = tr_strdup( str ); 
448 
449    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str ); 
450    assert( found ); 
451    session->proxyPassword = tr_strdup( str ); 
452 
453    session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */ 
454    session->so_rcvbuf = 8192; 
455 
456    tr_setConfigDir( session, configDir ); 
457
458    tr_netInit( ); /* must go before tr_eventInit */
459    tr_eventInit( session );
460    assert( session->events != NULL );
461
462    session->peerMgr = tr_peerMgrNew( session );
463
464    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &i ); 
465    assert( found ); 
466    session->useLazyBitfield = i != 0; 
467
468    /* Initialize rate and file descripts controls */
469
470    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ); 
471    assert( found ); 
472    session->openFileLimit = i;
473    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j ); 
474    assert( found ); 
475    tr_fdInit( session->openFileLimit, j );
476
477    /**
478    *** random port
479    **/ 
480 
481    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &i ); 
482    assert( found ); 
483    session->isPortRandom = i != 0; 
484 
485    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ); 
486    assert( found ); 
487    session->randomPortLow = i; 
488 
489    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ); 
490    assert( found ); 
491    session->randomPortHigh = i; 
492 
493    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PORT_FORWARDING, &i ) 
494         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j ); 
495    assert( found ); 
496    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j; 
497    session->shared = tr_sharedInit( session, i, session->peerPort ); 
498    session->isPortSet = session->isPortRandom || j>0; 
499
500    /**
501    **/ 
502
503    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i );
504    assert( found );
505    session->uploadSlotsPerTorrent = i;
506 
507    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i )
508         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED_ENABLED, &j );
509    assert( found ); 
510    tr_sessionSetSpeedLimit( session, TR_UP, i );
511    tr_sessionSetSpeedLimitEnabled( session, TR_UP, j );
512 
513    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i )
514         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &j );
515    assert( found ); 
516    tr_sessionSetSpeedLimit( session, TR_DOWN, i );
517    tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j );
518
519    /* initialize the blocklist */
520    filename = tr_buildPath( session->configDir, "blocklists", NULL );
521    tr_mkdirp( filename, 0777 );
522    tr_free( filename );
523    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &i ); 
524    assert( found ); 
525    session->isBlocklistEnabled = i; 
526    loadBlocklists( session ); 
527
528    session->rpcServer = tr_rpcInit( session, &settings ); 
529
530    tr_bencFree( &settings );
531
532    tr_runInEventThread( session, tr_sessionInitImpl, session );
533    return session;
534}
535static void
536tr_sessionInitImpl( void * vsession )
537{
538    tr_session * session = vsession;
539 
540    /* first %s is the application name
541       second %s is the version number */
542    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
543
544    tr_statsInit( session );
545
546    session->web = tr_webInit( session ); 
547
548    metainfoLookupRescan( session );
549}
550
551/***
552****
553***/
554
555void
556tr_sessionSetDownloadDir( tr_session * session, const char * dir )
557{
558    if( session->downloadDir != dir )
559    {
560        tr_free( session->downloadDir );
561        session->downloadDir = tr_strdup( dir );
562    }
563}
564
565const char *
566tr_sessionGetDownloadDir( const tr_session * session )
567{
568    return session->downloadDir;
569}
570
571/***
572****
573***/
574
575void
576tr_globalLock( tr_session * session )
577{
578    tr_lockLock( session->lock );
579}
580
581void
582tr_globalUnlock( tr_session * session )
583{
584    tr_lockUnlock( session->lock );
585}
586
587tr_bool
588tr_globalIsLocked( const tr_session * session )
589{
590    return session && tr_lockHave( session->lock );
591}
592
593/***********************************************************************
594 * tr_setBindPort
595 ***********************************************************************
596 *
597 **********************************************************************/
598
599struct bind_port_data
600{
601    tr_session * session;
602    tr_port      port;
603};
604
605static void
606tr_setBindPortImpl( void * vdata )
607{
608    struct bind_port_data * data = vdata;
609    tr_session * session = data->session;
610    const tr_port port = data->port;
611
612    session->isPortSet = 1;
613    tr_sharedSetPort( session->shared, port );
614
615    tr_free( data );
616}
617
618static void
619setPortImpl( tr_session * session, tr_port port )
620{
621    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
622    data->session = session;
623    data->port = port;
624    tr_runInEventThread( session, tr_setBindPortImpl, data );
625}
626
627void
628tr_sessionSetPeerPort( tr_session * session,
629                       tr_port      port )
630{
631    session->isPortRandom = FALSE;
632    session->peerPort = port;
633    setPortImpl( session, session->peerPort );
634}
635
636tr_port
637tr_sessionSetPeerPortRandom( tr_session * session )
638{
639    session->isPortRandom = TRUE;
640    session->peerPort = getRandomPort( session );
641    setPortImpl( session, session->peerPort );
642    return session->peerPort;
643}
644
645tr_port
646tr_sessionGetPeerPort( const tr_session * session )
647{
648    assert( session );
649
650    return session->peerPort;
651}
652
653tr_port_forwarding
654tr_sessionGetPortForwarding( const tr_session * session )
655{
656    return tr_sharedTraversalStatus( session->shared );
657}
658
659/***
660****
661***/
662
663static void
664updateBandwidth( tr_session * session, tr_direction dir )
665{
666    const tr_bool zeroCase = session->speedLimit[dir] < 1 && session->isSpeedLimited[dir];
667
668    tr_bandwidthSetLimited( session->bandwidth, dir, session->isSpeedLimited[dir] && !zeroCase );
669
670    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, session->speedLimit[dir] );
671}
672
673void
674tr_sessionSetSpeedLimitEnabled( tr_session      * session,
675                                tr_direction      dir,
676                                tr_bool           isLimited )
677{
678    assert( session );
679    assert( tr_isDirection( dir ) );
680
681    session->isSpeedLimited[dir] = isLimited;
682    updateBandwidth( session, dir );
683}
684
685void
686tr_sessionSetSpeedLimit( tr_session    * session,
687                         tr_direction    dir,
688                         int             desiredSpeed )
689{
690    assert( session );
691    assert( tr_isDirection( dir ) );
692
693    session->speedLimit[dir] = desiredSpeed;
694    updateBandwidth( session, dir );
695}
696
697tr_bool
698tr_sessionIsSpeedLimitEnabled( const tr_session  * session,
699                               tr_direction        dir )
700{
701    assert( session );
702    assert( tr_isDirection( dir ) );
703
704    return session->isSpeedLimited[dir];
705}
706
707int
708tr_sessionGetSpeedLimit( const tr_session  * session,
709                         tr_direction        dir )
710{
711    assert( session );
712    assert( tr_isDirection( dir ) );
713
714    return session->speedLimit[dir];
715}
716
717/***
718****
719***/
720
721void
722tr_sessionSetPeerLimit( tr_session * session UNUSED,
723                        uint16_t     maxGlobalPeers )
724{
725    tr_fdSetPeerLimit( maxGlobalPeers );
726}
727
728uint16_t
729tr_sessionGetPeerLimit( const tr_session * session UNUSED )
730{
731    return tr_fdGetPeerLimit( );
732}
733
734void
735tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
736{
737    session->peerLimitPerTorrent = n;
738}
739
740uint16_t
741tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
742{
743    return session->peerLimitPerTorrent;
744}
745
746/***
747****
748***/
749
750double
751tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
752{
753    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
754}
755
756double
757tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
758{
759    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
760}
761
762int
763tr_sessionCountTorrents( const tr_session * session )
764{
765    return session->torrentCount;
766}
767
768static int
769compareTorrentByCur( const void * va, const void * vb )
770{
771    const tr_torrent * a = *(const tr_torrent**)va;
772    const tr_torrent * b = *(const tr_torrent**)vb;
773    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
774    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
775
776    if( aCur != bCur )
777        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
778
779    return 0;
780}
781
782static void
783tr_closeAllConnections( void * vsession )
784{
785    tr_session *  session = vsession;
786    tr_torrent *  tor;
787    int           i, n;
788    tr_torrent ** torrents;
789
790    tr_statsClose( session );
791    tr_sharedShuttingDown( session->shared );
792    tr_rpcClose( &session->rpcServer );
793
794    /* close the torrents.  get the most active ones first so that
795     * if we can't get them all closed in a reasonable amount of time,
796     * at least we get the most important ones first. */
797    tor = NULL;
798    n = session->torrentCount;
799    torrents = tr_new( tr_torrent *, session->torrentCount );
800    for( i = 0; i < n; ++i )
801        torrents[i] = tor = tr_torrentNext( session, tor );
802    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
803    for( i = 0; i < n; ++i )
804        tr_torrentFree( torrents[i] );
805    tr_free( torrents );
806
807    tr_peerMgrFree( session->peerMgr );
808
809    tr_trackerSessionClose( session );
810    tr_list_free( &session->blocklists,
811                  (TrListForeachFunc)_tr_blocklistFree );
812    tr_webClose( &session->web );
813
814    session->isClosed = TRUE;
815}
816
817static int
818deadlineReached( const uint64_t deadline )
819{
820    return tr_date( ) >= deadline;
821}
822
823#define SHUTDOWN_MAX_SECONDS 30
824
825void
826tr_sessionClose( tr_session * session )
827{
828    int            i;
829    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
830    const uint64_t deadline = tr_date( ) + maxwait_msec;
831
832    dbgmsg( "shutting down transmission session %p", session );
833
834    /* close the session */
835    tr_runInEventThread( session, tr_closeAllConnections, session );
836    while( !session->isClosed && !deadlineReached( deadline ) )
837    {
838        dbgmsg(
839            "waiting for the shutdown commands to run in the main thread" );
840        tr_wait( 100 );
841    }
842
843    /* "shared" and "tracker" have live sockets,
844     * so we need to keep the transmission thread alive
845     * for a bit while they tell the router & tracker
846     * that we're closing now */
847    while( ( session->shared
848           || session->tracker ) && !deadlineReached( deadline ) )
849    {
850        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
851                session->shared, session->tracker );
852        tr_wait( 100 );
853    }
854
855    tr_fdClose( );
856
857    /* close the libtransmission thread */
858    tr_eventClose( session );
859    while( session->events && !deadlineReached( deadline ) )
860    {
861        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
862        tr_wait( 100 );
863    }
864
865    /* free the session memory */
866    tr_bandwidthFree( session->bandwidth );
867    tr_lockFree( session->lock );
868    for( i = 0; i < session->metainfoLookupCount; ++i )
869        tr_free( session->metainfoLookup[i].filename );
870    tr_free( session->metainfoLookup );
871    tr_free( session->tag );
872    tr_free( session->configDir );
873    tr_free( session->resumeDir );
874    tr_free( session->torrentDir );
875    tr_free( session->downloadDir );
876    tr_free( session->proxy );
877    tr_free( session->proxyUsername );
878    tr_free( session->proxyPassword );
879    tr_free( session );
880}
881
882tr_torrent **
883tr_sessionLoadTorrents( tr_session * session,
884                        tr_ctor    * ctor,
885                        int        * setmeCount )
886{
887    int           i, n = 0;
888    struct stat   sb;
889    DIR *         odir = NULL;
890    const char *  dirname = tr_getTorrentDir( session );
891    tr_torrent ** torrents;
892    tr_list *     l = NULL, *list = NULL;
893
894    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
895
896    if( !stat( dirname, &sb )
897      && S_ISDIR( sb.st_mode )
898      && ( ( odir = opendir ( dirname ) ) ) )
899    {
900        struct dirent *d;
901        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
902        {
903            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
904                                                     */
905            {
906                tr_torrent * tor;
907                char * path = tr_buildPath( dirname, d->d_name, NULL );
908                tr_ctorSetMetainfoFromFile( ctor, path );
909                if(( tor = tr_torrentNew( session, ctor, NULL )))
910                {
911                    tr_list_append( &list, tor );
912                    ++n;
913                }
914                tr_free( path );
915            }
916        }
917        closedir( odir );
918    }
919
920    torrents = tr_new( tr_torrent *, n );
921    for( i = 0, l = list; l != NULL; l = l->next )
922        torrents[i++] = (tr_torrent*) l->data;
923    assert( i == n );
924
925    tr_list_free( &list, NULL );
926
927    if( n )
928        tr_inf( _( "Loaded %d torrents" ), n );
929
930    if( setmeCount )
931        *setmeCount = n;
932    return torrents;
933}
934
935/***
936****
937***/
938
939void
940tr_sessionSetPexEnabled( tr_session * session,
941                         tr_bool      enabled )
942{
943    session->isPexEnabled = enabled != 0;
944}
945
946tr_bool
947tr_sessionIsPexEnabled( const tr_session * session )
948{
949    return session->isPexEnabled;
950}
951
952/***
953****
954***/
955
956void
957tr_sessionSetLazyBitfieldEnabled( tr_session * session,
958                                  tr_bool      enabled )
959{
960    session->useLazyBitfield = enabled != 0;
961}
962
963tr_bool
964tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
965{
966    return session->useLazyBitfield;
967}
968
969/***
970****
971***/
972
973void
974tr_sessionSetPortForwardingEnabled( tr_session  * session,
975                                    tr_bool       enabled )
976{
977    tr_globalLock( session );
978    tr_sharedTraversalEnable( session->shared, enabled );
979    tr_globalUnlock( session );
980}
981
982tr_bool
983tr_sessionIsPortForwardingEnabled( const tr_session * session )
984{
985    return tr_sharedTraversalIsEnabled( session->shared );
986}
987
988/***
989****
990***/
991
992int
993tr_blocklistGetRuleCount( const tr_session * session )
994{
995    int       n = 0;
996    tr_list * l;
997
998    for( l = session->blocklists; l; l = l->next )
999        n += _tr_blocklistGetRuleCount( l->data );
1000    return n;
1001}
1002
1003tr_bool
1004tr_blocklistIsEnabled( const tr_session * session )
1005{
1006    return session->isBlocklistEnabled;
1007}
1008
1009void
1010tr_blocklistSetEnabled( tr_session * session,
1011                        tr_bool      isEnabled )
1012{
1013    tr_list * l;
1014
1015    session->isBlocklistEnabled = isEnabled != 0;
1016
1017    for( l=session->blocklists; l!=NULL; l=l->next )
1018        _tr_blocklistSetEnabled( l->data, isEnabled );
1019}
1020
1021tr_bool
1022tr_blocklistExists( const tr_session * session )
1023{
1024    return session->blocklists != NULL;
1025}
1026
1027int
1028tr_blocklistSetContent( tr_session * session,
1029                        const char * contentFilename )
1030{
1031    tr_list *      l;
1032    tr_blocklist * b;
1033    const char *   defaultName = "level1.bin";
1034
1035    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
1036        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
1037                               defaultName ) )
1038            b = l->data;
1039
1040    if( !b )
1041    {
1042        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
1043        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
1044        tr_list_append( &session->blocklists, b );
1045        tr_free( path );
1046    }
1047
1048    return _tr_blocklistSetContent( b, contentFilename );
1049}
1050
1051tr_bool
1052tr_sessionIsAddressBlocked( const tr_session * session,
1053                            const tr_address * addr )
1054{
1055    tr_list * l;
1056
1057    for( l = session->blocklists; l; l = l->next )
1058        if( _tr_blocklistHasAddress( l->data, addr ) )
1059            return TRUE;
1060    return FALSE;
1061}
1062
1063/***
1064****
1065***/
1066
1067static int
1068compareLookupEntries( const void * va,
1069                      const void * vb )
1070{
1071    const struct tr_metainfo_lookup * a = va;
1072    const struct tr_metainfo_lookup * b = vb;
1073
1074    return strcmp( a->hashString, b->hashString );
1075}
1076
1077static void
1078metainfoLookupResort( tr_session * session )
1079{
1080    qsort( session->metainfoLookup,
1081           session->metainfoLookupCount,
1082           sizeof( struct tr_metainfo_lookup ),
1083           compareLookupEntries );
1084}
1085
1086static int
1087compareHashStringToLookupEntry( const void * va,
1088                                const void * vb )
1089{
1090    const char *                      a = va;
1091    const struct tr_metainfo_lookup * b = vb;
1092
1093    return strcmp( a, b->hashString );
1094}
1095
1096const char*
1097tr_sessionFindTorrentFile( const tr_session * session,
1098                           const char       * hashStr )
1099{
1100    struct tr_metainfo_lookup * l = bsearch( hashStr,
1101                                             session->metainfoLookup,
1102                                             session->metainfoLookupCount,
1103                                             sizeof( struct tr_metainfo_lookup ),
1104                                             compareHashStringToLookupEntry );
1105
1106    return l ? l->filename : NULL;
1107}
1108
1109static void
1110metainfoLookupRescan( tr_session * session )
1111{
1112    int          i;
1113    int          n;
1114    struct stat  sb;
1115    const char * dirname = tr_getTorrentDir( session );
1116    DIR *        odir = NULL;
1117    tr_ctor *    ctor = NULL;
1118    tr_list *    list = NULL;
1119
1120    /* walk through the directory and find the mappings */
1121    ctor = tr_ctorNew( session );
1122    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1123    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
1124    {
1125        struct dirent *d;
1126        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1127        {
1128            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1129                                                     */
1130            {
1131                tr_info inf;
1132                char * path = tr_buildPath( dirname, d->d_name, NULL );
1133                tr_ctorSetMetainfoFromFile( ctor, path );
1134                if( !tr_torrentParse( session, ctor, &inf ) )
1135                {
1136                    tr_list_append( &list, tr_strdup( inf.hashString ) );
1137                    tr_list_append( &list, tr_strdup( path ) );
1138                    tr_metainfoFree( &inf );
1139                }
1140                tr_free( path );
1141            }
1142        }
1143        closedir( odir );
1144    }
1145    tr_ctorFree( ctor );
1146
1147    n = tr_list_size( list ) / 2;
1148    session->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
1149    session->metainfoLookupCount = n;
1150    for( i = 0; i < n; ++i )
1151    {
1152        char * hashString = tr_list_pop_front( &list );
1153        char * filename = tr_list_pop_front( &list );
1154
1155        memcpy( session->metainfoLookup[i].hashString, hashString,
1156                2 * SHA_DIGEST_LENGTH + 1 );
1157        tr_free( hashString );
1158        session->metainfoLookup[i].filename = filename;
1159    }
1160
1161    metainfoLookupResort( session );
1162    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
1163}
1164
1165void
1166tr_sessionSetTorrentFile( tr_session * session,
1167                          const char * hashString,
1168                          const char * filename )
1169{
1170    struct tr_metainfo_lookup * l = bsearch( hashString,
1171                                             session->metainfoLookup,
1172                                             session->metainfoLookupCount,
1173                                             sizeof( struct tr_metainfo_lookup ),
1174                                             compareHashStringToLookupEntry );
1175
1176    if( l )
1177    {
1178        if( l->filename != filename )
1179        {
1180            tr_free( l->filename );
1181            l->filename = tr_strdup( filename );
1182        }
1183    }
1184    else
1185    {
1186        const int n = session->metainfoLookupCount++;
1187        struct tr_metainfo_lookup * node;
1188        session->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
1189                                            session->metainfoLookup,
1190                                            session->metainfoLookupCount );
1191        node = session->metainfoLookup + n;
1192        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
1193        node->filename = tr_strdup( filename );
1194        metainfoLookupResort( session );
1195    }
1196}
1197
1198tr_torrent*
1199tr_torrentNext( tr_session * session,
1200                tr_torrent * tor )
1201{
1202    return tor ? tor->next : session->torrentList;
1203}
1204
1205/***
1206****
1207***/
1208
1209void
1210tr_sessionSetRPCEnabled( tr_session * session,
1211                         tr_bool      isEnabled )
1212{
1213    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1214}
1215
1216tr_bool
1217tr_sessionIsRPCEnabled( const tr_session * session )
1218{
1219    return tr_rpcIsEnabled( session->rpcServer );
1220}
1221
1222void
1223tr_sessionSetRPCPort( tr_session * session,
1224                      tr_port      port )
1225{
1226    tr_rpcSetPort( session->rpcServer, port );
1227}
1228
1229tr_port
1230tr_sessionGetRPCPort( const tr_session * session )
1231{
1232    return tr_rpcGetPort( session->rpcServer );
1233}
1234
1235void
1236tr_sessionSetRPCCallback( tr_session * session,
1237                          tr_rpc_func  func,
1238                          void *       user_data )
1239{
1240    session->rpc_func = func;
1241    session->rpc_func_user_data = user_data;
1242}
1243
1244void
1245tr_sessionSetRPCWhitelist( tr_session * session,
1246                           const char * whitelist )
1247{
1248    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1249}
1250
1251char*
1252tr_sessionGetRPCWhitelist( const tr_session * session )
1253{
1254    return tr_rpcGetWhitelist( session->rpcServer );
1255}
1256
1257void
1258tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1259                                  tr_bool      isEnabled )
1260{
1261    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1262}
1263
1264tr_bool
1265tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1266{
1267    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1268}
1269
1270
1271void
1272tr_sessionSetRPCPassword( tr_session * session,
1273                          const char * password )
1274{
1275    tr_rpcSetPassword( session->rpcServer, password );
1276}
1277
1278char*
1279tr_sessionGetRPCPassword( const tr_session * session )
1280{
1281    return tr_rpcGetPassword( session->rpcServer );
1282}
1283
1284void
1285tr_sessionSetRPCUsername( tr_session * session,
1286                          const char * username )
1287{
1288    tr_rpcSetUsername( session->rpcServer, username );
1289}
1290
1291char*
1292tr_sessionGetRPCUsername( const tr_session * session )
1293{
1294    return tr_rpcGetUsername( session->rpcServer );
1295}
1296
1297void
1298tr_sessionSetRPCPasswordEnabled( tr_session * session,
1299                                 tr_bool      isEnabled )
1300{
1301    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1302}
1303
1304tr_bool
1305tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1306{
1307    return tr_rpcIsPasswordEnabled( session->rpcServer );
1308}
1309
1310/***
1311****
1312***/
1313
1314tr_bool
1315tr_sessionIsProxyEnabled( const tr_session * session )
1316{
1317    return session->isProxyEnabled;
1318}
1319
1320void
1321tr_sessionSetProxyEnabled( tr_session * session,
1322                           tr_bool      isEnabled )
1323{
1324    session->isProxyEnabled = isEnabled != 0;
1325}
1326
1327tr_proxy_type
1328tr_sessionGetProxyType( const tr_session * session )
1329{
1330    return session->proxyType;
1331}
1332
1333void
1334tr_sessionSetProxyType( tr_session *  session,
1335                        tr_proxy_type type )
1336{
1337    session->proxyType = type;
1338}
1339
1340const char*
1341tr_sessionGetProxy( const tr_session * session )
1342{
1343    return session->proxy;
1344}
1345
1346tr_port
1347tr_sessionGetProxyPort( const tr_session * session )
1348{
1349    return session->proxyPort;
1350}
1351
1352void
1353tr_sessionSetProxy( tr_session * session,
1354                    const char * proxy )
1355{
1356    if( proxy != session->proxy )
1357    {
1358        tr_free( session->proxy );
1359        session->proxy = tr_strdup( proxy );
1360    }
1361}
1362
1363void
1364tr_sessionSetProxyPort( tr_session * session,
1365                        tr_port      port )
1366{
1367    session->proxyPort = port;
1368}
1369
1370tr_bool
1371tr_sessionIsProxyAuthEnabled( const tr_session * session )
1372{
1373    return session->isProxyAuthEnabled;
1374}
1375
1376void
1377tr_sessionSetProxyAuthEnabled( tr_session * session,
1378                               tr_bool      isEnabled )
1379{
1380    session->isProxyAuthEnabled = isEnabled != 0;
1381}
1382
1383const char*
1384tr_sessionGetProxyUsername( const tr_session * session )
1385{
1386    return session->proxyUsername;
1387}
1388
1389void
1390tr_sessionSetProxyUsername( tr_session * session,
1391                            const char * username )
1392{
1393    if( username != session->proxyUsername )
1394    {
1395        tr_free( session->proxyUsername );
1396        session->proxyUsername = tr_strdup( username );
1397    }
1398}
1399
1400const char*
1401tr_sessionGetProxyPassword( const tr_session * session )
1402{
1403    return session->proxyPassword;
1404}
1405
1406void
1407tr_sessionSetProxyPassword( tr_session * session,
1408                            const char * password )
1409{
1410    if( password != session->proxyPassword )
1411    {
1412        tr_free( session->proxyPassword );
1413        session->proxyPassword = tr_strdup( password );
1414    }
1415}
1416
1417int
1418tr_sessionGetActiveTorrentCount( tr_session * session )
1419{
1420    int ret = 0;
1421    tr_torrent * tor = NULL;
1422
1423    while(( tor = tr_torrentNext( session, tor )))
1424        if( tr_torrentGetActivity( tor ) != TR_STATUS_STOPPED )
1425            ++ret;
1426   
1427    return ret;
1428}
Note: See TracBrowser for help on using the repository browser.