source: trunk/libtransmission/session.c @ 8967

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

(trunk) un-remove the conditional DHT compiling for now for reasons discussed @ http://lists.opensuse.org/opensuse-gnome/2009-08/msg00033.html. I'll re-remove it for 1.80. :)

  • Property svn:keywords set to Date Rev Author Id
File size: 59.6 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 8967 2009-08-18 16:02:16Z 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(), umask() */
19#include <sys/stat.h> /* stat(), umask() */
20#include <unistd.h> /* stat */
21#include <dirent.h> /* opendir */
22
23#include <event.h>
24
25#include "transmission.h"
26#include "bandwidth.h"
27#include "bencode.h"
28#include "blocklist.h"
29#include "crypto.h"
30#include "fdlimit.h"
31#include "list.h"
32#include "metainfo.h" /* tr_metainfoFree */
33#include "net.h"
34#include "peer-io.h"
35#include "peer-mgr.h"
36#include "platform.h" /* tr_lock */
37#include "port-forwarding.h"
38#include "rpc-server.h"
39#include "session.h"
40#include "stats.h"
41#include "torrent.h"
42#include "tracker.h"
43#include "tr-dht.h"
44#include "trevent.h"
45#include "utils.h"
46#include "verify.h"
47#include "version.h"
48#include "web.h"
49
50enum
51{
52    SAVE_INTERVAL_SECS = 120
53};
54
55
56#define dbgmsg( ... ) \
57    do { \
58        if( tr_deepLoggingIsActive( ) ) \
59            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
60    } while( 0 )
61
62static tr_port
63getRandomPort( tr_session * s )
64{
65    return tr_cryptoWeakRandInt( s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow;
66}
67
68/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
69   characters, where x is the major version number, y is the
70   minor version number, z is the maintenance number, and b
71   designates beta (Azureus-style) */
72uint8_t*
73tr_peerIdNew( void )
74{
75    int          i;
76    int          val;
77    int          total = 0;
78    uint8_t *    buf = tr_new( uint8_t, 21 );
79    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
80    const int    base = 36;
81
82    memcpy( buf, PEERID_PREFIX, 8 );
83
84    for( i = 8; i < 19; ++i )
85    {
86        val = tr_cryptoRandInt( base );
87        total += val;
88        buf[i] = pool[val];
89    }
90
91    val = total % base ? base - ( total % base ) : 0;
92    buf[19] = pool[val];
93    buf[20] = '\0';
94
95    return buf;
96}
97
98const uint8_t*
99tr_getPeerId( void )
100{
101    static uint8_t * id = NULL;
102
103    if( id == NULL )
104        id = tr_peerIdNew( );
105    return id;
106}
107
108/***
109****
110***/
111
112tr_encryption_mode
113tr_sessionGetEncryption( tr_session * session )
114{
115    assert( session );
116
117    return session->encryptionMode;
118}
119
120void
121tr_sessionSetEncryption( tr_session *       session,
122                         tr_encryption_mode mode )
123{
124    assert( session );
125    assert( mode == TR_ENCRYPTION_PREFERRED
126          || mode == TR_ENCRYPTION_REQUIRED
127          || mode == TR_CLEAR_PREFERRED );
128
129    session->encryptionMode = mode;
130}
131
132/***
133****
134***/
135
136struct tr_bindinfo
137{
138    int socket;
139    tr_address addr;
140    struct event ev;
141};
142
143
144static void
145close_bindinfo( struct tr_bindinfo * b )
146{
147    if( b->socket >=0 )
148    {
149        event_del( &b->ev );
150        EVUTIL_CLOSESOCKET( b->socket );
151    }
152}
153
154static void
155close_incoming_peer_port( tr_session * session )
156{
157    close_bindinfo( session->public_ipv4 );
158    close_bindinfo( session->public_ipv6 );
159}
160
161static void
162free_incoming_peer_port( tr_session * session )
163{
164    close_bindinfo( session->public_ipv4 );
165    tr_free( session->public_ipv4 );
166    session->public_ipv4 = NULL;
167
168    close_bindinfo( session->public_ipv6 );
169    tr_free( session->public_ipv6 );
170    session->public_ipv6 = NULL;
171}
172
173static void
174accept_incoming_peer( int fd, short what UNUSED, void * vsession )
175{
176    int clientSocket;
177    tr_port clientPort;
178    tr_address clientAddr;
179    tr_session * session = vsession;
180
181    clientSocket = tr_netAccept( session, fd, &clientAddr, &clientPort );
182    if( clientSocket > 0 ) {
183        tr_deepLog( __FILE__, __LINE__, NULL, "new incoming connection %d (%s)",
184                   clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
185        tr_peerMgrAddIncoming( session->peerMgr, &clientAddr, clientPort, clientSocket );
186    }
187}
188
189static void
190open_incoming_peer_port( tr_session * session )
191{
192    struct tr_bindinfo * b;
193
194    /* bind an ipv4 port to listen for incoming peers... */
195    b = session->public_ipv4;
196    b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
197    if( b->socket >= 0 ) {
198        event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
199        event_add( &b->ev, NULL );
200    }
201
202    /* and do the exact same thing for ipv6, if it's supported... */
203    if( tr_net_hasIPv6( session->peerPort ) ) {
204        b = session->public_ipv6;
205        b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
206        if( b->socket >= 0 ) {
207            event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
208            event_add( &b->ev, NULL );
209        }
210    }
211}
212
213const tr_address*
214tr_sessionGetPublicAddress( const tr_session * session, int tr_af_type )
215{
216    switch( tr_af_type )
217    {
218        case TR_AF_INET: return &session->public_ipv4->addr;
219        case TR_AF_INET6: return &session->public_ipv6->addr; break;
220        default: return NULL;
221    }
222}
223
224/***
225****
226***/
227
228static int
229tr_stringEndsWith( const char * str, const char * end )
230{
231    const size_t slen = strlen( str );
232    const size_t elen = strlen( end );
233
234    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
235}
236
237static void
238loadBlocklists( tr_session * session )
239{
240    int         binCount = 0;
241    int         newCount = 0;
242    struct stat sb;
243    char      * dirname;
244    DIR *       odir = NULL;
245    tr_list *   list = NULL;
246    const tr_bool   isEnabled = session->isBlocklistEnabled;
247
248    /* walk through the directory and find blocklists */
249    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
250    if( !stat( dirname,
251               &sb ) && S_ISDIR( sb.st_mode )
252      && ( ( odir = opendir( dirname ) ) ) )
253    {
254        struct dirent *d;
255        for( d = readdir( odir ); d; d = readdir( odir ) )
256        {
257            char * filename;
258
259            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
260                                                      */
261                continue;
262
263            filename = tr_buildPath( dirname, d->d_name, NULL );
264
265            if( tr_stringEndsWith( filename, ".bin" ) )
266            {
267                /* if we don't already have this blocklist, add it */
268                if( !tr_list_find( list, filename,
269                                   (TrListCompareFunc)strcmp ) )
270                {
271                    tr_list_append( &list,
272                                   _tr_blocklistNew( filename, isEnabled ) );
273                    ++binCount;
274                }
275            }
276            else
277            {
278                /* strip out the file suffix, if there is one, and add ".bin"
279                  instead */
280                tr_blocklist * b;
281                const char *   dot = strrchr( d->d_name, '.' );
282                const int      len = dot ? dot - d->d_name
283                                         : (int)strlen( d->d_name );
284                char         * tmp = tr_strdup_printf(
285                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
286                                        dirname, len, len, d->d_name );
287                b = _tr_blocklistNew( tmp, isEnabled );
288                _tr_blocklistSetContent( b, filename );
289                tr_list_append( &list, b );
290                ++newCount;
291                tr_free( tmp );
292            }
293
294            tr_free( filename );
295        }
296
297        closedir( odir );
298    }
299
300    session->blocklists = list;
301
302    if( binCount )
303        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
304    if( newCount )
305        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
306
307    tr_free( dirname );
308}
309
310static tr_bool
311isAltTime( const tr_session * s )
312{
313    int minutes, day;
314    tr_bool withinTime;
315    struct tm tm;
316    const time_t now = time( NULL );
317    const int begin = s->altSpeedTimeBegin;
318    const int end = s->altSpeedTimeEnd;
319    const tr_bool toNextDay = begin > end;
320
321    tr_localtime_r( &now, &tm );
322    minutes = tm.tm_hour*60 + tm.tm_min;
323    day = tm.tm_wday;
324
325    if( !toNextDay )
326        withinTime = ( begin <= minutes ) && ( minutes < end );
327    else /* goes past midnight */
328        withinTime = ( begin <= minutes ) || ( minutes < end );
329
330    if( !withinTime )
331        return FALSE;
332
333    if( toNextDay && (minutes < end) )
334        day = (day - 1) % 7;
335
336    return ((1<<day) & s->altSpeedTimeDay) != 0;
337}
338
339/***
340****
341***/
342
343#ifdef TR_EMBEDDED
344 #define TR_DEFAULT_ENCRYPTION   TR_CLEAR_PREFERRED
345#else
346 #define TR_DEFAULT_ENCRYPTION   TR_ENCRYPTION_PREFERRED
347#endif
348
349void
350tr_sessionGetDefaultSettings( tr_benc * d )
351{
352    assert( tr_bencIsDict( d ) );
353
354    tr_bencDictReserve( d, 35 );
355    tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        FALSE );
356    tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED,              TRUE );
357    tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR,             tr_getDefaultDownloadDir( ) );
358    tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED,                   100 );
359    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           FALSE );
360    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               TR_DEFAULT_ENCRYPTION );
361    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
362    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
363    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
364    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
365    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       atoi( TR_DEFAULT_PEER_LIMIT_TORRENT_STR ) );
366    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT,                atoi( TR_DEFAULT_PEER_PORT_STR ) );
367    tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, FALSE );
368    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     49152 );
369    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    65535 );
370    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          atoi( TR_DEFAULT_PEER_SOCKET_TOS_STR ) );
371    tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED,              TRUE );
372    tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING,          TRUE );
373    tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION,            TR_PREALLOCATE_SPARSE );
374    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY,                    "" );
375    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       FALSE );
376    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_ENABLED,            FALSE );
377    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_PASSWORD,           "" );
378    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_PORT,               80 );
379    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_TYPE,               TR_PROXY_HTTP );
380    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_USERNAME,           "" );
381    tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO,                    2.0 );
382    tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED,            FALSE );
383    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        FALSE );
384    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS,         "0.0.0.0" );
385    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED,              TRUE );
386    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD,             "" );
387    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME,             "" );
388    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST,            TR_DEFAULT_RPC_WHITELIST );
389    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    TRUE );
390    tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT,                 atoi( TR_DEFAULT_RPC_PORT_STR ) );
391    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED,        FALSE );
392    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP,             50 ); /* half the regular */
393    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN,           50 ); /* half the regular */
394    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN,     540 ); /* 9am */
395    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED,   FALSE );
396    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END,       1020 ); /* 5pm */
397    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY,       TR_SCHED_ALL );
398    tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED,                   100 );
399    tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED,           FALSE );
400    tr_bencDictAddInt ( d, TR_PREFS_KEY_UMASK,                    022 );
401    tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 );
402    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4,        TR_DEFAULT_BIND_ADDRESS_IPV4 );
403    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6,        TR_DEFAULT_BIND_ADDRESS_IPV6 );
404}
405
406void
407tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
408{
409    assert( tr_bencIsDict( d ) );
410
411    tr_bencDictReserve( d, 30 );
412    tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        tr_blocklistIsEnabled( s ) );
413    tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED,              s->isDHTEnabled );
414    tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR,             s->downloadDir );
415    tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED,                   tr_sessionGetSpeedLimit( s, TR_DOWN ) );
416    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_DOWN ) );
417    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               s->encryptionMode );
418    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
419    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
420    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          s->openFileLimit );
421    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        tr_sessionGetPeerLimit( s ) );
422    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       s->peerLimitPerTorrent );
423    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT,                tr_sessionGetPeerPort( s ) );
424    tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, s->isPortRandom );
425    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     s->randomPortLow );
426    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    s->randomPortHigh );
427    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          s->peerSocketTOS );
428    tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED,              s->isPexEnabled );
429    tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING,          tr_sessionIsPortForwardingEnabled( s ) );
430    tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION,            s->preallocationMode );
431    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY,                    s->proxy );
432    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       s->isProxyAuthEnabled );
433    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_ENABLED,            s->isProxyEnabled );
434    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_PASSWORD,           s->proxyPassword );
435    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_PORT,               s->proxyPort );
436    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_TYPE,               s->proxyType );
437    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_USERNAME,           s->proxyUsername );
438    tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO,                    s->desiredRatio );
439    tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED,            s->isRatioLimited );
440    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        tr_sessionIsRPCPasswordEnabled( s ) );
441    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS,         tr_sessionGetRPCBindAddress( s ) );
442    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED,              tr_sessionIsRPCEnabled( s ) );
443    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD,             tr_sessionGetRPCPassword( s ) );
444    tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT,                 tr_sessionGetRPCPort( s ) );
445    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME,             tr_sessionGetRPCUsername( s ) );
446    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST,            tr_sessionGetRPCWhitelist( s ) );
447    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    tr_sessionGetRPCWhitelistEnabled( s ) );
448    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED,        tr_sessionUsesAltSpeed( s ) );
449    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP,             tr_sessionGetAltSpeed( s, TR_UP ) );
450    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN,           tr_sessionGetAltSpeed( s, TR_DOWN ) );
451    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN,     tr_sessionGetAltSpeedBegin( s ) );
452    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED,   tr_sessionUsesAltSpeedTime( s ) );
453    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END,       tr_sessionGetAltSpeedEnd( s ) );
454    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY,       tr_sessionGetAltSpeedDay( s ) );
455    tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED,                   tr_sessionGetSpeedLimit( s, TR_UP ) );
456    tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_UP ) );
457    tr_bencDictAddInt ( d, TR_PREFS_KEY_UMASK,                    s->umask );
458    tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
459    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4,        tr_ntop_non_ts( &s->public_ipv4->addr ) );
460    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6,        tr_ntop_non_ts( &s->public_ipv6->addr ) );
461}
462
463void
464tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName )
465{
466    char * filename;
467    tr_benc fileSettings;
468    tr_benc sessionDefaults;
469    tr_benc tmp;
470
471    assert( tr_bencIsDict( d ) );
472
473    /* initializing the defaults: caller may have passed in some app-level defaults.
474     * preserve those and use the session defaults to fill in any missing gaps. */
475    tr_bencInitDict( &sessionDefaults, 0 );
476    tr_sessionGetDefaultSettings( &sessionDefaults );
477    tr_bencMergeDicts( &sessionDefaults, d );
478    tmp = *d; *d = sessionDefaults; sessionDefaults = tmp;
479
480    /* if caller didn't specify a config dir, use the default */
481    if( !configDir || !*configDir )
482        configDir = tr_getDefaultConfigDir( appName );
483
484    /* file settings override the defaults */
485    filename = tr_buildPath( configDir, "settings.json", NULL );
486    if( !tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename ) ) {
487        tr_bencMergeDicts( d, &fileSettings );
488        tr_bencFree( &fileSettings );
489    }
490
491    /* cleanup */
492    tr_bencFree( &sessionDefaults );
493    tr_free( filename );
494}
495
496void
497tr_sessionSaveSettings( tr_session    * session,
498                        const char    * configDir,
499                        const tr_benc * clientSettings )
500{
501    tr_benc settings;
502    char * filename = tr_buildPath( configDir, "settings.json", NULL );
503
504    assert( tr_bencIsDict( clientSettings ) );
505
506    tr_bencInitDict( &settings, 0 );
507
508    /* the existing file settings are the fallback values */
509    {
510        tr_benc fileSettings;
511        if( !tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename ) )
512        {
513            tr_bencMergeDicts( &settings, &fileSettings );
514            tr_bencFree( &fileSettings );
515        }
516    }
517
518    /* the client's settings override the file settings */
519    tr_bencMergeDicts( &settings, clientSettings );
520
521    /* the session's true values override the file & client settings */
522    {
523        tr_benc sessionSettings;
524        tr_bencInitDict( &sessionSettings, 0 );
525        tr_sessionGetSettings( session, &sessionSettings );
526        tr_bencMergeDicts( &settings, &sessionSettings );
527        tr_bencFree( &sessionSettings );
528    }
529
530    /* save the result */
531    tr_bencToFile( &settings, TR_FMT_JSON, filename );
532    tr_inf( "Saved \"%s\"", filename );
533
534    /* cleanup */
535    tr_free( filename );
536    tr_bencFree( &settings );
537}
538
539/***
540****
541***/
542
543/**
544 * Periodically save the .resume files of any torrents whose
545 * status has recently changed.  This prevents loss of metadata
546 * in the case of a crash, unclean shutdown, clumsy user, etc.
547 */
548static void
549onSaveTimer( int foo UNUSED, short bar UNUSED, void * vsession )
550{
551    tr_torrent * tor = NULL;
552    tr_session * session = vsession;
553
554    while(( tor = tr_torrentNext( session, tor )))
555        tr_torrentSave( tor );
556
557    tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
558}
559
560/***
561****
562***/
563
564static void tr_sessionInitImpl( void * );
565static void onAltTimer( int, short, void* );
566static void setAltTimer( tr_session * session );
567
568struct init_data
569{
570    tr_session  * session;
571    const char  * configDir;
572    tr_bool       messageQueuingEnabled;
573    tr_benc     * clientSettings;
574};
575
576tr_session *
577tr_sessionInit( const char  * tag,
578                const char  * configDir,
579                tr_bool       messageQueuingEnabled,
580                tr_benc     * clientSettings )
581{
582    tr_session * session;
583    struct init_data data;
584
585    assert( tr_bencIsDict( clientSettings ) );
586
587    /* initialize the bare skeleton of the session object */
588    session = tr_new0( tr_session, 1 );
589    session->bandwidth = tr_bandwidthNew( session, NULL );
590    session->lock = tr_lockNew( );
591    session->tag = tr_strdup( tag );
592    session->magicNumber = SESSION_MAGIC_NUMBER;
593    tr_bencInitList( &session->removedTorrents, 0 );
594
595    /* start the libtransmission thread */
596    tr_netInit( ); /* must go before tr_eventInit */
597    tr_eventInit( session );
598    assert( session->events != NULL );
599
600    /* run the rest in the libtransmission thread */
601    session->isWaiting = TRUE;
602    data.session = session;
603    data.configDir = configDir;
604    data.messageQueuingEnabled = messageQueuingEnabled;
605    data.clientSettings = clientSettings;
606    tr_runInEventThread( session, tr_sessionInitImpl, &data );
607    while( session->isWaiting )
608        tr_wait( 100 );
609
610    return session;
611}
612
613static void useAltSpeed( tr_session * session, tr_bool enabled, tr_bool byUser );
614static void useAltSpeedTime( tr_session * session, tr_bool enabled, tr_bool byUser );
615
616static void
617tr_sessionInitImpl( void * vdata )
618{
619    int64_t i;
620    int64_t j;
621    double  d;
622    tr_bool found;
623    tr_bool boolVal;
624    const char * str;
625    tr_benc settings;
626    char * filename;
627    struct init_data * data = vdata;
628    tr_benc * clientSettings = data->clientSettings;
629    tr_session * session = data->session;
630
631    assert( tr_amInEventThread( session ) );
632    assert( tr_bencIsDict( clientSettings ) );
633
634    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth );
635
636    tr_bencInitDict( &settings, 0 );
637    tr_sessionGetDefaultSettings( &settings );
638    tr_bencMergeDicts( &settings, clientSettings );
639
640#ifndef WIN32
641    /* Don't exit when writing on a broken socket */
642    signal( SIGPIPE, SIG_IGN );
643#endif
644
645    /* set the session's file mode creation mask (umask) to session->umask & 0777 */
646    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UMASK, &i );
647    assert( found );
648    session->umask = (mode_t)i;
649    umask( session->umask );
650
651    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i );
652    assert( found );
653    session->peerLimitPerTorrent = i;
654
655    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i );
656    assert( found );
657    tr_setMessageLevel( i );
658    tr_setMessageQueuing( data->messageQueuingEnabled );
659
660
661    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal );
662    assert( found );
663    session->isPexEnabled = boolVal;
664
665    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_DHT_ENABLED, &boolVal );
666    assert( found );
667    session->isDHTEnabled = boolVal;
668
669    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i );
670    assert( found );
671    assert( tr_isEncryptionMode( i ) );
672    session->encryptionMode = i;
673
674    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i );
675    assert( found );
676    assert( tr_isPreallocationMode( i ) );
677    session->preallocationMode = i;
678
679    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i );
680    assert( found );
681    session->peerSocketTOS = i;
682
683    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str );
684    assert( found );
685    session->downloadDir = tr_strdup( str );
686
687    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_ENABLED, &boolVal );
688    assert( found );
689    session->isProxyEnabled = boolVal;
690
691    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str );
692    assert( found );
693    session->proxy = tr_strdup( str );
694
695    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i );
696    assert( found );
697    session->proxyPort = i;
698
699    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i );
700    assert( found );
701    session->proxyType = i;
702
703    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &boolVal );
704    assert( found );
705    session->isProxyAuthEnabled = boolVal;
706
707    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str );
708    assert( found );
709    session->proxyUsername = tr_strdup( str );
710
711    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str );
712    assert( found );
713    session->proxyPassword = tr_strdup( str );
714
715    session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */
716    session->so_rcvbuf = 8192;
717
718    tr_setConfigDir( session, data->configDir );
719
720    tr_trackerSessionInit( session );
721    assert( session->tracker != NULL );
722
723    session->peerMgr = tr_peerMgrNew( session );
724
725    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal );
726    assert( found );
727    session->useLazyBitfield = boolVal;
728
729    /* Initialize rate and file descripts controls */
730
731    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i );
732    assert( found );
733    session->openFileLimit = i;
734    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j );
735    assert( found );
736    tr_fdInit( session->openFileLimit, j );
737
738    /**
739    *** random port
740    **/
741
742    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, &boolVal );
743    assert( found );
744    session->isPortRandom = boolVal;
745
746    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i );
747    assert( found );
748    session->randomPortLow = i;
749
750    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i );
751    assert( found );
752    session->randomPortHigh = i;
753
754    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, &boolVal )
755         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j );
756    assert( found );
757    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
758
759    /* public addresses */
760
761    {
762        struct tr_bindinfo b;
763        const char * str;
764
765        str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
766        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
767        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET ) )
768            b.addr = tr_inaddr_any;
769        b.socket = -1;
770        session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
771
772        str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
773        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
774        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET6 ) )
775            b.addr = tr_in6addr_any;
776        b.socket = -1;
777        session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
778
779        open_incoming_peer_port( session );
780    }
781
782    session->shared = tr_sharedInit( session, boolVal );
783
784    /**
785    **/
786
787    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i );
788    assert( found );
789    session->uploadSlotsPerTorrent = i;
790
791    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i )
792         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_USPEED_ENABLED, &boolVal );
793    assert( found );
794    tr_sessionSetSpeedLimit( session, TR_UP, i );
795    tr_sessionLimitSpeed( session, TR_UP, boolVal );
796
797    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i )
798         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &boolVal );
799    assert( found );
800    tr_sessionSetSpeedLimit( session, TR_DOWN, i );
801    tr_sessionLimitSpeed( session, TR_DOWN, boolVal );
802
803    found = tr_bencDictFindReal( &settings, TR_PREFS_KEY_RATIO, &d )
804         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, &boolVal );
805    assert( found );
806    tr_sessionSetRatioLimit( session, d );
807    tr_sessionSetRatioLimited( session, boolVal );
808
809    /**
810    ***  Alternate speed limits
811    **/
812
813    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_UP, &i );
814    assert( found );
815    session->altSpeed[TR_UP] = i;
816
817    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_DOWN, &i );
818    assert( found );
819    session->altSpeed[TR_DOWN] = i;
820
821    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, &i );
822    assert( found );
823    session->altSpeedTimeBegin = i;
824
825    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_END, &i );
826    assert( found );
827    session->altSpeedTimeEnd = i;
828
829    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, &i );
830    assert( found );
831    session->altSpeedTimeDay = i;
832
833    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, &boolVal );
834    assert( found );
835    useAltSpeedTime( session, boolVal, FALSE );
836
837    if( !boolVal )
838    {
839        found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_ENABLED, &boolVal );
840        assert( found );
841        useAltSpeed( session, boolVal, FALSE );
842    }
843    else
844        useAltSpeed( session, isAltTime( session ), FALSE );
845
846    /**
847    ***  Blocklist
848    **/
849
850    filename = tr_buildPath( session->configDir, "blocklists", NULL );
851    tr_mkdirp( filename, 0777 );
852    tr_free( filename );
853    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal );
854    assert( found );
855    session->isBlocklistEnabled = boolVal;
856    loadBlocklists( session );
857
858    session->rpcServer = tr_rpcInit( session, &settings );
859
860    tr_bencFree( &settings );
861
862    assert( tr_isSession( session ) );
863
864    session->altTimer = tr_new0( struct event, 1 );
865    evtimer_set( session->altTimer, onAltTimer, session );
866    setAltTimer( session );
867
868    session->saveTimer = tr_new0( struct event, 1 );
869    evtimer_set( session->saveTimer, onSaveTimer, session );
870    tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
871
872    /* first %s is the application name
873       second %s is the version number */
874    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
875
876    tr_statsInit( session );
877    session->web = tr_webInit( session );
878    session->isWaiting = FALSE;
879    dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker );
880
881    if( session->isDHTEnabled )
882    {
883#ifdef WITHOUT_DHT
884        tr_inf( "DHT disabled by packager." );
885#else
886        tr_dhtInit( session, &session->public_ipv4->addr );
887#endif
888    }
889}
890
891/***
892****
893***/
894
895void
896tr_sessionSetDownloadDir( tr_session * session, const char * dir )
897{
898    assert( tr_isSession( session ) );
899
900    if( session->downloadDir != dir )
901    {
902        tr_free( session->downloadDir );
903        session->downloadDir = tr_strdup( dir );
904    }
905}
906
907const char *
908tr_sessionGetDownloadDir( const tr_session * session )
909{
910    assert( tr_isSession( session ) );
911
912    return session->downloadDir;
913}
914
915/***
916****
917***/
918
919void
920tr_globalLock( tr_session * session )
921{
922    assert( tr_isSession( session ) );
923
924    tr_lockLock( session->lock );
925}
926
927void
928tr_globalUnlock( tr_session * session )
929{
930    assert( tr_isSession( session ) );
931
932    tr_lockUnlock( session->lock );
933}
934
935tr_bool
936tr_globalIsLocked( const tr_session * session )
937{
938    return tr_isSession( session ) && tr_lockHave( session->lock );
939}
940
941/***********************************************************************
942 * tr_setBindPort
943 ***********************************************************************
944 *
945 **********************************************************************/
946
947static void
948setPeerPort( void * session )
949{
950    tr_torrent * tor = NULL;
951
952    assert( tr_isSession( session ) );
953
954    close_incoming_peer_port( session );
955    open_incoming_peer_port( session );
956    tr_sharedPortChanged( session );
957
958    while(( tor = tr_torrentNext( session, tor )))
959        tr_torrentChangeMyPort( tor );
960}
961
962void
963tr_sessionSetPeerPort( tr_session * session,
964                       tr_port      port )
965{
966    assert( tr_isSession( session ) );
967
968    session->peerPort = port;
969
970    tr_runInEventThread( session, setPeerPort, session );
971}
972
973tr_port
974tr_sessionGetPeerPort( const tr_session * session )
975{
976    assert( tr_isSession( session ) );
977
978    return session->peerPort;
979}
980
981tr_port
982tr_sessionSetPeerPortRandom( tr_session * session )
983{
984    assert( tr_isSession( session ) );
985
986    tr_sessionSetPeerPort( session, getRandomPort( session ) );
987    return session->peerPort;
988}
989
990void
991tr_sessionSetPeerPortRandomOnStart( tr_session * session,
992                                    tr_bool random )
993{
994    assert( tr_isSession( session ) );
995
996    session->isPortRandom = random;
997}
998
999tr_bool
1000tr_sessionGetPeerPortRandomOnStart( tr_session * session )
1001{
1002    assert( tr_isSession( session ) );
1003
1004    return session->isPortRandom;
1005}
1006
1007tr_port_forwarding
1008tr_sessionGetPortForwarding( const tr_session * session )
1009{
1010    assert( tr_isSession( session ) );
1011
1012    return tr_sharedTraversalStatus( session->shared );
1013}
1014
1015/***
1016****
1017***/
1018
1019static void
1020updateSeedRatio( tr_session * session )
1021{
1022    tr_torrent * tor = NULL;
1023
1024    while(( tor = tr_torrentNext( session, tor )))
1025        tor->needsSeedRatioCheck = TRUE;
1026}
1027
1028void
1029tr_sessionSetRatioLimited( tr_session * session, tr_bool isLimited )
1030{
1031    assert( tr_isSession( session ) );
1032
1033    session->isRatioLimited = isLimited;
1034    updateSeedRatio( session );
1035}
1036
1037void
1038tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
1039{
1040    assert( tr_isSession( session ) );
1041
1042    session->desiredRatio = desiredRatio;
1043    updateSeedRatio( session );
1044}
1045
1046tr_bool
1047tr_sessionIsRatioLimited( const tr_session  * session )
1048{
1049    assert( tr_isSession( session ) );
1050
1051    return session->isRatioLimited;
1052}
1053
1054double
1055tr_sessionGetRatioLimit( const tr_session * session )
1056{
1057    assert( tr_isSession( session ) );
1058
1059    return session->desiredRatio;
1060}
1061
1062/***
1063****  SPEED LIMITS
1064***/
1065
1066tr_bool
1067tr_sessionGetActiveSpeedLimit( const tr_session * session, tr_direction dir, int * setme )
1068{
1069    int isLimited = TRUE;
1070
1071    if( !tr_isSession( session ) )
1072        return FALSE;
1073
1074    if( tr_sessionUsesAltSpeed( session ) )
1075        *setme = tr_sessionGetAltSpeed( session, dir );
1076    else if( tr_sessionIsSpeedLimited( session, dir ) )
1077        *setme = tr_sessionGetSpeedLimit( session, dir );
1078    else
1079        isLimited = FALSE;
1080
1081    return isLimited;
1082}
1083
1084static void
1085updateBandwidth( tr_session * session, tr_direction dir )
1086{
1087    int limit = 0;
1088    const tr_bool isLimited = tr_sessionGetActiveSpeedLimit( session, dir, &limit );
1089    const tr_bool zeroCase = isLimited && !limit;
1090
1091    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited && !zeroCase );
1092
1093    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, limit );
1094}
1095
1096static void
1097altSpeedToggled( void * vsession )
1098{
1099    tr_session * session = vsession;
1100
1101    assert( tr_isSession( session ) );
1102
1103    updateBandwidth( session, TR_UP );
1104    updateBandwidth( session, TR_DOWN );
1105
1106    if( session->altCallback != NULL )
1107        (*session->altCallback)( session, session->altSpeedEnabled, session->altSpeedChangedByUser, session->altCallbackUserData );
1108}
1109
1110/* tell the alt speed limit timer to fire again at the top of the minute */
1111static void
1112setAltTimer( tr_session * session )
1113{
1114    const time_t now = time( NULL );
1115    struct tm tm;
1116
1117    assert( tr_isSession( session ) );
1118    assert( session->altTimer != NULL );
1119
1120    tr_localtime_r( &now, &tm );
1121    tr_timerAdd( session->altTimer, 60-tm.tm_sec, 0 );
1122}
1123
1124/* this is called once a minute to:
1125 * (1) update session->isAltTime
1126 * (2) alter the speed limits when the alt limits go on and off */
1127static void
1128onAltTimer( int foo UNUSED, short bar UNUSED, void * vsession )
1129{
1130    tr_session * session = vsession;
1131
1132    assert( tr_isSession( session ) );
1133
1134    if( session->altSpeedTimeEnabled )
1135    {
1136        const time_t now = time( NULL );
1137        struct tm tm;
1138        int currentMinute, day;
1139        tr_bool isBeginTime, isEndTime, isDay;
1140        tr_localtime_r( &now, &tm );
1141        currentMinute = tm.tm_hour*60 + tm.tm_min;
1142        day = tm.tm_wday;
1143
1144        isBeginTime = currentMinute == session->altSpeedTimeBegin;
1145        isEndTime = currentMinute == session->altSpeedTimeEnd;
1146        if( isBeginTime || isEndTime )
1147        {
1148            /* if looking at the end date, look at the next day if end time is before begin time */
1149            if( isEndTime && !isBeginTime && session->altSpeedTimeEnd < session->altSpeedTimeBegin )
1150                day = (day - 1) % 7;
1151
1152            isDay = ((1<<day) & session->altSpeedTimeDay) != 0;
1153
1154            if( isDay )
1155                useAltSpeed( session, isBeginTime, FALSE );
1156        }
1157    }
1158
1159    setAltTimer( session );
1160}
1161
1162/***
1163****  Primary session speed limits
1164***/
1165
1166void
1167tr_sessionSetSpeedLimit( tr_session * s, tr_direction d, int KB_s )
1168{
1169    assert( tr_isSession( s ) );
1170    assert( tr_isDirection( d ) );
1171    assert( KB_s >= 0 );
1172
1173    s->speedLimit[d] = KB_s;
1174
1175    updateBandwidth( s, d );
1176}
1177
1178int
1179tr_sessionGetSpeedLimit( const tr_session * s, tr_direction d )
1180{
1181    assert( tr_isSession( s ) );
1182    assert( tr_isDirection( d ) );
1183
1184    return s->speedLimit[d];
1185}
1186
1187void
1188tr_sessionLimitSpeed( tr_session * s, tr_direction d, tr_bool b )
1189{
1190    assert( tr_isSession( s ) );
1191    assert( tr_isDirection( d ) );
1192    assert( tr_isBool( b ) );
1193
1194    s->speedLimitEnabled[d] = b;
1195
1196    updateBandwidth( s, d );
1197}
1198
1199tr_bool
1200tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1201{
1202    assert( tr_isSession( s ) );
1203    assert( tr_isDirection( d ) );
1204
1205    return s->speedLimitEnabled[d];
1206}
1207
1208/***
1209****  Alternative speed limits that are used during scheduled times
1210***/
1211
1212void
1213tr_sessionSetAltSpeed( tr_session * s, tr_direction d, int KB_s )
1214{
1215    assert( tr_isSession( s ) );
1216    assert( tr_isDirection( d ) );
1217    assert( KB_s >= 0 );
1218
1219    s->altSpeed[d] = KB_s;
1220
1221    updateBandwidth( s, d );
1222}
1223
1224int
1225tr_sessionGetAltSpeed( const tr_session * s, tr_direction d )
1226{
1227    assert( tr_isSession( s ) );
1228    assert( tr_isDirection( d ) );
1229
1230    return s->altSpeed[d];
1231}
1232
1233void
1234useAltSpeedTime( tr_session * session, tr_bool enabled, tr_bool byUser )
1235{
1236    assert( tr_isSession( session ) );
1237    assert( tr_isBool( enabled ) );
1238    assert( tr_isBool( byUser ) );
1239
1240    if( session->altSpeedTimeEnabled != enabled )
1241    {
1242        const tr_bool isAlt = isAltTime( session );
1243
1244        session->altSpeedTimeEnabled = enabled;
1245
1246        if( enabled && session->altSpeedEnabled != isAlt )
1247            useAltSpeed( session, isAlt, byUser );
1248    }
1249}
1250void
1251tr_sessionUseAltSpeedTime( tr_session * s, tr_bool b )
1252{
1253    useAltSpeedTime( s, b, TRUE );
1254}
1255
1256tr_bool
1257tr_sessionUsesAltSpeedTime( const tr_session * s )
1258{
1259    assert( tr_isSession( s ) );
1260
1261    return s->altSpeedTimeEnabled;
1262}
1263
1264void
1265tr_sessionSetAltSpeedBegin( tr_session * s, int minutes )
1266{
1267    assert( tr_isSession( s ) );
1268    assert( 0<=minutes && minutes<(60*24) );
1269
1270    if( s->altSpeedTimeBegin != minutes )
1271    {
1272        s->altSpeedTimeBegin = minutes;
1273
1274        if( tr_sessionUsesAltSpeedTime( s ) )
1275            useAltSpeed( s, isAltTime( s ), TRUE );
1276    }
1277}
1278
1279int
1280tr_sessionGetAltSpeedBegin( const tr_session * s )
1281{
1282    assert( tr_isSession( s ) );
1283
1284    return s->altSpeedTimeBegin;
1285}
1286
1287void
1288tr_sessionSetAltSpeedEnd( tr_session * s, int minutes )
1289{
1290    assert( tr_isSession( s ) );
1291    assert( 0<=minutes && minutes<(60*24) );
1292
1293    if( s->altSpeedTimeEnd != minutes )
1294    {
1295        s->altSpeedTimeEnd = minutes;
1296
1297        if( tr_sessionUsesAltSpeedTime( s ) )
1298            useAltSpeed( s, isAltTime( s ), TRUE );
1299    }
1300}
1301
1302int
1303tr_sessionGetAltSpeedEnd( const tr_session * s )
1304{
1305    assert( tr_isSession( s ) );
1306
1307    return s->altSpeedTimeEnd;
1308}
1309
1310void
1311tr_sessionSetAltSpeedDay( tr_session * s, tr_sched_day day )
1312{
1313    assert( tr_isSession( s ) );
1314
1315    if( s->altSpeedTimeDay != day )
1316    {
1317        s->altSpeedTimeDay = day;
1318
1319        if( tr_sessionUsesAltSpeedTime( s ) )
1320            useAltSpeed( s, isAltTime( s ), TRUE );
1321    }
1322}
1323
1324tr_sched_day
1325tr_sessionGetAltSpeedDay( const tr_session * s )
1326{
1327    assert( tr_isSession( s ) );
1328
1329    return s->altSpeedTimeDay;
1330}
1331
1332void
1333useAltSpeed( tr_session * s, tr_bool enabled, tr_bool byUser )
1334{
1335    assert( tr_isSession( s ) );
1336    assert( tr_isBool( enabled ) );
1337    assert( tr_isBool( byUser ) );
1338
1339    if( s->altSpeedEnabled != enabled)
1340    {
1341        s->altSpeedEnabled = enabled;
1342        s->altSpeedChangedByUser = byUser;
1343
1344        tr_runInEventThread( s, altSpeedToggled, s );
1345    }
1346}
1347void
1348tr_sessionUseAltSpeed( tr_session * session, tr_bool enabled )
1349{
1350    useAltSpeed( session, enabled, TRUE );
1351}
1352
1353tr_bool
1354tr_sessionUsesAltSpeed( const tr_session * s )
1355{
1356    assert( tr_isSession( s ) );
1357
1358    return s->altSpeedEnabled;
1359}
1360
1361void
1362tr_sessionSetAltSpeedFunc( tr_session       * session,
1363                           tr_altSpeedFunc    func,
1364                           void             * userData )
1365{
1366    assert( tr_isSession( session ) );
1367
1368    session->altCallback = func;
1369    session->altCallbackUserData = userData;
1370}
1371
1372void
1373tr_sessionClearAltSpeedFunc( tr_session * session )
1374{
1375    tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1376}
1377
1378/***
1379****
1380***/
1381
1382void
1383tr_sessionSetPeerLimit( tr_session * session, uint16_t maxGlobalPeers )
1384{
1385    assert( tr_isSession( session ) );
1386
1387    tr_fdSetPeerLimit( maxGlobalPeers );
1388}
1389
1390uint16_t
1391tr_sessionGetPeerLimit( const tr_session * session )
1392{
1393    assert( tr_isSession( session ) );
1394
1395    return tr_fdGetPeerLimit( );
1396}
1397
1398void
1399tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
1400{
1401    assert( tr_isSession( session ) );
1402
1403    session->peerLimitPerTorrent = n;
1404}
1405
1406uint16_t
1407tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1408{
1409    assert( tr_isSession( session ) );
1410
1411    return session->peerLimitPerTorrent;
1412}
1413
1414/***
1415****
1416***/
1417
1418double
1419tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
1420{
1421    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1422}
1423
1424double
1425tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
1426{
1427    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1428}
1429
1430int
1431tr_sessionCountTorrents( const tr_session * session )
1432{
1433    return tr_isSession( session ) ? session->torrentCount : 0;
1434}
1435
1436static int
1437compareTorrentByCur( const void * va, const void * vb )
1438{
1439    const tr_torrent * a = *(const tr_torrent**)va;
1440    const tr_torrent * b = *(const tr_torrent**)vb;
1441    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1442    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1443
1444    if( aCur != bCur )
1445        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1446
1447    return 0;
1448}
1449
1450static void
1451sessionCloseImpl( void * vsession )
1452{
1453    tr_session *  session = vsession;
1454    tr_torrent *  tor;
1455    int           i, n;
1456    tr_torrent ** torrents;
1457
1458    assert( tr_isSession( session ) );
1459
1460    free_incoming_peer_port( session );
1461
1462    if( session->isDHTEnabled )
1463        tr_dhtUninit( session );
1464
1465    evtimer_del( session->saveTimer );
1466    tr_free( session->saveTimer );
1467    session->saveTimer = NULL;
1468
1469    evtimer_del( session->altTimer );
1470    tr_free( session->altTimer );
1471    session->altTimer = NULL;
1472
1473    tr_verifyClose( session );
1474    tr_statsClose( session );
1475    tr_sharedClose( session );
1476    tr_rpcClose( &session->rpcServer );
1477
1478    /* close the torrents.  get the most active ones first so that
1479     * if we can't get them all closed in a reasonable amount of time,
1480     * at least we get the most important ones first. */
1481    tor = NULL;
1482    n = session->torrentCount;
1483    torrents = tr_new( tr_torrent *, session->torrentCount );
1484    for( i = 0; i < n; ++i )
1485        torrents[i] = tor = tr_torrentNext( session, tor );
1486    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1487    for( i = 0; i < n; ++i )
1488        tr_torrentFree( torrents[i] );
1489    tr_free( torrents );
1490
1491    tr_peerMgrFree( session->peerMgr );
1492
1493    tr_trackerSessionClose( session );
1494    tr_list_free( &session->blocklists,
1495                  (TrListForeachFunc)_tr_blocklistFree );
1496    tr_webClose( &session->web );
1497
1498    session->isClosed = TRUE;
1499}
1500
1501static int
1502deadlineReached( const uint64_t deadline )
1503{
1504    return tr_date( ) >= deadline;
1505}
1506
1507#define SHUTDOWN_MAX_SECONDS 30
1508
1509void
1510tr_sessionClose( tr_session * session )
1511{
1512    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
1513    const uint64_t deadline = tr_date( ) + maxwait_msec;
1514
1515    assert( tr_isSession( session ) );
1516
1517    dbgmsg( "shutting down transmission session %p", session );
1518
1519    /* close the session */
1520    tr_runInEventThread( session, sessionCloseImpl, session );
1521    while( !session->isClosed && !deadlineReached( deadline ) )
1522    {
1523        dbgmsg(
1524            "waiting for the shutdown commands to run in the main thread" );
1525        tr_wait( 100 );
1526    }
1527
1528    /* "shared" and "tracker" have live sockets,
1529     * so we need to keep the transmission thread alive
1530     * for a bit while they tell the router & tracker
1531     * that we're closing now */
1532    while( ( session->shared
1533           || session->tracker ) && !deadlineReached( deadline ) )
1534    {
1535        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
1536                session->shared, session->tracker );
1537        tr_wait( 100 );
1538    }
1539
1540    tr_fdClose( );
1541
1542    /* close the libtransmission thread */
1543    tr_eventClose( session );
1544    while( session->events && !deadlineReached( deadline ) )
1545    {
1546        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
1547        tr_wait( 100 );
1548    }
1549
1550    /* free the session memory */
1551    tr_bencFree( &session->removedTorrents );
1552    tr_bandwidthFree( session->bandwidth );
1553    tr_lockFree( session->lock );
1554    if( session->metainfoLookup ) {
1555        tr_bencFree( session->metainfoLookup );
1556        tr_free( session->metainfoLookup );
1557    }
1558    tr_free( session->tag );
1559    tr_free( session->configDir );
1560    tr_free( session->resumeDir );
1561    tr_free( session->torrentDir );
1562    tr_free( session->downloadDir );
1563    tr_free( session->proxy );
1564    tr_free( session->proxyUsername );
1565    tr_free( session->proxyPassword );
1566    tr_free( session );
1567}
1568
1569tr_torrent **
1570tr_sessionLoadTorrents( tr_session * session,
1571                        tr_ctor    * ctor,
1572                        int        * setmeCount )
1573{
1574    int           i, n = 0;
1575    struct stat   sb;
1576    DIR *         odir = NULL;
1577    const char *  dirname = tr_getTorrentDir( session );
1578    tr_torrent ** torrents;
1579    tr_list *     l = NULL, *list = NULL;
1580
1581    assert( tr_isSession( session ) );
1582
1583    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1584
1585    if( !stat( dirname, &sb )
1586      && S_ISDIR( sb.st_mode )
1587      && ( ( odir = opendir ( dirname ) ) ) )
1588    {
1589        struct dirent *d;
1590        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1591        {
1592            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1593                                                     */
1594            {
1595                tr_torrent * tor;
1596                char * path = tr_buildPath( dirname, d->d_name, NULL );
1597                tr_ctorSetMetainfoFromFile( ctor, path );
1598                if(( tor = tr_torrentNew( ctor, NULL )))
1599                {
1600                    tr_list_append( &list, tor );
1601                    ++n;
1602                }
1603                tr_free( path );
1604            }
1605        }
1606        closedir( odir );
1607    }
1608
1609    torrents = tr_new( tr_torrent *, n );
1610    for( i = 0, l = list; l != NULL; l = l->next )
1611        torrents[i++] = (tr_torrent*) l->data;
1612    assert( i == n );
1613
1614    tr_list_free( &list, NULL );
1615
1616    if( n )
1617        tr_inf( _( "Loaded %d torrents" ), n );
1618
1619    if( setmeCount )
1620        *setmeCount = n;
1621    return torrents;
1622}
1623
1624/***
1625****
1626***/
1627
1628void
1629tr_sessionSetPexEnabled( tr_session * session,
1630                         tr_bool      enabled )
1631{
1632    assert( tr_isSession( session ) );
1633
1634    session->isPexEnabled = enabled != 0;
1635}
1636
1637tr_bool
1638tr_sessionIsPexEnabled( const tr_session * session )
1639{
1640    assert( tr_isSession( session ) );
1641
1642    return session->isPexEnabled;
1643}
1644
1645tr_bool
1646tr_sessionAllowsDHT( const tr_session * session UNUSED )
1647{
1648#ifdef WITHOUT_DHT
1649    return 0;
1650#else
1651    return tr_sessionIsDHTEnabled( session );
1652#endif
1653}
1654
1655tr_bool
1656tr_sessionIsDHTEnabled( const tr_session * session )
1657{
1658    assert( tr_isSession( session ) );
1659
1660    return session->isDHTEnabled;
1661}
1662
1663static void
1664toggleDHTImpl(  void * data )
1665{
1666    tr_session * session = data;
1667    assert( tr_isSession( session ) );
1668
1669    if( session->isDHTEnabled )
1670        tr_dhtUninit( session );
1671
1672    session->isDHTEnabled = !session->isDHTEnabled;
1673
1674    if( session->isDHTEnabled )
1675        tr_dhtInit( session, &session->public_ipv4->addr );
1676}
1677
1678void
1679tr_sessionSetDHTEnabled( tr_session * session, tr_bool enabled )
1680{
1681    assert( tr_isSession( session ) );
1682    assert( tr_isBool( enabled ) );
1683
1684    if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1685        tr_runInEventThread( session, toggleDHTImpl, session );
1686}
1687
1688/***
1689****
1690***/
1691
1692void
1693tr_sessionSetLazyBitfieldEnabled( tr_session * session,
1694                                  tr_bool      enabled )
1695{
1696    assert( tr_isSession( session ) );
1697
1698    session->useLazyBitfield = enabled != 0;
1699}
1700
1701tr_bool
1702tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
1703{
1704    assert( tr_isSession( session ) );
1705
1706    return session->useLazyBitfield;
1707}
1708
1709/***
1710****
1711***/
1712
1713void
1714tr_sessionSetPortForwardingEnabled( tr_session  * session,
1715                                    tr_bool       enabled )
1716{
1717    assert( tr_isSession( session ) );
1718
1719    tr_globalLock( session );
1720    tr_sharedTraversalEnable( session->shared, enabled );
1721    tr_globalUnlock( session );
1722}
1723
1724tr_bool
1725tr_sessionIsPortForwardingEnabled( const tr_session * session )
1726{
1727    assert( tr_isSession( session ) );
1728
1729    return tr_sharedTraversalIsEnabled( session->shared );
1730}
1731
1732/***
1733****
1734***/
1735
1736int
1737tr_blocklistGetRuleCount( const tr_session * session )
1738{
1739    int       n = 0;
1740    tr_list * l;
1741
1742    assert( tr_isSession( session ) );
1743
1744    for( l = session->blocklists; l; l = l->next )
1745        n += _tr_blocklistGetRuleCount( l->data );
1746    return n;
1747}
1748
1749tr_bool
1750tr_blocklistIsEnabled( const tr_session * session )
1751{
1752    assert( tr_isSession( session ) );
1753
1754    return session->isBlocklistEnabled;
1755}
1756
1757void
1758tr_blocklistSetEnabled( tr_session * session,
1759                        tr_bool      isEnabled )
1760{
1761    tr_list * l;
1762
1763    assert( tr_isSession( session ) );
1764
1765    session->isBlocklistEnabled = isEnabled != 0;
1766
1767    for( l=session->blocklists; l!=NULL; l=l->next )
1768        _tr_blocklistSetEnabled( l->data, isEnabled );
1769}
1770
1771tr_bool
1772tr_blocklistExists( const tr_session * session )
1773{
1774    assert( tr_isSession( session ) );
1775
1776    return session->blocklists != NULL;
1777}
1778
1779int
1780tr_blocklistSetContent( tr_session * session,
1781                        const char * contentFilename )
1782{
1783    tr_list *      l;
1784    tr_blocklist * b;
1785    const char *   defaultName = "level1.bin";
1786
1787    assert( tr_isSession( session ) );
1788
1789    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
1790        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
1791                               defaultName ) )
1792            b = l->data;
1793
1794    if( !b )
1795    {
1796        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
1797        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
1798        tr_list_append( &session->blocklists, b );
1799        tr_free( path );
1800    }
1801
1802    return _tr_blocklistSetContent( b, contentFilename );
1803}
1804
1805tr_bool
1806tr_sessionIsAddressBlocked( const tr_session * session,
1807                            const tr_address * addr )
1808{
1809    tr_list * l;
1810
1811    assert( tr_isSession( session ) );
1812
1813    for( l = session->blocklists; l; l = l->next )
1814        if( _tr_blocklistHasAddress( l->data, addr ) )
1815            return TRUE;
1816    return FALSE;
1817}
1818
1819/***
1820****
1821***/
1822
1823static void
1824metainfoLookupInit( tr_session * session )
1825{
1826    struct stat  sb;
1827    const char * dirname = tr_getTorrentDir( session );
1828    DIR *        odir = NULL;
1829    tr_ctor *    ctor = NULL;
1830    tr_benc * lookup;
1831    int n = 0;
1832
1833    assert( tr_isSession( session ) );
1834
1835    /* walk through the directory and find the mappings */
1836    lookup = tr_new0( tr_benc, 1 );
1837    tr_bencInitDict( lookup, 0 );
1838    ctor = tr_ctorNew( session );
1839    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1840    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
1841    {
1842        struct dirent *d;
1843        while(( d = readdir( odir )))
1844        {
1845            if( d->d_name && d->d_name[0] != '.' )
1846            {
1847                tr_info inf;
1848                char * path = tr_buildPath( dirname, d->d_name, NULL );
1849                tr_ctorSetMetainfoFromFile( ctor, path );
1850                if( !tr_torrentParse( ctor, &inf ) )
1851                {
1852                    ++n;
1853                    tr_bencDictAddStr( lookup, inf.hashString, path );
1854                }
1855                tr_free( path );
1856            }
1857        }
1858        closedir( odir );
1859    }
1860    tr_ctorFree( ctor );
1861
1862    session->metainfoLookup = lookup;
1863    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
1864}
1865
1866const char*
1867tr_sessionFindTorrentFile( const tr_session * session,
1868                           const char       * hashString )
1869{
1870    const char * filename = NULL;
1871    if( !session->metainfoLookup )
1872        metainfoLookupInit( (tr_session*)session );
1873    tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
1874    return filename;
1875}
1876
1877void
1878tr_sessionSetTorrentFile( tr_session * session,
1879                          const char * hashString,
1880                          const char * filename )
1881{
1882    /* since we walk session->configDir/torrents/ to build the lookup table,
1883     * and tr_sessionSetTorrentFile() is just to tell us there's a new file
1884     * in that same directory, we don't need to do anything here if the
1885     * lookup table hasn't been built yet */
1886    if( session->metainfoLookup )
1887        tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
1888}
1889
1890tr_torrent*
1891tr_torrentNext( tr_session * session,
1892                tr_torrent * tor )
1893{
1894    assert( tr_isSession( session ) );
1895
1896    return tor ? tor->next : session->torrentList;
1897}
1898
1899/***
1900****
1901***/
1902
1903void
1904tr_sessionSetRPCEnabled( tr_session * session,
1905                         tr_bool      isEnabled )
1906{
1907    assert( tr_isSession( session ) );
1908
1909    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1910}
1911
1912tr_bool
1913tr_sessionIsRPCEnabled( const tr_session * session )
1914{
1915    assert( tr_isSession( session ) );
1916
1917    return tr_rpcIsEnabled( session->rpcServer );
1918}
1919
1920void
1921tr_sessionSetRPCPort( tr_session * session,
1922                      tr_port      port )
1923{
1924    assert( tr_isSession( session ) );
1925
1926    tr_rpcSetPort( session->rpcServer, port );
1927}
1928
1929tr_port
1930tr_sessionGetRPCPort( const tr_session * session )
1931{
1932    assert( tr_isSession( session ) );
1933
1934    return tr_rpcGetPort( session->rpcServer );
1935}
1936
1937void
1938tr_sessionSetRPCCallback( tr_session * session,
1939                          tr_rpc_func  func,
1940                          void *       user_data )
1941{
1942    assert( tr_isSession( session ) );
1943
1944    session->rpc_func = func;
1945    session->rpc_func_user_data = user_data;
1946}
1947
1948void
1949tr_sessionSetRPCWhitelist( tr_session * session,
1950                           const char * whitelist )
1951{
1952    assert( tr_isSession( session ) );
1953
1954    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1955}
1956
1957const char*
1958tr_sessionGetRPCWhitelist( const tr_session * session )
1959{
1960    assert( tr_isSession( session ) );
1961
1962    return tr_rpcGetWhitelist( session->rpcServer );
1963}
1964
1965void
1966tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1967                                  tr_bool      isEnabled )
1968{
1969    assert( tr_isSession( session ) );
1970
1971    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1972}
1973
1974tr_bool
1975tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1976{
1977    assert( tr_isSession( session ) );
1978
1979    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1980}
1981
1982
1983void
1984tr_sessionSetRPCPassword( tr_session * session,
1985                          const char * password )
1986{
1987    assert( tr_isSession( session ) );
1988
1989    tr_rpcSetPassword( session->rpcServer, password );
1990}
1991
1992const char*
1993tr_sessionGetRPCPassword( const tr_session * session )
1994{
1995    assert( tr_isSession( session ) );
1996
1997    return tr_rpcGetPassword( session->rpcServer );
1998}
1999
2000void
2001tr_sessionSetRPCUsername( tr_session * session,
2002                          const char * username )
2003{
2004    assert( tr_isSession( session ) );
2005
2006    tr_rpcSetUsername( session->rpcServer, username );
2007}
2008
2009const char*
2010tr_sessionGetRPCUsername( const tr_session * session )
2011{
2012    assert( tr_isSession( session ) );
2013
2014    return tr_rpcGetUsername( session->rpcServer );
2015}
2016
2017void
2018tr_sessionSetRPCPasswordEnabled( tr_session * session,
2019                                 tr_bool      isEnabled )
2020{
2021    assert( tr_isSession( session ) );
2022
2023    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2024}
2025
2026tr_bool
2027tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2028{
2029    assert( tr_isSession( session ) );
2030
2031    return tr_rpcIsPasswordEnabled( session->rpcServer );
2032}
2033
2034const char *
2035tr_sessionGetRPCBindAddress( const tr_session * session )
2036{
2037    assert( tr_isSession( session ) );
2038
2039    return tr_rpcGetBindAddress( session->rpcServer );
2040}
2041
2042/***
2043****
2044***/
2045
2046tr_bool
2047tr_sessionIsProxyEnabled( const tr_session * session )
2048{
2049    assert( tr_isSession( session ) );
2050
2051    return session->isProxyEnabled;
2052}
2053
2054void
2055tr_sessionSetProxyEnabled( tr_session * session,
2056                           tr_bool      isEnabled )
2057{
2058    assert( tr_isSession( session ) );
2059
2060    session->isProxyEnabled = isEnabled != 0;
2061}
2062
2063tr_proxy_type
2064tr_sessionGetProxyType( const tr_session * session )
2065{
2066    assert( tr_isSession( session ) );
2067
2068    return session->proxyType;
2069}
2070
2071void
2072tr_sessionSetProxyType( tr_session *  session,
2073                        tr_proxy_type type )
2074{
2075    assert( tr_isSession( session ) );
2076
2077    session->proxyType = type;
2078}
2079
2080const char*
2081tr_sessionGetProxy( const tr_session * session )
2082{
2083    assert( tr_isSession( session ) );
2084
2085    return session->proxy;
2086}
2087
2088tr_port
2089tr_sessionGetProxyPort( const tr_session * session )
2090{
2091    assert( tr_isSession( session ) );
2092
2093    return session->proxyPort;
2094}
2095
2096void
2097tr_sessionSetProxy( tr_session * session,
2098                    const char * proxy )
2099{
2100    assert( tr_isSession( session ) );
2101
2102    if( proxy != session->proxy )
2103    {
2104        tr_free( session->proxy );
2105        session->proxy = tr_strdup( proxy );
2106    }
2107}
2108
2109void
2110tr_sessionSetProxyPort( tr_session * session,
2111                        tr_port      port )
2112{
2113    assert( tr_isSession( session ) );
2114
2115    session->proxyPort = port;
2116}
2117
2118tr_bool
2119tr_sessionIsProxyAuthEnabled( const tr_session * session )
2120{
2121    assert( tr_isSession( session ) );
2122
2123    return session->isProxyAuthEnabled;
2124}
2125
2126void
2127tr_sessionSetProxyAuthEnabled( tr_session * session,
2128                               tr_bool      isEnabled )
2129{
2130    assert( tr_isSession( session ) );
2131
2132    session->isProxyAuthEnabled = isEnabled != 0;
2133}
2134
2135const char*
2136tr_sessionGetProxyUsername( const tr_session * session )
2137{
2138    assert( tr_isSession( session ) );
2139
2140    return session->proxyUsername;
2141}
2142
2143void
2144tr_sessionSetProxyUsername( tr_session * session,
2145                            const char * username )
2146{
2147    assert( tr_isSession( session ) );
2148
2149    if( username != session->proxyUsername )
2150    {
2151        tr_free( session->proxyUsername );
2152        session->proxyUsername = tr_strdup( username );
2153    }
2154}
2155
2156const char*
2157tr_sessionGetProxyPassword( const tr_session * session )
2158{
2159    assert( tr_isSession( session ) );
2160
2161    return session->proxyPassword;
2162}
2163
2164void
2165tr_sessionSetProxyPassword( tr_session * session,
2166                            const char * password )
2167{
2168    assert( tr_isSession( session ) );
2169
2170    if( password != session->proxyPassword )
2171    {
2172        tr_free( session->proxyPassword );
2173        session->proxyPassword = tr_strdup( password );
2174    }
2175}
2176
2177int
2178tr_sessionGetActiveTorrentCount( tr_session * session )
2179{
2180    int ret = 0;
2181    tr_torrent * tor = NULL;
2182
2183    assert( tr_isSession( session ) );
2184
2185    while(( tor = tr_torrentNext( session, tor )))
2186        if( tr_torrentGetActivity( tor ) != TR_STATUS_STOPPED )
2187            ++ret;
2188
2189    return ret;
2190}
Note: See TracBrowser for help on using the repository browser.