source: trunk/libtransmission/session.c @ 9073

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

delete the obsolete zsh bindings

  • Property svn:keywords set to Date Rev Author Id
File size: 59.7 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 9073 2009-09-08 20:01:12Z 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
585fprintf( stderr, "sizeof(tr_address) is %d\n", (int)sizeof(tr_address) );
586
587    assert( tr_bencIsDict( clientSettings ) );
588
589    /* initialize the bare skeleton of the session object */
590    session = tr_new0( tr_session, 1 );
591    session->bandwidth = tr_bandwidthNew( session, NULL );
592    session->lock = tr_lockNew( );
593    session->tag = tr_strdup( tag );
594    session->magicNumber = SESSION_MAGIC_NUMBER;
595    tr_bencInitList( &session->removedTorrents, 0 );
596
597    /* start the libtransmission thread */
598    tr_netInit( ); /* must go before tr_eventInit */
599    tr_eventInit( session );
600    assert( session->events != NULL );
601
602    /* run the rest in the libtransmission thread */
603    session->isWaiting = TRUE;
604    data.session = session;
605    data.configDir = configDir;
606    data.messageQueuingEnabled = messageQueuingEnabled;
607    data.clientSettings = clientSettings;
608    tr_runInEventThread( session, tr_sessionInitImpl, &data );
609    while( session->isWaiting )
610        tr_wait( 100 );
611
612    return session;
613}
614
615static void useAltSpeed( tr_session * session, tr_bool enabled, tr_bool byUser );
616static void useAltSpeedTime( tr_session * session, tr_bool enabled, tr_bool byUser );
617
618static void
619tr_sessionInitImpl( void * vdata )
620{
621    int64_t i;
622    int64_t j;
623    double  d;
624    tr_bool found;
625    tr_bool boolVal;
626    const char * str;
627    tr_benc settings;
628    char * filename;
629    struct init_data * data = vdata;
630    tr_benc * clientSettings = data->clientSettings;
631    tr_session * session = data->session;
632
633    assert( tr_amInEventThread( session ) );
634    assert( tr_bencIsDict( clientSettings ) );
635
636    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth );
637
638    tr_bencInitDict( &settings, 0 );
639    tr_sessionGetDefaultSettings( &settings );
640    tr_bencMergeDicts( &settings, clientSettings );
641
642#ifndef WIN32
643    /* Don't exit when writing on a broken socket */
644    signal( SIGPIPE, SIG_IGN );
645#endif
646
647    /* set the session's file mode creation mask (umask) to session->umask & 0777 */
648    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UMASK, &i );
649    assert( found );
650    session->umask = (mode_t)i;
651    umask( session->umask );
652
653    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i );
654    assert( found );
655    session->peerLimitPerTorrent = i;
656
657    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i );
658    assert( found );
659    tr_setMessageLevel( i );
660    tr_setMessageQueuing( data->messageQueuingEnabled );
661
662
663    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal );
664    assert( found );
665    session->isPexEnabled = boolVal;
666
667    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_DHT_ENABLED, &boolVal );
668    assert( found );
669    session->isDHTEnabled = boolVal;
670
671    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i );
672    assert( found );
673    assert( tr_isEncryptionMode( i ) );
674    session->encryptionMode = i;
675
676    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i );
677    assert( found );
678    assert( tr_isPreallocationMode( i ) );
679    session->preallocationMode = i;
680
681    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i );
682    assert( found );
683    session->peerSocketTOS = i;
684
685    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str );
686    assert( found );
687    session->downloadDir = tr_strdup( str );
688
689    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_ENABLED, &boolVal );
690    assert( found );
691    session->isProxyEnabled = boolVal;
692
693    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str );
694    assert( found );
695    session->proxy = tr_strdup( str );
696
697    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i );
698    assert( found );
699    session->proxyPort = i;
700
701    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i );
702    assert( found );
703    session->proxyType = i;
704
705    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &boolVal );
706    assert( found );
707    session->isProxyAuthEnabled = boolVal;
708
709    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str );
710    assert( found );
711    session->proxyUsername = tr_strdup( str );
712
713    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str );
714    assert( found );
715    session->proxyPassword = tr_strdup( str );
716
717    session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */
718    session->so_rcvbuf = 8192;
719
720    tr_setConfigDir( session, data->configDir );
721
722    tr_trackerSessionInit( session );
723    assert( session->tracker != NULL );
724
725    session->peerMgr = tr_peerMgrNew( session );
726
727    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal );
728    assert( found );
729    session->useLazyBitfield = boolVal;
730
731    /* Initialize rate and file descripts controls */
732
733    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i );
734    assert( found );
735    session->openFileLimit = i;
736    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j );
737    assert( found );
738    tr_fdInit( session->openFileLimit, j );
739
740    /**
741    *** random port
742    **/
743
744    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, &boolVal );
745    assert( found );
746    session->isPortRandom = boolVal;
747
748    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i );
749    assert( found );
750    session->randomPortLow = i;
751
752    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i );
753    assert( found );
754    session->randomPortHigh = i;
755
756    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, &boolVal )
757         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j );
758    assert( found );
759    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
760
761    /* public addresses */
762
763    {
764        struct tr_bindinfo b;
765        const char * str;
766
767        str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
768        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
769        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET ) )
770            b.addr = tr_inaddr_any;
771        b.socket = -1;
772        session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
773
774        str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
775        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
776        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET6 ) )
777            b.addr = tr_in6addr_any;
778        b.socket = -1;
779        session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
780
781        open_incoming_peer_port( session );
782    }
783
784    session->shared = tr_sharedInit( session, boolVal );
785
786    /**
787    **/
788
789    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i );
790    assert( found );
791    session->uploadSlotsPerTorrent = i;
792
793    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i )
794         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_USPEED_ENABLED, &boolVal );
795    assert( found );
796    tr_sessionSetSpeedLimit( session, TR_UP, i );
797    tr_sessionLimitSpeed( session, TR_UP, boolVal );
798
799    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i )
800         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &boolVal );
801    assert( found );
802    tr_sessionSetSpeedLimit( session, TR_DOWN, i );
803    tr_sessionLimitSpeed( session, TR_DOWN, boolVal );
804
805    found = tr_bencDictFindReal( &settings, TR_PREFS_KEY_RATIO, &d )
806         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, &boolVal );
807    assert( found );
808    tr_sessionSetRatioLimit( session, d );
809    tr_sessionSetRatioLimited( session, boolVal );
810
811    /**
812    ***  Alternate speed limits
813    **/
814
815    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_UP, &i );
816    assert( found );
817    session->altSpeed[TR_UP] = i;
818
819    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_DOWN, &i );
820    assert( found );
821    session->altSpeed[TR_DOWN] = i;
822
823    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, &i );
824    assert( found );
825    session->altSpeedTimeBegin = i;
826
827    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_END, &i );
828    assert( found );
829    session->altSpeedTimeEnd = i;
830
831    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, &i );
832    assert( found );
833    session->altSpeedTimeDay = i;
834
835    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, &boolVal );
836    assert( found );
837    useAltSpeedTime( session, boolVal, FALSE );
838
839    if( !boolVal )
840    {
841        found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_ENABLED, &boolVal );
842        assert( found );
843        useAltSpeed( session, boolVal, FALSE );
844    }
845    else
846        useAltSpeed( session, isAltTime( session ), FALSE );
847
848    /**
849    ***  Blocklist
850    **/
851
852    filename = tr_buildPath( session->configDir, "blocklists", NULL );
853    tr_mkdirp( filename, 0777 );
854    tr_free( filename );
855    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal );
856    assert( found );
857    session->isBlocklistEnabled = boolVal;
858    loadBlocklists( session );
859
860    session->rpcServer = tr_rpcInit( session, &settings );
861
862    tr_bencFree( &settings );
863
864    assert( tr_isSession( session ) );
865
866    session->altTimer = tr_new0( struct event, 1 );
867    evtimer_set( session->altTimer, onAltTimer, session );
868    setAltTimer( session );
869
870    session->saveTimer = tr_new0( struct event, 1 );
871    evtimer_set( session->saveTimer, onSaveTimer, session );
872    tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
873
874    /* first %s is the application name
875       second %s is the version number */
876    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
877
878    tr_statsInit( session );
879    session->web = tr_webInit( session );
880    session->isWaiting = FALSE;
881    dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker );
882
883    if( session->isDHTEnabled )
884    {
885#ifdef WITHOUT_DHT
886        tr_inf( "DHT disabled by packager." );
887#else
888        tr_dhtInit( session, &session->public_ipv4->addr );
889#endif
890    }
891}
892
893/***
894****
895***/
896
897void
898tr_sessionSetDownloadDir( tr_session * session, const char * dir )
899{
900    assert( tr_isSession( session ) );
901
902    if( session->downloadDir != dir )
903    {
904        tr_free( session->downloadDir );
905        session->downloadDir = tr_strdup( dir );
906    }
907}
908
909const char *
910tr_sessionGetDownloadDir( const tr_session * session )
911{
912    assert( tr_isSession( session ) );
913
914    return session->downloadDir;
915}
916
917/***
918****
919***/
920
921void
922tr_globalLock( tr_session * session )
923{
924    assert( tr_isSession( session ) );
925
926    tr_lockLock( session->lock );
927}
928
929void
930tr_globalUnlock( tr_session * session )
931{
932    assert( tr_isSession( session ) );
933
934    tr_lockUnlock( session->lock );
935}
936
937tr_bool
938tr_globalIsLocked( const tr_session * session )
939{
940    return tr_isSession( session ) && tr_lockHave( session->lock );
941}
942
943/***********************************************************************
944 * tr_setBindPort
945 ***********************************************************************
946 *
947 **********************************************************************/
948
949static void
950setPeerPort( void * session )
951{
952    tr_torrent * tor = NULL;
953
954    assert( tr_isSession( session ) );
955
956    close_incoming_peer_port( session );
957    open_incoming_peer_port( session );
958    tr_sharedPortChanged( session );
959
960    while(( tor = tr_torrentNext( session, tor )))
961        tr_torrentChangeMyPort( tor );
962}
963
964void
965tr_sessionSetPeerPort( tr_session * session,
966                       tr_port      port )
967{
968    assert( tr_isSession( session ) );
969
970    session->peerPort = port;
971
972    tr_runInEventThread( session, setPeerPort, session );
973}
974
975tr_port
976tr_sessionGetPeerPort( const tr_session * session )
977{
978    assert( tr_isSession( session ) );
979
980    return session->peerPort;
981}
982
983tr_port
984tr_sessionSetPeerPortRandom( tr_session * session )
985{
986    assert( tr_isSession( session ) );
987
988    tr_sessionSetPeerPort( session, getRandomPort( session ) );
989    return session->peerPort;
990}
991
992void
993tr_sessionSetPeerPortRandomOnStart( tr_session * session,
994                                    tr_bool random )
995{
996    assert( tr_isSession( session ) );
997
998    session->isPortRandom = random;
999}
1000
1001tr_bool
1002tr_sessionGetPeerPortRandomOnStart( tr_session * session )
1003{
1004    assert( tr_isSession( session ) );
1005
1006    return session->isPortRandom;
1007}
1008
1009tr_port_forwarding
1010tr_sessionGetPortForwarding( const tr_session * session )
1011{
1012    assert( tr_isSession( session ) );
1013
1014    return tr_sharedTraversalStatus( session->shared );
1015}
1016
1017/***
1018****
1019***/
1020
1021static void
1022updateSeedRatio( tr_session * session )
1023{
1024    tr_torrent * tor = NULL;
1025
1026    while(( tor = tr_torrentNext( session, tor )))
1027        tor->needsSeedRatioCheck = TRUE;
1028}
1029
1030void
1031tr_sessionSetRatioLimited( tr_session * session, tr_bool isLimited )
1032{
1033    assert( tr_isSession( session ) );
1034
1035    session->isRatioLimited = isLimited;
1036    updateSeedRatio( session );
1037}
1038
1039void
1040tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
1041{
1042    assert( tr_isSession( session ) );
1043
1044    session->desiredRatio = desiredRatio;
1045    updateSeedRatio( session );
1046}
1047
1048tr_bool
1049tr_sessionIsRatioLimited( const tr_session  * session )
1050{
1051    assert( tr_isSession( session ) );
1052
1053    return session->isRatioLimited;
1054}
1055
1056double
1057tr_sessionGetRatioLimit( const tr_session * session )
1058{
1059    assert( tr_isSession( session ) );
1060
1061    return session->desiredRatio;
1062}
1063
1064/***
1065****  SPEED LIMITS
1066***/
1067
1068tr_bool
1069tr_sessionGetActiveSpeedLimit( const tr_session * session, tr_direction dir, int * setme )
1070{
1071    int isLimited = TRUE;
1072
1073    if( !tr_isSession( session ) )
1074        return FALSE;
1075
1076    if( tr_sessionUsesAltSpeed( session ) )
1077        *setme = tr_sessionGetAltSpeed( session, dir );
1078    else if( tr_sessionIsSpeedLimited( session, dir ) )
1079        *setme = tr_sessionGetSpeedLimit( session, dir );
1080    else
1081        isLimited = FALSE;
1082
1083    return isLimited;
1084}
1085
1086static void
1087updateBandwidth( tr_session * session, tr_direction dir )
1088{
1089    int limit = 0;
1090    const tr_bool isLimited = tr_sessionGetActiveSpeedLimit( session, dir, &limit );
1091    const tr_bool zeroCase = isLimited && !limit;
1092
1093    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited && !zeroCase );
1094
1095    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, limit );
1096}
1097
1098static void
1099altSpeedToggled( void * vsession )
1100{
1101    tr_session * session = vsession;
1102
1103    assert( tr_isSession( session ) );
1104
1105    updateBandwidth( session, TR_UP );
1106    updateBandwidth( session, TR_DOWN );
1107
1108    if( session->altCallback != NULL )
1109        (*session->altCallback)( session, session->altSpeedEnabled, session->altSpeedChangedByUser, session->altCallbackUserData );
1110}
1111
1112/* tell the alt speed limit timer to fire again at the top of the minute */
1113static void
1114setAltTimer( tr_session * session )
1115{
1116    const time_t now = time( NULL );
1117    struct tm tm;
1118
1119    assert( tr_isSession( session ) );
1120    assert( session->altTimer != NULL );
1121
1122    tr_localtime_r( &now, &tm );
1123    tr_timerAdd( session->altTimer, 60-tm.tm_sec, 0 );
1124}
1125
1126/* this is called once a minute to:
1127 * (1) update session->isAltTime
1128 * (2) alter the speed limits when the alt limits go on and off */
1129static void
1130onAltTimer( int foo UNUSED, short bar UNUSED, void * vsession )
1131{
1132    tr_session * session = vsession;
1133
1134    assert( tr_isSession( session ) );
1135
1136    if( session->altSpeedTimeEnabled )
1137    {
1138        const time_t now = time( NULL );
1139        struct tm tm;
1140        int currentMinute, day;
1141        tr_bool isBeginTime, isEndTime, isDay;
1142        tr_localtime_r( &now, &tm );
1143        currentMinute = tm.tm_hour*60 + tm.tm_min;
1144        day = tm.tm_wday;
1145
1146        isBeginTime = currentMinute == session->altSpeedTimeBegin;
1147        isEndTime = currentMinute == session->altSpeedTimeEnd;
1148        if( isBeginTime || isEndTime )
1149        {
1150            /* if looking at the end date, look at the next day if end time is before begin time */
1151            if( isEndTime && !isBeginTime && session->altSpeedTimeEnd < session->altSpeedTimeBegin )
1152                day = (day - 1) % 7;
1153
1154            isDay = ((1<<day) & session->altSpeedTimeDay) != 0;
1155
1156            if( isDay )
1157                useAltSpeed( session, isBeginTime, FALSE );
1158        }
1159    }
1160
1161    setAltTimer( session );
1162}
1163
1164/***
1165****  Primary session speed limits
1166***/
1167
1168void
1169tr_sessionSetSpeedLimit( tr_session * s, tr_direction d, int KB_s )
1170{
1171    assert( tr_isSession( s ) );
1172    assert( tr_isDirection( d ) );
1173    assert( KB_s >= 0 );
1174
1175    s->speedLimit[d] = KB_s;
1176
1177    updateBandwidth( s, d );
1178}
1179
1180int
1181tr_sessionGetSpeedLimit( const tr_session * s, tr_direction d )
1182{
1183    assert( tr_isSession( s ) );
1184    assert( tr_isDirection( d ) );
1185
1186    return s->speedLimit[d];
1187}
1188
1189void
1190tr_sessionLimitSpeed( tr_session * s, tr_direction d, tr_bool b )
1191{
1192    assert( tr_isSession( s ) );
1193    assert( tr_isDirection( d ) );
1194    assert( tr_isBool( b ) );
1195
1196    s->speedLimitEnabled[d] = b;
1197
1198    updateBandwidth( s, d );
1199}
1200
1201tr_bool
1202tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1203{
1204    assert( tr_isSession( s ) );
1205    assert( tr_isDirection( d ) );
1206
1207    return s->speedLimitEnabled[d];
1208}
1209
1210/***
1211****  Alternative speed limits that are used during scheduled times
1212***/
1213
1214void
1215tr_sessionSetAltSpeed( tr_session * s, tr_direction d, int KB_s )
1216{
1217    assert( tr_isSession( s ) );
1218    assert( tr_isDirection( d ) );
1219    assert( KB_s >= 0 );
1220
1221    s->altSpeed[d] = KB_s;
1222
1223    updateBandwidth( s, d );
1224}
1225
1226int
1227tr_sessionGetAltSpeed( const tr_session * s, tr_direction d )
1228{
1229    assert( tr_isSession( s ) );
1230    assert( tr_isDirection( d ) );
1231
1232    return s->altSpeed[d];
1233}
1234
1235void
1236useAltSpeedTime( tr_session * session, tr_bool enabled, tr_bool byUser )
1237{
1238    assert( tr_isSession( session ) );
1239    assert( tr_isBool( enabled ) );
1240    assert( tr_isBool( byUser ) );
1241
1242    if( session->altSpeedTimeEnabled != enabled )
1243    {
1244        const tr_bool isAlt = isAltTime( session );
1245
1246        session->altSpeedTimeEnabled = enabled;
1247
1248        if( enabled && session->altSpeedEnabled != isAlt )
1249            useAltSpeed( session, isAlt, byUser );
1250    }
1251}
1252void
1253tr_sessionUseAltSpeedTime( tr_session * s, tr_bool b )
1254{
1255    useAltSpeedTime( s, b, TRUE );
1256}
1257
1258tr_bool
1259tr_sessionUsesAltSpeedTime( const tr_session * s )
1260{
1261    assert( tr_isSession( s ) );
1262
1263    return s->altSpeedTimeEnabled;
1264}
1265
1266void
1267tr_sessionSetAltSpeedBegin( tr_session * s, int minutes )
1268{
1269    assert( tr_isSession( s ) );
1270    assert( 0<=minutes && minutes<(60*24) );
1271
1272    if( s->altSpeedTimeBegin != minutes )
1273    {
1274        s->altSpeedTimeBegin = minutes;
1275
1276        if( tr_sessionUsesAltSpeedTime( s ) )
1277            useAltSpeed( s, isAltTime( s ), TRUE );
1278    }
1279}
1280
1281int
1282tr_sessionGetAltSpeedBegin( const tr_session * s )
1283{
1284    assert( tr_isSession( s ) );
1285
1286    return s->altSpeedTimeBegin;
1287}
1288
1289void
1290tr_sessionSetAltSpeedEnd( tr_session * s, int minutes )
1291{
1292    assert( tr_isSession( s ) );
1293    assert( 0<=minutes && minutes<(60*24) );
1294
1295    if( s->altSpeedTimeEnd != minutes )
1296    {
1297        s->altSpeedTimeEnd = minutes;
1298
1299        if( tr_sessionUsesAltSpeedTime( s ) )
1300            useAltSpeed( s, isAltTime( s ), TRUE );
1301    }
1302}
1303
1304int
1305tr_sessionGetAltSpeedEnd( const tr_session * s )
1306{
1307    assert( tr_isSession( s ) );
1308
1309    return s->altSpeedTimeEnd;
1310}
1311
1312void
1313tr_sessionSetAltSpeedDay( tr_session * s, tr_sched_day day )
1314{
1315    assert( tr_isSession( s ) );
1316
1317    if( s->altSpeedTimeDay != day )
1318    {
1319        s->altSpeedTimeDay = day;
1320
1321        if( tr_sessionUsesAltSpeedTime( s ) )
1322            useAltSpeed( s, isAltTime( s ), TRUE );
1323    }
1324}
1325
1326tr_sched_day
1327tr_sessionGetAltSpeedDay( const tr_session * s )
1328{
1329    assert( tr_isSession( s ) );
1330
1331    return s->altSpeedTimeDay;
1332}
1333
1334void
1335useAltSpeed( tr_session * s, tr_bool enabled, tr_bool byUser )
1336{
1337    assert( tr_isSession( s ) );
1338    assert( tr_isBool( enabled ) );
1339    assert( tr_isBool( byUser ) );
1340
1341    if( s->altSpeedEnabled != enabled)
1342    {
1343        s->altSpeedEnabled = enabled;
1344        s->altSpeedChangedByUser = byUser;
1345
1346        tr_runInEventThread( s, altSpeedToggled, s );
1347    }
1348}
1349void
1350tr_sessionUseAltSpeed( tr_session * session, tr_bool enabled )
1351{
1352    useAltSpeed( session, enabled, TRUE );
1353}
1354
1355tr_bool
1356tr_sessionUsesAltSpeed( const tr_session * s )
1357{
1358    assert( tr_isSession( s ) );
1359
1360    return s->altSpeedEnabled;
1361}
1362
1363void
1364tr_sessionSetAltSpeedFunc( tr_session       * session,
1365                           tr_altSpeedFunc    func,
1366                           void             * userData )
1367{
1368    assert( tr_isSession( session ) );
1369
1370    session->altCallback = func;
1371    session->altCallbackUserData = userData;
1372}
1373
1374void
1375tr_sessionClearAltSpeedFunc( tr_session * session )
1376{
1377    tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1378}
1379
1380/***
1381****
1382***/
1383
1384void
1385tr_sessionSetPeerLimit( tr_session * session, uint16_t maxGlobalPeers )
1386{
1387    assert( tr_isSession( session ) );
1388
1389    tr_fdSetPeerLimit( maxGlobalPeers );
1390}
1391
1392uint16_t
1393tr_sessionGetPeerLimit( const tr_session * session )
1394{
1395    assert( tr_isSession( session ) );
1396
1397    return tr_fdGetPeerLimit( );
1398}
1399
1400void
1401tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
1402{
1403    assert( tr_isSession( session ) );
1404
1405    session->peerLimitPerTorrent = n;
1406}
1407
1408uint16_t
1409tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1410{
1411    assert( tr_isSession( session ) );
1412
1413    return session->peerLimitPerTorrent;
1414}
1415
1416/***
1417****
1418***/
1419
1420double
1421tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
1422{
1423    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1424}
1425
1426double
1427tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
1428{
1429    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1430}
1431
1432int
1433tr_sessionCountTorrents( const tr_session * session )
1434{
1435    return tr_isSession( session ) ? session->torrentCount : 0;
1436}
1437
1438static int
1439compareTorrentByCur( const void * va, const void * vb )
1440{
1441    const tr_torrent * a = *(const tr_torrent**)va;
1442    const tr_torrent * b = *(const tr_torrent**)vb;
1443    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1444    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1445
1446    if( aCur != bCur )
1447        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1448
1449    return 0;
1450}
1451
1452static void
1453sessionCloseImpl( void * vsession )
1454{
1455    tr_session *  session = vsession;
1456    tr_torrent *  tor;
1457    int           i, n;
1458    tr_torrent ** torrents;
1459
1460    assert( tr_isSession( session ) );
1461
1462    free_incoming_peer_port( session );
1463
1464    if( session->isDHTEnabled )
1465        tr_dhtUninit( session );
1466
1467    evtimer_del( session->saveTimer );
1468    tr_free( session->saveTimer );
1469    session->saveTimer = NULL;
1470
1471    evtimer_del( session->altTimer );
1472    tr_free( session->altTimer );
1473    session->altTimer = NULL;
1474
1475    tr_verifyClose( session );
1476    tr_statsClose( session );
1477    tr_sharedClose( session );
1478    tr_rpcClose( &session->rpcServer );
1479
1480    /* close the torrents.  get the most active ones first so that
1481     * if we can't get them all closed in a reasonable amount of time,
1482     * at least we get the most important ones first. */
1483    tor = NULL;
1484    n = session->torrentCount;
1485    torrents = tr_new( tr_torrent *, session->torrentCount );
1486    for( i = 0; i < n; ++i )
1487        torrents[i] = tor = tr_torrentNext( session, tor );
1488    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1489    for( i = 0; i < n; ++i )
1490        tr_torrentFree( torrents[i] );
1491    tr_free( torrents );
1492
1493    tr_peerMgrFree( session->peerMgr );
1494
1495    tr_trackerSessionClose( session );
1496    tr_list_free( &session->blocklists,
1497                  (TrListForeachFunc)_tr_blocklistFree );
1498    tr_webClose( &session->web );
1499
1500    session->isClosed = TRUE;
1501}
1502
1503static int
1504deadlineReached( const uint64_t deadline )
1505{
1506    return tr_date( ) >= deadline;
1507}
1508
1509#define SHUTDOWN_MAX_SECONDS 30
1510
1511void
1512tr_sessionClose( tr_session * session )
1513{
1514    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
1515    const uint64_t deadline = tr_date( ) + maxwait_msec;
1516
1517    assert( tr_isSession( session ) );
1518
1519    dbgmsg( "shutting down transmission session %p", session );
1520
1521    /* close the session */
1522    tr_runInEventThread( session, sessionCloseImpl, session );
1523    while( !session->isClosed && !deadlineReached( deadline ) )
1524    {
1525        dbgmsg(
1526            "waiting for the shutdown commands to run in the main thread" );
1527        tr_wait( 100 );
1528    }
1529
1530    /* "shared" and "tracker" have live sockets,
1531     * so we need to keep the transmission thread alive
1532     * for a bit while they tell the router & tracker
1533     * that we're closing now */
1534    while( ( session->shared
1535           || session->tracker ) && !deadlineReached( deadline ) )
1536    {
1537        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
1538                session->shared, session->tracker );
1539        tr_wait( 100 );
1540    }
1541
1542    tr_fdClose( );
1543
1544    /* close the libtransmission thread */
1545    tr_eventClose( session );
1546    while( session->events && !deadlineReached( deadline ) )
1547    {
1548        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
1549        tr_wait( 100 );
1550    }
1551
1552    /* free the session memory */
1553    tr_bencFree( &session->removedTorrents );
1554    tr_bandwidthFree( session->bandwidth );
1555    tr_lockFree( session->lock );
1556    if( session->metainfoLookup ) {
1557        tr_bencFree( session->metainfoLookup );
1558        tr_free( session->metainfoLookup );
1559    }
1560    tr_free( session->tag );
1561    tr_free( session->configDir );
1562    tr_free( session->resumeDir );
1563    tr_free( session->torrentDir );
1564    tr_free( session->downloadDir );
1565    tr_free( session->proxy );
1566    tr_free( session->proxyUsername );
1567    tr_free( session->proxyPassword );
1568    tr_free( session );
1569}
1570
1571tr_torrent **
1572tr_sessionLoadTorrents( tr_session * session,
1573                        tr_ctor    * ctor,
1574                        int        * setmeCount )
1575{
1576    int           i, n = 0;
1577    struct stat   sb;
1578    DIR *         odir = NULL;
1579    const char *  dirname = tr_getTorrentDir( session );
1580    tr_torrent ** torrents;
1581    tr_list *     l = NULL, *list = NULL;
1582
1583    assert( tr_isSession( session ) );
1584
1585    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1586
1587    if( !stat( dirname, &sb )
1588      && S_ISDIR( sb.st_mode )
1589      && ( ( odir = opendir ( dirname ) ) ) )
1590    {
1591        struct dirent *d;
1592        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1593        {
1594            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1595                                                     */
1596            {
1597                tr_torrent * tor;
1598                char * path = tr_buildPath( dirname, d->d_name, NULL );
1599                tr_ctorSetMetainfoFromFile( ctor, path );
1600                if(( tor = tr_torrentNew( ctor, NULL )))
1601                {
1602                    tr_list_append( &list, tor );
1603                    ++n;
1604                }
1605                tr_free( path );
1606            }
1607        }
1608        closedir( odir );
1609    }
1610
1611    torrents = tr_new( tr_torrent *, n );
1612    for( i = 0, l = list; l != NULL; l = l->next )
1613        torrents[i++] = (tr_torrent*) l->data;
1614    assert( i == n );
1615
1616    tr_list_free( &list, NULL );
1617
1618    if( n )
1619        tr_inf( _( "Loaded %d torrents" ), n );
1620
1621    if( setmeCount )
1622        *setmeCount = n;
1623    return torrents;
1624}
1625
1626/***
1627****
1628***/
1629
1630void
1631tr_sessionSetPexEnabled( tr_session * session,
1632                         tr_bool      enabled )
1633{
1634    assert( tr_isSession( session ) );
1635
1636    session->isPexEnabled = enabled != 0;
1637}
1638
1639tr_bool
1640tr_sessionIsPexEnabled( const tr_session * session )
1641{
1642    assert( tr_isSession( session ) );
1643
1644    return session->isPexEnabled;
1645}
1646
1647tr_bool
1648tr_sessionAllowsDHT( const tr_session * session UNUSED )
1649{
1650#ifdef WITHOUT_DHT
1651    return 0;
1652#else
1653    return tr_sessionIsDHTEnabled( session );
1654#endif
1655}
1656
1657tr_bool
1658tr_sessionIsDHTEnabled( const tr_session * session )
1659{
1660    assert( tr_isSession( session ) );
1661
1662    return session->isDHTEnabled;
1663}
1664
1665static void
1666toggleDHTImpl(  void * data )
1667{
1668    tr_session * session = data;
1669    assert( tr_isSession( session ) );
1670
1671    if( session->isDHTEnabled )
1672        tr_dhtUninit( session );
1673
1674    session->isDHTEnabled = !session->isDHTEnabled;
1675
1676    if( session->isDHTEnabled )
1677        tr_dhtInit( session, &session->public_ipv4->addr );
1678}
1679
1680void
1681tr_sessionSetDHTEnabled( tr_session * session, tr_bool enabled )
1682{
1683    assert( tr_isSession( session ) );
1684    assert( tr_isBool( enabled ) );
1685
1686    if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1687        tr_runInEventThread( session, toggleDHTImpl, session );
1688}
1689
1690/***
1691****
1692***/
1693
1694void
1695tr_sessionSetLazyBitfieldEnabled( tr_session * session,
1696                                  tr_bool      enabled )
1697{
1698    assert( tr_isSession( session ) );
1699
1700    session->useLazyBitfield = enabled != 0;
1701}
1702
1703tr_bool
1704tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
1705{
1706    assert( tr_isSession( session ) );
1707
1708    return session->useLazyBitfield;
1709}
1710
1711/***
1712****
1713***/
1714
1715void
1716tr_sessionSetPortForwardingEnabled( tr_session  * session,
1717                                    tr_bool       enabled )
1718{
1719    assert( tr_isSession( session ) );
1720
1721    tr_globalLock( session );
1722    tr_sharedTraversalEnable( session->shared, enabled );
1723    tr_globalUnlock( session );
1724}
1725
1726tr_bool
1727tr_sessionIsPortForwardingEnabled( const tr_session * session )
1728{
1729    assert( tr_isSession( session ) );
1730
1731    return tr_sharedTraversalIsEnabled( session->shared );
1732}
1733
1734/***
1735****
1736***/
1737
1738int
1739tr_blocklistGetRuleCount( const tr_session * session )
1740{
1741    int       n = 0;
1742    tr_list * l;
1743
1744    assert( tr_isSession( session ) );
1745
1746    for( l = session->blocklists; l; l = l->next )
1747        n += _tr_blocklistGetRuleCount( l->data );
1748    return n;
1749}
1750
1751tr_bool
1752tr_blocklistIsEnabled( const tr_session * session )
1753{
1754    assert( tr_isSession( session ) );
1755
1756    return session->isBlocklistEnabled;
1757}
1758
1759void
1760tr_blocklistSetEnabled( tr_session * session,
1761                        tr_bool      isEnabled )
1762{
1763    tr_list * l;
1764
1765    assert( tr_isSession( session ) );
1766
1767    session->isBlocklistEnabled = isEnabled != 0;
1768
1769    for( l=session->blocklists; l!=NULL; l=l->next )
1770        _tr_blocklistSetEnabled( l->data, isEnabled );
1771}
1772
1773tr_bool
1774tr_blocklistExists( const tr_session * session )
1775{
1776    assert( tr_isSession( session ) );
1777
1778    return session->blocklists != NULL;
1779}
1780
1781int
1782tr_blocklistSetContent( tr_session * session,
1783                        const char * contentFilename )
1784{
1785    tr_list *      l;
1786    tr_blocklist * b;
1787    const char *   defaultName = "level1.bin";
1788
1789    assert( tr_isSession( session ) );
1790
1791    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
1792        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
1793                               defaultName ) )
1794            b = l->data;
1795
1796    if( !b )
1797    {
1798        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
1799        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
1800        tr_list_append( &session->blocklists, b );
1801        tr_free( path );
1802    }
1803
1804    return _tr_blocklistSetContent( b, contentFilename );
1805}
1806
1807tr_bool
1808tr_sessionIsAddressBlocked( const tr_session * session,
1809                            const tr_address * addr )
1810{
1811    tr_list * l;
1812
1813    assert( tr_isSession( session ) );
1814
1815    for( l = session->blocklists; l; l = l->next )
1816        if( _tr_blocklistHasAddress( l->data, addr ) )
1817            return TRUE;
1818    return FALSE;
1819}
1820
1821/***
1822****
1823***/
1824
1825static void
1826metainfoLookupInit( tr_session * session )
1827{
1828    struct stat  sb;
1829    const char * dirname = tr_getTorrentDir( session );
1830    DIR *        odir = NULL;
1831    tr_ctor *    ctor = NULL;
1832    tr_benc * lookup;
1833    int n = 0;
1834
1835    assert( tr_isSession( session ) );
1836
1837    /* walk through the directory and find the mappings */
1838    lookup = tr_new0( tr_benc, 1 );
1839    tr_bencInitDict( lookup, 0 );
1840    ctor = tr_ctorNew( session );
1841    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1842    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
1843    {
1844        struct dirent *d;
1845        while(( d = readdir( odir )))
1846        {
1847            if( d->d_name && d->d_name[0] != '.' )
1848            {
1849                tr_info inf;
1850                char * path = tr_buildPath( dirname, d->d_name, NULL );
1851                tr_ctorSetMetainfoFromFile( ctor, path );
1852                if( !tr_torrentParse( ctor, &inf ) )
1853                {
1854                    ++n;
1855                    tr_bencDictAddStr( lookup, inf.hashString, path );
1856                }
1857                tr_free( path );
1858            }
1859        }
1860        closedir( odir );
1861    }
1862    tr_ctorFree( ctor );
1863
1864    session->metainfoLookup = lookup;
1865    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
1866}
1867
1868const char*
1869tr_sessionFindTorrentFile( const tr_session * session,
1870                           const char       * hashString )
1871{
1872    const char * filename = NULL;
1873    if( !session->metainfoLookup )
1874        metainfoLookupInit( (tr_session*)session );
1875    tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
1876    return filename;
1877}
1878
1879void
1880tr_sessionSetTorrentFile( tr_session * session,
1881                          const char * hashString,
1882                          const char * filename )
1883{
1884    /* since we walk session->configDir/torrents/ to build the lookup table,
1885     * and tr_sessionSetTorrentFile() is just to tell us there's a new file
1886     * in that same directory, we don't need to do anything here if the
1887     * lookup table hasn't been built yet */
1888    if( session->metainfoLookup )
1889        tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
1890}
1891
1892tr_torrent*
1893tr_torrentNext( tr_session * session,
1894                tr_torrent * tor )
1895{
1896    assert( tr_isSession( session ) );
1897
1898    return tor ? tor->next : session->torrentList;
1899}
1900
1901/***
1902****
1903***/
1904
1905void
1906tr_sessionSetRPCEnabled( tr_session * session,
1907                         tr_bool      isEnabled )
1908{
1909    assert( tr_isSession( session ) );
1910
1911    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1912}
1913
1914tr_bool
1915tr_sessionIsRPCEnabled( const tr_session * session )
1916{
1917    assert( tr_isSession( session ) );
1918
1919    return tr_rpcIsEnabled( session->rpcServer );
1920}
1921
1922void
1923tr_sessionSetRPCPort( tr_session * session,
1924                      tr_port      port )
1925{
1926    assert( tr_isSession( session ) );
1927
1928    tr_rpcSetPort( session->rpcServer, port );
1929}
1930
1931tr_port
1932tr_sessionGetRPCPort( const tr_session * session )
1933{
1934    assert( tr_isSession( session ) );
1935
1936    return tr_rpcGetPort( session->rpcServer );
1937}
1938
1939void
1940tr_sessionSetRPCCallback( tr_session * session,
1941                          tr_rpc_func  func,
1942                          void *       user_data )
1943{
1944    assert( tr_isSession( session ) );
1945
1946    session->rpc_func = func;
1947    session->rpc_func_user_data = user_data;
1948}
1949
1950void
1951tr_sessionSetRPCWhitelist( tr_session * session,
1952                           const char * whitelist )
1953{
1954    assert( tr_isSession( session ) );
1955
1956    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1957}
1958
1959const char*
1960tr_sessionGetRPCWhitelist( const tr_session * session )
1961{
1962    assert( tr_isSession( session ) );
1963
1964    return tr_rpcGetWhitelist( session->rpcServer );
1965}
1966
1967void
1968tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1969                                  tr_bool      isEnabled )
1970{
1971    assert( tr_isSession( session ) );
1972
1973    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1974}
1975
1976tr_bool
1977tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1978{
1979    assert( tr_isSession( session ) );
1980
1981    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1982}
1983
1984
1985void
1986tr_sessionSetRPCPassword( tr_session * session,
1987                          const char * password )
1988{
1989    assert( tr_isSession( session ) );
1990
1991    tr_rpcSetPassword( session->rpcServer, password );
1992}
1993
1994const char*
1995tr_sessionGetRPCPassword( const tr_session * session )
1996{
1997    assert( tr_isSession( session ) );
1998
1999    return tr_rpcGetPassword( session->rpcServer );
2000}
2001
2002void
2003tr_sessionSetRPCUsername( tr_session * session,
2004                          const char * username )
2005{
2006    assert( tr_isSession( session ) );
2007
2008    tr_rpcSetUsername( session->rpcServer, username );
2009}
2010
2011const char*
2012tr_sessionGetRPCUsername( const tr_session * session )
2013{
2014    assert( tr_isSession( session ) );
2015
2016    return tr_rpcGetUsername( session->rpcServer );
2017}
2018
2019void
2020tr_sessionSetRPCPasswordEnabled( tr_session * session,
2021                                 tr_bool      isEnabled )
2022{
2023    assert( tr_isSession( session ) );
2024
2025    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2026}
2027
2028tr_bool
2029tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2030{
2031    assert( tr_isSession( session ) );
2032
2033    return tr_rpcIsPasswordEnabled( session->rpcServer );
2034}
2035
2036const char *
2037tr_sessionGetRPCBindAddress( const tr_session * session )
2038{
2039    assert( tr_isSession( session ) );
2040
2041    return tr_rpcGetBindAddress( session->rpcServer );
2042}
2043
2044/***
2045****
2046***/
2047
2048tr_bool
2049tr_sessionIsProxyEnabled( const tr_session * session )
2050{
2051    assert( tr_isSession( session ) );
2052
2053    return session->isProxyEnabled;
2054}
2055
2056void
2057tr_sessionSetProxyEnabled( tr_session * session,
2058                           tr_bool      isEnabled )
2059{
2060    assert( tr_isSession( session ) );
2061
2062    session->isProxyEnabled = isEnabled != 0;
2063}
2064
2065tr_proxy_type
2066tr_sessionGetProxyType( const tr_session * session )
2067{
2068    assert( tr_isSession( session ) );
2069
2070    return session->proxyType;
2071}
2072
2073void
2074tr_sessionSetProxyType( tr_session *  session,
2075                        tr_proxy_type type )
2076{
2077    assert( tr_isSession( session ) );
2078
2079    session->proxyType = type;
2080}
2081
2082const char*
2083tr_sessionGetProxy( const tr_session * session )
2084{
2085    assert( tr_isSession( session ) );
2086
2087    return session->proxy;
2088}
2089
2090tr_port
2091tr_sessionGetProxyPort( const tr_session * session )
2092{
2093    assert( tr_isSession( session ) );
2094
2095    return session->proxyPort;
2096}
2097
2098void
2099tr_sessionSetProxy( tr_session * session,
2100                    const char * proxy )
2101{
2102    assert( tr_isSession( session ) );
2103
2104    if( proxy != session->proxy )
2105    {
2106        tr_free( session->proxy );
2107        session->proxy = tr_strdup( proxy );
2108    }
2109}
2110
2111void
2112tr_sessionSetProxyPort( tr_session * session,
2113                        tr_port      port )
2114{
2115    assert( tr_isSession( session ) );
2116
2117    session->proxyPort = port;
2118}
2119
2120tr_bool
2121tr_sessionIsProxyAuthEnabled( const tr_session * session )
2122{
2123    assert( tr_isSession( session ) );
2124
2125    return session->isProxyAuthEnabled;
2126}
2127
2128void
2129tr_sessionSetProxyAuthEnabled( tr_session * session,
2130                               tr_bool      isEnabled )
2131{
2132    assert( tr_isSession( session ) );
2133
2134    session->isProxyAuthEnabled = isEnabled != 0;
2135}
2136
2137const char*
2138tr_sessionGetProxyUsername( const tr_session * session )
2139{
2140    assert( tr_isSession( session ) );
2141
2142    return session->proxyUsername;
2143}
2144
2145void
2146tr_sessionSetProxyUsername( tr_session * session,
2147                            const char * username )
2148{
2149    assert( tr_isSession( session ) );
2150
2151    if( username != session->proxyUsername )
2152    {
2153        tr_free( session->proxyUsername );
2154        session->proxyUsername = tr_strdup( username );
2155    }
2156}
2157
2158const char*
2159tr_sessionGetProxyPassword( const tr_session * session )
2160{
2161    assert( tr_isSession( session ) );
2162
2163    return session->proxyPassword;
2164}
2165
2166void
2167tr_sessionSetProxyPassword( tr_session * session,
2168                            const char * password )
2169{
2170    assert( tr_isSession( session ) );
2171
2172    if( password != session->proxyPassword )
2173    {
2174        tr_free( session->proxyPassword );
2175        session->proxyPassword = tr_strdup( password );
2176    }
2177}
2178
2179int
2180tr_sessionGetActiveTorrentCount( tr_session * session )
2181{
2182    int ret = 0;
2183    tr_torrent * tor = NULL;
2184
2185    assert( tr_isSession( session ) );
2186
2187    while(( tor = tr_torrentNext( session, tor )))
2188        if( tr_torrentGetActivity( tor ) != TR_STATUS_STOPPED )
2189            ++ret;
2190
2191    return ret;
2192}
Note: See TracBrowser for help on using the repository browser.