source: trunk/libtransmission/session.c @ 7803

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

(trunk libT) add more assertions to make Biiaru crash moreHHHHHHHHHHHHHHHHhelp track down the cause of Biiaru's crashes

  • Property svn:keywords set to Date Rev Author Id
File size: 40.1 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 7803 2009-01-26 02:51:50Z 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 * );
360
361tr_session *
362tr_sessionInit( const char  * tag,
363                const char  * configDir,
364                tr_bool       messageQueuingEnabled,
365                tr_benc     * clientSettings )
366{
367    int64_t i;
368    int64_t j;
369    tr_bool found;
370    const char * str;
371    tr_benc settings;
372    tr_session * session;
373    char * filename;
374
375    assert( tr_bencIsDict( clientSettings ) );
376
377    session = tr_new0( tr_session, 1 );
378    session->bandwidth = tr_bandwidthNew( session, NULL );
379    session->lock = tr_lockNew( );
380    session->tag = tr_strdup( tag );
381    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth );
382
383    tr_bencInitDict( &settings, 0 );
384    tr_sessionGetDefaultSettings( &settings );
385    tr_bencMergeDicts( &settings, clientSettings );
386
387#ifndef WIN32
388    /* Don't exit when writing on a broken socket */
389    signal( SIGPIPE, SIG_IGN );
390#endif
391
392    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ); 
393    assert( found ); 
394    session->peerLimitPerTorrent = i; 
395 
396    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i ); 
397    assert( found ); 
398    tr_setMessageLevel( i ); 
399    tr_setMessageQueuing( messageQueuingEnabled ); 
400 
401 
402    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEX_ENABLED, &i ); 
403    assert( found ); 
404    session->isPexEnabled = i != 0; 
405 
406    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i ); 
407    assert( found ); 
408    assert( tr_isEncryptionMode( i ) );
409    session->encryptionMode = i; 
410
411    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i );
412    assert( found );
413    assert( tr_isPreallocationMode( i ) );
414    session->preallocationMode = i;
415 
416    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i ); 
417    assert( found ); 
418    session->peerSocketTOS = i; 
419 
420    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ); 
421    assert( found ); 
422    session->downloadDir = tr_strdup( str ); 
423 
424    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_ENABLED, &i ); 
425    assert( found ); 
426    session->isProxyEnabled = i != 0; 
427 
428    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str ); 
429    assert( found ); 
430    session->proxy = tr_strdup( str ); 
431 
432    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i ); 
433    assert( found ); 
434    session->proxyPort = i; 
435 
436    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i ); 
437    assert( found ); 
438    session->proxyType = i; 
439 
440    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &i ); 
441    assert( found ); 
442    session->isProxyAuthEnabled = i != 0; 
443 
444    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str ); 
445    assert( found ); 
446    session->proxyUsername = tr_strdup( str ); 
447 
448    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str ); 
449    assert( found ); 
450    session->proxyPassword = tr_strdup( str ); 
451 
452    session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */ 
453    session->so_rcvbuf = 8192; 
454 
455    tr_setConfigDir( session, configDir ); 
456
457    tr_netInit( ); /* must go before tr_eventInit */
458    tr_eventInit( session );
459    assert( session->events != NULL );
460
461    session->peerMgr = tr_peerMgrNew( session );
462
463    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &i ); 
464    assert( found ); 
465    session->useLazyBitfield = i != 0; 
466
467    /* Initialize rate and file descripts controls */
468
469    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ); 
470    assert( found ); 
471    session->openFileLimit = i;
472    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j ); 
473    assert( found ); 
474    tr_fdInit( session->openFileLimit, j );
475
476    /**
477    *** random port
478    **/ 
479 
480    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &i ); 
481    assert( found ); 
482    session->isPortRandom = i != 0; 
483 
484    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ); 
485    assert( found ); 
486    session->randomPortLow = i; 
487 
488    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ); 
489    assert( found ); 
490    session->randomPortHigh = i; 
491 
492    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PORT_FORWARDING, &i ) 
493         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j ); 
494    assert( found ); 
495    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j; 
496    session->shared = tr_sharedInit( session, i, session->peerPort ); 
497    session->isPortSet = session->isPortRandom || j>0; 
498
499    /**
500    **/ 
501
502    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i );
503    assert( found );
504    session->uploadSlotsPerTorrent = i;
505 
506    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i )
507         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED_ENABLED, &j );
508    assert( found ); 
509    tr_sessionSetSpeedLimit( session, TR_UP, i );
510    tr_sessionSetSpeedLimitEnabled( session, TR_UP, j );
511 
512    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i )
513         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &j );
514    assert( found ); 
515    tr_sessionSetSpeedLimit( session, TR_DOWN, i );
516    tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j );
517 
518    /* first %s is the application name
519       second %s is the version number */
520    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
521
522    /* initialize the blocklist */
523    filename = tr_buildPath( session->configDir, "blocklists", NULL );
524    tr_mkdirp( filename, 0777 );
525    tr_free( filename );
526    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &i ); 
527    assert( found ); 
528    session->isBlocklistEnabled = i; 
529    loadBlocklists( session ); 
530
531    tr_statsInit( session );
532
533    session->web = tr_webInit( session ); 
534    session->rpcServer = tr_rpcInit( session, &settings ); 
535
536    metainfoLookupRescan( session );
537
538    tr_bencFree( &settings );
539    return session;
540}
541
542/***
543****
544***/
545
546void
547tr_sessionSetDownloadDir( tr_session * session, const char * dir )
548{
549    if( session->downloadDir != dir )
550    {
551        tr_free( session->downloadDir );
552        session->downloadDir = tr_strdup( dir );
553    }
554}
555
556const char *
557tr_sessionGetDownloadDir( const tr_session * session )
558{
559    return session->downloadDir;
560}
561
562/***
563****
564***/
565
566void
567tr_globalLock( tr_session * session )
568{
569    tr_lockLock( session->lock );
570}
571
572void
573tr_globalUnlock( tr_session * session )
574{
575    tr_lockUnlock( session->lock );
576}
577
578tr_bool
579tr_globalIsLocked( const tr_session * session )
580{
581    return session && tr_lockHave( session->lock );
582}
583
584/***********************************************************************
585 * tr_setBindPort
586 ***********************************************************************
587 *
588 **********************************************************************/
589
590struct bind_port_data
591{
592    tr_session * session;
593    tr_port      port;
594};
595
596static void
597tr_setBindPortImpl( void * vdata )
598{
599    struct bind_port_data * data = vdata;
600    tr_session * session = data->session;
601    const tr_port port = data->port;
602
603    session->isPortSet = 1;
604    tr_sharedSetPort( session->shared, port );
605
606    tr_free( data );
607}
608
609static void
610setPortImpl( tr_session * session, tr_port port )
611{
612    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
613    data->session = session;
614    data->port = port;
615    tr_runInEventThread( session, tr_setBindPortImpl, data );
616}
617
618void
619tr_sessionSetPeerPort( tr_session * session,
620                       tr_port      port )
621{
622    session->isPortRandom = FALSE;
623    session->peerPort = port;
624    setPortImpl( session, session->peerPort );
625}
626
627tr_port
628tr_sessionSetPeerPortRandom( tr_session * session )
629{
630    session->isPortRandom = TRUE;
631    session->peerPort = getRandomPort( session );
632    setPortImpl( session, session->peerPort );
633    return session->peerPort;
634}
635
636tr_port
637tr_sessionGetPeerPort( const tr_session * session )
638{
639    assert( session );
640
641    return session->peerPort;
642}
643
644tr_port_forwarding
645tr_sessionGetPortForwarding( const tr_session * session )
646{
647    return tr_sharedTraversalStatus( session->shared );
648}
649
650/***
651****
652***/
653
654static void
655updateBandwidth( tr_session * session, tr_direction dir )
656{
657    const tr_bool zeroCase = session->speedLimit[dir] < 1 && session->isSpeedLimited[dir];
658
659    tr_bandwidthSetLimited( session->bandwidth, dir, session->isSpeedLimited[dir] && !zeroCase );
660
661    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, session->speedLimit[dir] );
662}
663
664void
665tr_sessionSetSpeedLimitEnabled( tr_session      * session,
666                                tr_direction      dir,
667                                tr_bool           isLimited )
668{
669    assert( session );
670    assert( tr_isDirection( dir ) );
671
672    session->isSpeedLimited[dir] = isLimited;
673    updateBandwidth( session, dir );
674}
675
676void
677tr_sessionSetSpeedLimit( tr_session    * session,
678                         tr_direction    dir,
679                         int             desiredSpeed )
680{
681    assert( session );
682    assert( tr_isDirection( dir ) );
683
684    session->speedLimit[dir] = desiredSpeed;
685    updateBandwidth( session, dir );
686}
687
688tr_bool
689tr_sessionIsSpeedLimitEnabled( const tr_session  * session,
690                               tr_direction        dir )
691{
692    assert( session );
693    assert( tr_isDirection( dir ) );
694
695    return session->isSpeedLimited[dir];
696}
697
698int
699tr_sessionGetSpeedLimit( const tr_session  * session,
700                         tr_direction        dir )
701{
702    assert( session );
703    assert( tr_isDirection( dir ) );
704
705    return session->speedLimit[dir];
706}
707
708/***
709****
710***/
711
712void
713tr_sessionSetPeerLimit( tr_session * session UNUSED,
714                        uint16_t     maxGlobalPeers )
715{
716    tr_fdSetPeerLimit( maxGlobalPeers );
717}
718
719uint16_t
720tr_sessionGetPeerLimit( const tr_session * session UNUSED )
721{
722    return tr_fdGetPeerLimit( );
723}
724
725void
726tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
727{
728    session->peerLimitPerTorrent = n;
729}
730
731uint16_t
732tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
733{
734    return session->peerLimitPerTorrent;
735}
736
737/***
738****
739***/
740
741double
742tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
743{
744    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
745}
746
747double
748tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
749{
750    return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
751}
752
753int
754tr_sessionCountTorrents( const tr_session * session )
755{
756    return session->torrentCount;
757}
758
759static int
760compareTorrentByCur( const void * va, const void * vb )
761{
762    const tr_torrent * a = *(const tr_torrent**)va;
763    const tr_torrent * b = *(const tr_torrent**)vb;
764    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
765    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
766
767    if( aCur != bCur )
768        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
769
770    return 0;
771}
772
773static void
774tr_closeAllConnections( void * vsession )
775{
776    tr_session *  session = vsession;
777    tr_torrent *  tor;
778    int           i, n;
779    tr_torrent ** torrents;
780
781    tr_statsClose( session );
782    tr_sharedShuttingDown( session->shared );
783    tr_rpcClose( &session->rpcServer );
784
785    /* close the torrents.  get the most active ones first so that
786     * if we can't get them all closed in a reasonable amount of time,
787     * at least we get the most important ones first. */
788    tor = NULL;
789    n = session->torrentCount;
790    torrents = tr_new( tr_torrent *, session->torrentCount );
791    for( i = 0; i < n; ++i )
792        torrents[i] = tor = tr_torrentNext( session, tor );
793    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
794    for( i = 0; i < n; ++i )
795        tr_torrentFree( torrents[i] );
796    tr_free( torrents );
797
798    tr_peerMgrFree( session->peerMgr );
799
800    tr_trackerSessionClose( session );
801    tr_list_free( &session->blocklists,
802                  (TrListForeachFunc)_tr_blocklistFree );
803    tr_webClose( &session->web );
804
805    session->isClosed = TRUE;
806}
807
808static int
809deadlineReached( const uint64_t deadline )
810{
811    return tr_date( ) >= deadline;
812}
813
814#define SHUTDOWN_MAX_SECONDS 30
815
816void
817tr_sessionClose( tr_session * session )
818{
819    int            i;
820    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
821    const uint64_t deadline = tr_date( ) + maxwait_msec;
822
823    dbgmsg( "shutting down transmission session %p", session );
824
825    /* close the session */
826    tr_runInEventThread( session, tr_closeAllConnections, session );
827    while( !session->isClosed && !deadlineReached( deadline ) )
828    {
829        dbgmsg(
830            "waiting for the shutdown commands to run in the main thread" );
831        tr_wait( 100 );
832    }
833
834    /* "shared" and "tracker" have live sockets,
835     * so we need to keep the transmission thread alive
836     * for a bit while they tell the router & tracker
837     * that we're closing now */
838    while( ( session->shared
839           || session->tracker ) && !deadlineReached( deadline ) )
840    {
841        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
842                session->shared, session->tracker );
843        tr_wait( 100 );
844    }
845
846    tr_fdClose( );
847
848    /* close the libtransmission thread */
849    tr_eventClose( session );
850    while( session->events && !deadlineReached( deadline ) )
851    {
852        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
853        tr_wait( 100 );
854    }
855
856    /* free the session memory */
857    tr_bandwidthFree( session->bandwidth );
858    tr_lockFree( session->lock );
859    for( i = 0; i < session->metainfoLookupCount; ++i )
860        tr_free( session->metainfoLookup[i].filename );
861    tr_free( session->metainfoLookup );
862    tr_free( session->tag );
863    tr_free( session->configDir );
864    tr_free( session->resumeDir );
865    tr_free( session->torrentDir );
866    tr_free( session->downloadDir );
867    tr_free( session->proxy );
868    tr_free( session->proxyUsername );
869    tr_free( session->proxyPassword );
870    tr_free( session );
871}
872
873tr_torrent **
874tr_sessionLoadTorrents( tr_session * session,
875                        tr_ctor    * ctor,
876                        int        * setmeCount )
877{
878    int           i, n = 0;
879    struct stat   sb;
880    DIR *         odir = NULL;
881    const char *  dirname = tr_getTorrentDir( session );
882    tr_torrent ** torrents;
883    tr_list *     l = NULL, *list = NULL;
884
885    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
886
887    if( !stat( dirname, &sb )
888      && S_ISDIR( sb.st_mode )
889      && ( ( odir = opendir ( dirname ) ) ) )
890    {
891        struct dirent *d;
892        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
893        {
894            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
895                                                     */
896            {
897                tr_torrent * tor;
898                char * path = tr_buildPath( dirname, d->d_name, NULL );
899                tr_ctorSetMetainfoFromFile( ctor, path );
900                if(( tor = tr_torrentNew( session, ctor, NULL )))
901                {
902                    tr_list_append( &list, tor );
903                    ++n;
904                }
905                tr_free( path );
906            }
907        }
908        closedir( odir );
909    }
910
911    torrents = tr_new( tr_torrent *, n );
912    for( i = 0, l = list; l != NULL; l = l->next )
913        torrents[i++] = (tr_torrent*) l->data;
914    assert( i == n );
915
916    tr_list_free( &list, NULL );
917
918    if( n )
919        tr_inf( _( "Loaded %d torrents" ), n );
920
921    if( setmeCount )
922        *setmeCount = n;
923    return torrents;
924}
925
926/***
927****
928***/
929
930void
931tr_sessionSetPexEnabled( tr_session * session,
932                         tr_bool      enabled )
933{
934    session->isPexEnabled = enabled != 0;
935}
936
937tr_bool
938tr_sessionIsPexEnabled( const tr_session * session )
939{
940    return session->isPexEnabled;
941}
942
943/***
944****
945***/
946
947void
948tr_sessionSetLazyBitfieldEnabled( tr_session * session,
949                                  tr_bool      enabled )
950{
951    session->useLazyBitfield = enabled != 0;
952}
953
954tr_bool
955tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
956{
957    return session->useLazyBitfield;
958}
959
960/***
961****
962***/
963
964void
965tr_sessionSetPortForwardingEnabled( tr_session  * session,
966                                    tr_bool       enabled )
967{
968    tr_globalLock( session );
969    tr_sharedTraversalEnable( session->shared, enabled );
970    tr_globalUnlock( session );
971}
972
973tr_bool
974tr_sessionIsPortForwardingEnabled( const tr_session * session )
975{
976    return tr_sharedTraversalIsEnabled( session->shared );
977}
978
979/***
980****
981***/
982
983int
984tr_blocklistGetRuleCount( const tr_session * session )
985{
986    int       n = 0;
987    tr_list * l;
988
989    for( l = session->blocklists; l; l = l->next )
990        n += _tr_blocklistGetRuleCount( l->data );
991    return n;
992}
993
994tr_bool
995tr_blocklistIsEnabled( const tr_session * session )
996{
997    return session->isBlocklistEnabled;
998}
999
1000void
1001tr_blocklistSetEnabled( tr_session * session,
1002                        tr_bool      isEnabled )
1003{
1004    tr_list * l;
1005
1006    session->isBlocklistEnabled = isEnabled != 0;
1007
1008    for( l=session->blocklists; l!=NULL; l=l->next )
1009        _tr_blocklistSetEnabled( l->data, isEnabled );
1010}
1011
1012tr_bool
1013tr_blocklistExists( const tr_session * session )
1014{
1015    return session->blocklists != NULL;
1016}
1017
1018int
1019tr_blocklistSetContent( tr_session * session,
1020                        const char * contentFilename )
1021{
1022    tr_list *      l;
1023    tr_blocklist * b;
1024    const char *   defaultName = "level1.bin";
1025
1026    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
1027        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
1028                               defaultName ) )
1029            b = l->data;
1030
1031    if( !b )
1032    {
1033        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
1034        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
1035        tr_list_append( &session->blocklists, b );
1036        tr_free( path );
1037    }
1038
1039    return _tr_blocklistSetContent( b, contentFilename );
1040}
1041
1042tr_bool
1043tr_sessionIsAddressBlocked( const tr_session * session,
1044                            const tr_address * addr )
1045{
1046    tr_list * l;
1047
1048    for( l = session->blocklists; l; l = l->next )
1049        if( _tr_blocklistHasAddress( l->data, addr ) )
1050            return TRUE;
1051    return FALSE;
1052}
1053
1054/***
1055****
1056***/
1057
1058static int
1059compareLookupEntries( const void * va,
1060                      const void * vb )
1061{
1062    const struct tr_metainfo_lookup * a = va;
1063    const struct tr_metainfo_lookup * b = vb;
1064
1065    return strcmp( a->hashString, b->hashString );
1066}
1067
1068static void
1069metainfoLookupResort( tr_session * session )
1070{
1071    qsort( session->metainfoLookup,
1072           session->metainfoLookupCount,
1073           sizeof( struct tr_metainfo_lookup ),
1074           compareLookupEntries );
1075}
1076
1077static int
1078compareHashStringToLookupEntry( const void * va,
1079                                const void * vb )
1080{
1081    const char *                      a = va;
1082    const struct tr_metainfo_lookup * b = vb;
1083
1084    return strcmp( a, b->hashString );
1085}
1086
1087const char*
1088tr_sessionFindTorrentFile( const tr_session * session,
1089                           const char       * hashStr )
1090{
1091    struct tr_metainfo_lookup * l = bsearch( hashStr,
1092                                             session->metainfoLookup,
1093                                             session->metainfoLookupCount,
1094                                             sizeof( struct tr_metainfo_lookup ),
1095                                             compareHashStringToLookupEntry );
1096
1097    return l ? l->filename : NULL;
1098}
1099
1100static void
1101metainfoLookupRescan( tr_session * session )
1102{
1103    int          i;
1104    int          n;
1105    struct stat  sb;
1106    const char * dirname = tr_getTorrentDir( session );
1107    DIR *        odir = NULL;
1108    tr_ctor *    ctor = NULL;
1109    tr_list *    list = NULL;
1110
1111    /* walk through the directory and find the mappings */
1112    ctor = tr_ctorNew( session );
1113    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1114    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
1115    {
1116        struct dirent *d;
1117        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1118        {
1119            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1120                                                     */
1121            {
1122                tr_info inf;
1123                char * path = tr_buildPath( dirname, d->d_name, NULL );
1124                tr_ctorSetMetainfoFromFile( ctor, path );
1125                if( !tr_torrentParse( session, ctor, &inf ) )
1126                {
1127                    tr_list_append( &list, tr_strdup( inf.hashString ) );
1128                    tr_list_append( &list, tr_strdup( path ) );
1129                    tr_metainfoFree( &inf );
1130                }
1131                tr_free( path );
1132            }
1133        }
1134        closedir( odir );
1135    }
1136    tr_ctorFree( ctor );
1137
1138    n = tr_list_size( list ) / 2;
1139    session->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
1140    session->metainfoLookupCount = n;
1141    for( i = 0; i < n; ++i )
1142    {
1143        char * hashString = tr_list_pop_front( &list );
1144        char * filename = tr_list_pop_front( &list );
1145
1146        memcpy( session->metainfoLookup[i].hashString, hashString,
1147                2 * SHA_DIGEST_LENGTH + 1 );
1148        tr_free( hashString );
1149        session->metainfoLookup[i].filename = filename;
1150    }
1151
1152    metainfoLookupResort( session );
1153    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
1154}
1155
1156void
1157tr_sessionSetTorrentFile( tr_session * session,
1158                          const char * hashString,
1159                          const char * filename )
1160{
1161    struct tr_metainfo_lookup * l = bsearch( hashString,
1162                                             session->metainfoLookup,
1163                                             session->metainfoLookupCount,
1164                                             sizeof( struct tr_metainfo_lookup ),
1165                                             compareHashStringToLookupEntry );
1166
1167    if( l )
1168    {
1169        if( l->filename != filename )
1170        {
1171            tr_free( l->filename );
1172            l->filename = tr_strdup( filename );
1173        }
1174    }
1175    else
1176    {
1177        const int n = session->metainfoLookupCount++;
1178        struct tr_metainfo_lookup * node;
1179        session->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
1180                                            session->metainfoLookup,
1181                                            session->metainfoLookupCount );
1182        node = session->metainfoLookup + n;
1183        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
1184        node->filename = tr_strdup( filename );
1185        metainfoLookupResort( session );
1186    }
1187}
1188
1189tr_torrent*
1190tr_torrentNext( tr_session * session,
1191                tr_torrent * tor )
1192{
1193    return tor ? tor->next : session->torrentList;
1194}
1195
1196/***
1197****
1198***/
1199
1200void
1201tr_sessionSetRPCEnabled( tr_session * session,
1202                         tr_bool      isEnabled )
1203{
1204    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1205}
1206
1207tr_bool
1208tr_sessionIsRPCEnabled( const tr_session * session )
1209{
1210    return tr_rpcIsEnabled( session->rpcServer );
1211}
1212
1213void
1214tr_sessionSetRPCPort( tr_session * session,
1215                      tr_port      port )
1216{
1217    tr_rpcSetPort( session->rpcServer, port );
1218}
1219
1220tr_port
1221tr_sessionGetRPCPort( const tr_session * session )
1222{
1223    return tr_rpcGetPort( session->rpcServer );
1224}
1225
1226void
1227tr_sessionSetRPCCallback( tr_session * session,
1228                          tr_rpc_func  func,
1229                          void *       user_data )
1230{
1231    session->rpc_func = func;
1232    session->rpc_func_user_data = user_data;
1233}
1234
1235void
1236tr_sessionSetRPCWhitelist( tr_session * session,
1237                           const char * whitelist )
1238{
1239    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1240}
1241
1242char*
1243tr_sessionGetRPCWhitelist( const tr_session * session )
1244{
1245    return tr_rpcGetWhitelist( session->rpcServer );
1246}
1247
1248void
1249tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1250                                  tr_bool      isEnabled )
1251{
1252    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1253}
1254
1255tr_bool
1256tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1257{
1258    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1259}
1260
1261
1262void
1263tr_sessionSetRPCPassword( tr_session * session,
1264                          const char * password )
1265{
1266    tr_rpcSetPassword( session->rpcServer, password );
1267}
1268
1269char*
1270tr_sessionGetRPCPassword( const tr_session * session )
1271{
1272    return tr_rpcGetPassword( session->rpcServer );
1273}
1274
1275void
1276tr_sessionSetRPCUsername( tr_session * session,
1277                          const char * username )
1278{
1279    tr_rpcSetUsername( session->rpcServer, username );
1280}
1281
1282char*
1283tr_sessionGetRPCUsername( const tr_session * session )
1284{
1285    return tr_rpcGetUsername( session->rpcServer );
1286}
1287
1288void
1289tr_sessionSetRPCPasswordEnabled( tr_session * session,
1290                                 tr_bool      isEnabled )
1291{
1292    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1293}
1294
1295tr_bool
1296tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1297{
1298    return tr_rpcIsPasswordEnabled( session->rpcServer );
1299}
1300
1301/***
1302****
1303***/
1304
1305tr_bool
1306tr_sessionIsProxyEnabled( const tr_session * session )
1307{
1308    return session->isProxyEnabled;
1309}
1310
1311void
1312tr_sessionSetProxyEnabled( tr_session * session,
1313                           tr_bool      isEnabled )
1314{
1315    session->isProxyEnabled = isEnabled != 0;
1316}
1317
1318tr_proxy_type
1319tr_sessionGetProxyType( const tr_session * session )
1320{
1321    return session->proxyType;
1322}
1323
1324void
1325tr_sessionSetProxyType( tr_session *  session,
1326                        tr_proxy_type type )
1327{
1328    session->proxyType = type;
1329}
1330
1331const char*
1332tr_sessionGetProxy( const tr_session * session )
1333{
1334    return session->proxy;
1335}
1336
1337tr_port
1338tr_sessionGetProxyPort( const tr_session * session )
1339{
1340    return session->proxyPort;
1341}
1342
1343void
1344tr_sessionSetProxy( tr_session * session,
1345                    const char * proxy )
1346{
1347    if( proxy != session->proxy )
1348    {
1349        tr_free( session->proxy );
1350        session->proxy = tr_strdup( proxy );
1351    }
1352}
1353
1354void
1355tr_sessionSetProxyPort( tr_session * session,
1356                        tr_port      port )
1357{
1358    session->proxyPort = port;
1359}
1360
1361tr_bool
1362tr_sessionIsProxyAuthEnabled( const tr_session * session )
1363{
1364    return session->isProxyAuthEnabled;
1365}
1366
1367void
1368tr_sessionSetProxyAuthEnabled( tr_session * session,
1369                               tr_bool      isEnabled )
1370{
1371    session->isProxyAuthEnabled = isEnabled != 0;
1372}
1373
1374const char*
1375tr_sessionGetProxyUsername( const tr_session * session )
1376{
1377    return session->proxyUsername;
1378}
1379
1380void
1381tr_sessionSetProxyUsername( tr_session * session,
1382                            const char * username )
1383{
1384    if( username != session->proxyUsername )
1385    {
1386        tr_free( session->proxyUsername );
1387        session->proxyUsername = tr_strdup( username );
1388    }
1389}
1390
1391const char*
1392tr_sessionGetProxyPassword( const tr_session * session )
1393{
1394    return session->proxyPassword;
1395}
1396
1397void
1398tr_sessionSetProxyPassword( tr_session * session,
1399                            const char * password )
1400{
1401    if( password != session->proxyPassword )
1402    {
1403        tr_free( session->proxyPassword );
1404        session->proxyPassword = tr_strdup( password );
1405    }
1406}
1407
1408int
1409tr_sessionGetActiveTorrentCount( tr_session * session )
1410{
1411    int ret = 0;
1412    tr_torrent * tor = NULL;
1413
1414    while(( tor = tr_torrentNext( session, tor )))
1415        if( tr_torrentGetActivity( tor ) != TR_STATUS_STOPPED )
1416            ++ret;
1417   
1418    return ret;
1419}
Note: See TracBrowser for help on using the repository browser.