source: trunk/libtransmission/session.c @ 9522

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

(trunk) #2222: revert r8967, as foreshadowed in http://trac.transmissionbt.com/ticket/2222#comment:20

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