source: trunk/libtransmission/session.c @ 9346

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

libT doesn't need to create the Incomplete directory until it's needed

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