source: trunk/libtransmission/session.c @ 10606

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

(trunk) #3060 -- Local Peer Discovery patch from Eszet

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