source: trunk/libtransmission/session.c @ 7646

Last change on this file since 7646 was 7646, checked in by charles, 12 years ago

(trunk libT) finally get around to making upload-slots-per-torrent a settings.json option, thanks to friendly prodding from ful in #transmission

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