source: trunk/libtransmission/session.c @ 12508

Last change on this file since 12508 was 12508, checked in by jordan, 10 years ago

(trunk libT) avoid thread issues on startup by ensuring that tr_sessionLoadTorrents() runs in the libtransmission thread.

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