source: trunk/libtransmission/session.c @ 12181

Last change on this file since 12181 was 12181, checked in by jordan, 11 years ago

(trunk libT) move tr_dhtUpkeep() out of the announcer module

During shutdown, we can stop DHT almost immediately, but need to leave the announcer running for the DHT tracker event=stopped messages. So it doesn't make sense to keep them on the same periodic timer.

  • 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 12181 2011-03-17 12:34:43Z 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/event.h>
25
26//#define TR_SHOW_DEPRECATED
27#include "transmission.h"
28#include "announcer.h"
29#include "bandwidth.h"
30#include "bencode.h"
31#include "blocklist.h"
32#include "cache.h"
33#include "crypto.h"
34#include "fdlimit.h"
35#include "list.h"
36#include "metainfo.h" /* tr_metainfoFree */
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, tr_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_ntop_non_ts( &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( const char * configDir UNUSED, 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_ntop_non_ts( &s->public_ipv4->addr ) );
425    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6,        tr_ntop_non_ts( &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
430tr_bool
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    tr_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( configDir, &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    tr_bool       done;
548    tr_bool       messageQueuingEnabled;
549    tr_benc     * clientSettings;
550};
551
552tr_session *
553tr_sessionInit( const char  * tag,
554                const char  * configDir,
555                tr_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->bandwidth = tr_bandwidthNew( session, NULL );
571    session->lock = tr_lockNew( );
572    session->cache = tr_cacheNew( 1024*1024*2 );
573    session->tag = tr_strdup( tag );
574    session->magicNumber = SESSION_MAGIC_NUMBER;
575    session->buffer = tr_valloc( SESSION_BUFFER_SIZE );
576    tr_peerIdInit( session->peer_id );
577    tr_bencInitList( &session->removedTorrents, 0 );
578
579    /* nice to start logging at the very beginning */
580    if( tr_bencDictFindInt( clientSettings, TR_PREFS_KEY_MSGLEVEL, &i ) )
581        tr_setMessageLevel( i );
582
583    /* start the libtransmission thread */
584    tr_netInit( ); /* must go before tr_eventInit */
585    tr_eventInit( session );
586    assert( session->events != NULL );
587
588    /* run the rest in the libtransmission thread */
589    data.done = FALSE;
590    data.session = session;
591    data.configDir = configDir;
592    data.messageQueuingEnabled = messageQueuingEnabled;
593    data.clientSettings = clientSettings;
594    tr_runInEventThread( session, tr_sessionInitImpl, &data );
595    while( !data.done )
596        tr_wait_msec( 100 );
597
598    return session;
599}
600
601static void turtleCheckClock( tr_session * s, struct tr_turtle_info * t );
602
603static void
604onNowTimer( int foo UNUSED, short bar UNUSED, void * vsession )
605{
606    int usec;
607    const int min = 100;
608    const int max = 999999;
609    struct timeval tv;
610    tr_torrent * tor = NULL;
611    tr_session * session = vsession;
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( time( NULL ) );
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( data->configDir, &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    tr_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_pton( str, &b.addr ) || ( 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_pton( str, &b.addr ) || ( 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, tr_bool b )
949{
950    assert( tr_isSession( session ) );
951    assert( tr_isBool( b ) );
952
953    session->isIncompleteFileNamingEnabled = b;
954}
955
956tr_bool
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, tr_bool b )
992{
993    assert( tr_isSession( session ) );
994    assert( tr_isBool( b ) );
995
996    session->isIncompleteDirEnabled = b;
997}
998
999tr_bool
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_sessionGetBuffer( tr_session * session )
1013{
1014    assert( tr_isSession( session ) );
1015    assert( !session->bufferInUse );
1016    assert( tr_amInEventThread( session ) );
1017
1018    session->bufferInUse = TRUE;
1019    return session->buffer;
1020}
1021
1022void
1023tr_sessionReleaseBuffer( tr_session * session )
1024{
1025    assert( tr_isSession( session ) );
1026    assert( session->bufferInUse );
1027    assert( tr_amInEventThread( session ) );
1028
1029    session->bufferInUse = FALSE;
1030}
1031
1032void
1033tr_sessionLock( tr_session * session )
1034{
1035    assert( tr_isSession( session ) );
1036
1037    tr_lockLock( session->lock );
1038}
1039
1040void
1041tr_sessionUnlock( tr_session * session )
1042{
1043    assert( tr_isSession( session ) );
1044
1045    tr_lockUnlock( session->lock );
1046}
1047
1048tr_bool
1049tr_sessionIsLocked( const tr_session * session )
1050{
1051    return tr_isSession( session ) && tr_lockHave( session->lock );
1052}
1053
1054/***********************************************************************
1055 * tr_setBindPort
1056 ***********************************************************************
1057 *
1058 **********************************************************************/
1059
1060static void
1061peerPortChanged( void * session )
1062{
1063    tr_torrent * tor = NULL;
1064
1065    assert( tr_isSession( session ) );
1066
1067    close_incoming_peer_port( session );
1068    open_incoming_peer_port( session );
1069    tr_sharedPortChanged( session );
1070
1071    while(( tor = tr_torrentNext( session, tor )))
1072        tr_torrentChangeMyPort( tor );
1073}
1074
1075static void
1076setPeerPort( tr_session * session, tr_port port )
1077{
1078    session->private_peer_port = port;
1079    session->public_peer_port = port;
1080
1081    tr_runInEventThread( session, peerPortChanged, session );
1082}
1083
1084void
1085tr_sessionSetPeerPort( tr_session * session, tr_port port )
1086{
1087    if( tr_isSession( session ) && ( session->private_peer_port != port ) )
1088    {
1089        setPeerPort( session, port );
1090    }
1091}
1092
1093tr_port
1094tr_sessionGetPeerPort( const tr_session * session )
1095{
1096    return tr_isSession( session ) ? session->private_peer_port : 0;
1097}
1098
1099tr_port
1100tr_sessionSetPeerPortRandom( tr_session * session )
1101{
1102    assert( tr_isSession( session ) );
1103
1104    tr_sessionSetPeerPort( session, getRandomPort( session ) );
1105    return session->private_peer_port;
1106}
1107
1108void
1109tr_sessionSetPeerPortRandomOnStart( tr_session * session,
1110                                    tr_bool random )
1111{
1112    assert( tr_isSession( session ) );
1113
1114    session->isPortRandom = random;
1115}
1116
1117tr_bool
1118tr_sessionGetPeerPortRandomOnStart( tr_session * session )
1119{
1120    assert( tr_isSession( session ) );
1121
1122    return session->isPortRandom;
1123}
1124
1125tr_port_forwarding
1126tr_sessionGetPortForwarding( const tr_session * session )
1127{
1128    assert( tr_isSession( session ) );
1129
1130    return tr_sharedTraversalStatus( session->shared );
1131}
1132
1133/***
1134****
1135***/
1136
1137void
1138tr_sessionSetRatioLimited( tr_session * session, tr_bool isLimited )
1139{
1140    assert( tr_isSession( session ) );
1141
1142    session->isRatioLimited = isLimited;
1143}
1144
1145void
1146tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
1147{
1148    assert( tr_isSession( session ) );
1149
1150    session->desiredRatio = desiredRatio;
1151}
1152
1153tr_bool
1154tr_sessionIsRatioLimited( const tr_session  * session )
1155{
1156    assert( tr_isSession( session ) );
1157
1158    return session->isRatioLimited;
1159}
1160
1161double
1162tr_sessionGetRatioLimit( const tr_session * session )
1163{
1164    assert( tr_isSession( session ) );
1165
1166    return session->desiredRatio;
1167}
1168
1169/***
1170****
1171***/
1172
1173void
1174tr_sessionSetIdleLimited( tr_session * session, tr_bool isLimited )
1175{
1176    assert( tr_isSession( session ) );
1177
1178    session->isIdleLimited = isLimited;
1179}
1180
1181void
1182tr_sessionSetIdleLimit( tr_session * session, uint16_t idleMinutes )
1183{
1184    assert( tr_isSession( session ) );
1185
1186    session->idleLimitMinutes = idleMinutes;
1187}
1188
1189tr_bool
1190tr_sessionIsIdleLimited( const tr_session  * session )
1191{
1192    assert( tr_isSession( session ) );
1193
1194    return session->isIdleLimited;
1195}
1196
1197uint16_t
1198tr_sessionGetIdleLimit( const tr_session * session )
1199{
1200    assert( tr_isSession( session ) );
1201
1202    return session->idleLimitMinutes;
1203}
1204
1205/***
1206****
1207****  SPEED LIMITS
1208****
1209***/
1210
1211tr_bool
1212tr_sessionGetActiveSpeedLimit_Bps( const tr_session * session, tr_direction dir, int * setme_Bps )
1213{
1214    int isLimited = TRUE;
1215
1216    if( !tr_isSession( session ) )
1217        return FALSE;
1218
1219    if( tr_sessionUsesAltSpeed( session ) )
1220        *setme_Bps = tr_sessionGetAltSpeed_Bps( session, dir );
1221    else if( tr_sessionIsSpeedLimited( session, dir ) )
1222        *setme_Bps = tr_sessionGetSpeedLimit_Bps( session, dir );
1223    else
1224        isLimited = FALSE;
1225
1226    return isLimited;
1227}
1228tr_bool
1229tr_sessionGetActiveSpeedLimit_KBps( const tr_session  * session,
1230                                    tr_direction        dir,
1231                                    double            * setme_KBps )
1232{
1233    int Bps = 0;
1234    const tr_bool is_active = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &Bps );
1235    *setme_KBps = toSpeedKBps( Bps );
1236    return is_active;
1237}
1238
1239static void
1240updateBandwidth( tr_session * session, tr_direction dir )
1241{
1242    int limit_Bps = 0;
1243    const tr_bool isLimited = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &limit_Bps );
1244    const tr_bool zeroCase = isLimited && !limit_Bps;
1245
1246    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited && !zeroCase );
1247
1248    tr_bandwidthSetDesiredSpeed_Bps( session->bandwidth, dir, limit_Bps );
1249}
1250
1251enum
1252{
1253    MINUTES_PER_HOUR = 60,
1254    MINUTES_PER_DAY = MINUTES_PER_HOUR * 24,
1255    MINUTES_PER_WEEK = MINUTES_PER_DAY * 7
1256};
1257
1258static void
1259turtleUpdateTable( struct tr_turtle_info * t )
1260{
1261    int day;
1262    tr_bitfield * b = &t->minutes;
1263
1264    tr_bitfieldClear( b );
1265
1266    for( day=0; day<7; ++day )
1267    {
1268        if( t->days & (1<<day) )
1269        {
1270            int i;
1271            const time_t begin = t->beginMinute;
1272            time_t end = t->endMinute;
1273
1274            if( end <= begin )
1275                end += MINUTES_PER_DAY;
1276
1277            for( i=begin; i<end; ++i )
1278                tr_bitfieldAdd( b, (i+day*MINUTES_PER_DAY) % MINUTES_PER_WEEK );
1279        }
1280    }
1281}
1282
1283static void
1284altSpeedToggled( void * vsession )
1285{
1286    tr_session * session = vsession;
1287    struct tr_turtle_info * t = &session->turtle;
1288
1289    assert( tr_isSession( session ) );
1290
1291    updateBandwidth( session, TR_UP );
1292    updateBandwidth( session, TR_DOWN );
1293
1294    if( t->callback != NULL )
1295        (*t->callback)( session, t->isEnabled, t->changedByUser, t->callbackUserData );
1296}
1297
1298static void
1299useAltSpeed( tr_session * s, struct tr_turtle_info * t,
1300             tr_bool enabled, tr_bool byUser )
1301{
1302    assert( tr_isSession( s ) );
1303    assert( t != NULL );
1304    assert( tr_isBool( enabled ) );
1305    assert( tr_isBool( byUser ) );
1306
1307    if( t->isEnabled != enabled )
1308    {
1309        t->isEnabled = enabled;
1310        t->changedByUser = byUser;
1311        tr_runInEventThread( s, altSpeedToggled, s );
1312    }
1313}
1314
1315/**
1316 * @param enabled whether turtle should be on/off according to the scheduler
1317 * @param changed whether that's different from the previous minute
1318 */
1319static void
1320testTurtleTime( const struct tr_turtle_info * t,
1321                tr_bool * enabled,
1322                tr_bool * changed )
1323{
1324    tr_bool e;
1325    struct tm tm;
1326    size_t minute_of_the_week;
1327    const time_t now = tr_time( );
1328
1329    tr_localtime_r( &now, &tm );
1330
1331    minute_of_the_week = tm.tm_wday * MINUTES_PER_DAY
1332                       + tm.tm_hour * MINUTES_PER_HOUR
1333                       + tm.tm_min;
1334    if( minute_of_the_week >= MINUTES_PER_WEEK ) /* leap minutes? */
1335        minute_of_the_week = MINUTES_PER_WEEK - 1;
1336
1337    e = tr_bitfieldHasFast( &t->minutes, minute_of_the_week );
1338    if( enabled != NULL )
1339        *enabled = e;
1340
1341    if( changed != NULL )
1342    {
1343        const size_t prev = minute_of_the_week > 0 ? minute_of_the_week - 1
1344                                                   : MINUTES_PER_WEEK - 1;
1345        *changed = e != tr_bitfieldHasFast( &t->minutes, prev );
1346    }
1347}
1348
1349static void
1350turtleCheckClock( tr_session * s, struct tr_turtle_info * t )
1351{
1352    tr_bool enabled;
1353    tr_bool changed;
1354
1355    assert( t->isClockEnabled );
1356
1357    testTurtleTime( t, &enabled, &changed );
1358
1359    if( changed )
1360    {
1361        tr_inf( "Time to turn %s turtle mode!", (enabled?"on":"off") );
1362        useAltSpeed( s, t, enabled, FALSE );
1363    }
1364}
1365
1366/* Called after the turtle's fields are loaded from an outside source.
1367 * It initializes the implementation fields
1368 * and turns on turtle mode if the clock settings say to. */
1369static void
1370turtleBootstrap( tr_session * session, struct tr_turtle_info * turtle )
1371{
1372    turtle->changedByUser = FALSE;
1373
1374    tr_bitfieldConstruct( &turtle->minutes, MINUTES_PER_WEEK );
1375
1376    turtleUpdateTable( turtle );
1377
1378    if( turtle->isClockEnabled )
1379        testTurtleTime( turtle, &turtle->isEnabled, NULL );
1380
1381    altSpeedToggled( session );
1382}
1383
1384/***
1385****  Primary session speed limits
1386***/
1387
1388void
1389tr_sessionSetSpeedLimit_Bps( tr_session * s, tr_direction d, int Bps )
1390{
1391    assert( tr_isSession( s ) );
1392    assert( tr_isDirection( d ) );
1393    assert( Bps >= 0 );
1394
1395    s->speedLimit_Bps[d] = Bps;
1396
1397    updateBandwidth( s, d );
1398}
1399void
1400tr_sessionSetSpeedLimit_KBps( tr_session * s, tr_direction d, int KBps )
1401{
1402    tr_sessionSetSpeedLimit_Bps( s, d, toSpeedBytes( KBps ) );
1403}
1404
1405int
1406tr_sessionGetSpeedLimit_Bps( const tr_session * s, tr_direction d )
1407{
1408    assert( tr_isSession( s ) );
1409    assert( tr_isDirection( d ) );
1410
1411    return s->speedLimit_Bps[d];
1412}
1413int
1414tr_sessionGetSpeedLimit_KBps( const tr_session * s, tr_direction d )
1415{
1416    return toSpeedKBps( tr_sessionGetSpeedLimit_Bps( s, d ) );
1417}
1418
1419void
1420tr_sessionLimitSpeed( tr_session * s, tr_direction d, tr_bool b )
1421{
1422    assert( tr_isSession( s ) );
1423    assert( tr_isDirection( d ) );
1424    assert( tr_isBool( b ) );
1425
1426    s->speedLimitEnabled[d] = b;
1427
1428    updateBandwidth( s, d );
1429}
1430
1431tr_bool
1432tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1433{
1434    assert( tr_isSession( s ) );
1435    assert( tr_isDirection( d ) );
1436
1437    return s->speedLimitEnabled[d];
1438}
1439
1440/***
1441****  Alternative speed limits that are used during scheduled times
1442***/
1443
1444void
1445tr_sessionSetAltSpeed_Bps( tr_session * s, tr_direction d, int Bps )
1446{
1447    assert( tr_isSession( s ) );
1448    assert( tr_isDirection( d ) );
1449    assert( Bps >= 0 );
1450
1451    s->turtle.speedLimit_Bps[d] = Bps;
1452
1453    updateBandwidth( s, d );
1454}
1455
1456void
1457tr_sessionSetAltSpeed_KBps( tr_session * s, tr_direction d, int KBps )
1458{
1459    tr_sessionSetAltSpeed_Bps( s, d, toSpeedBytes( KBps ) );
1460}
1461
1462int
1463tr_sessionGetAltSpeed_Bps( const tr_session * s, tr_direction d )
1464{
1465    assert( tr_isSession( s ) );
1466    assert( tr_isDirection( d ) );
1467
1468    return s->turtle.speedLimit_Bps[d];
1469}
1470int
1471tr_sessionGetAltSpeed_KBps( const tr_session * s, tr_direction d )
1472{
1473    return toSpeedKBps( tr_sessionGetAltSpeed_Bps( s, d ) );
1474}
1475
1476static void
1477userPokedTheClock( tr_session * s, struct tr_turtle_info * t )
1478{
1479    tr_dbg( "Refreshing the turtle mode clock due to user changes" );
1480
1481    turtleUpdateTable( t );
1482
1483    if( t->isClockEnabled )
1484    {
1485        tr_bool enabled, changed;
1486        testTurtleTime( t, &enabled, &changed );
1487        useAltSpeed( s, t, enabled, TRUE );
1488    }
1489}
1490
1491void
1492tr_sessionUseAltSpeedTime( tr_session * s, tr_bool b )
1493{
1494    struct tr_turtle_info * t = &s->turtle;
1495
1496    assert( tr_isSession( s ) );
1497    assert( tr_isBool ( b ) );
1498
1499    if( t->isClockEnabled != b ) {
1500        t->isClockEnabled = b;
1501        userPokedTheClock( s, t );
1502    }
1503}
1504
1505tr_bool
1506tr_sessionUsesAltSpeedTime( const tr_session * s )
1507{
1508    assert( tr_isSession( s ) );
1509
1510    return s->turtle.isClockEnabled;
1511}
1512
1513void
1514tr_sessionSetAltSpeedBegin( tr_session * s, int minute )
1515{
1516    assert( tr_isSession( s ) );
1517    assert( 0<=minute && minute<(60*24) );
1518
1519    if( s->turtle.beginMinute != minute ) {
1520        s->turtle.beginMinute = minute;
1521        userPokedTheClock( s, &s->turtle );
1522    }
1523}
1524
1525int
1526tr_sessionGetAltSpeedBegin( const tr_session * s )
1527{
1528    assert( tr_isSession( s ) );
1529
1530    return s->turtle.beginMinute;
1531}
1532
1533void
1534tr_sessionSetAltSpeedEnd( tr_session * s, int minute )
1535{
1536    assert( tr_isSession( s ) );
1537    assert( 0<=minute && minute<(60*24) );
1538
1539    if( s->turtle.endMinute != minute ) {
1540        s->turtle.endMinute = minute;
1541        userPokedTheClock( s, &s->turtle );
1542    }
1543}
1544
1545int
1546tr_sessionGetAltSpeedEnd( const tr_session * s )
1547{
1548    assert( tr_isSession( s ) );
1549
1550    return s->turtle.endMinute;
1551}
1552
1553void
1554tr_sessionSetAltSpeedDay( tr_session * s, tr_sched_day days )
1555{
1556    assert( tr_isSession( s ) );
1557
1558    if( s->turtle.days != days ) {
1559        s->turtle.days = days;
1560        userPokedTheClock( s, &s->turtle );
1561    }
1562}
1563
1564tr_sched_day
1565tr_sessionGetAltSpeedDay( const tr_session * s )
1566{
1567    assert( tr_isSession( s ) );
1568
1569    return s->turtle.days;
1570}
1571
1572void
1573tr_sessionUseAltSpeed( tr_session * session, tr_bool enabled )
1574{
1575    useAltSpeed( session, &session->turtle, enabled, TRUE );
1576}
1577
1578tr_bool
1579tr_sessionUsesAltSpeed( const tr_session * s )
1580{
1581    assert( tr_isSession( s ) );
1582
1583    return s->turtle.isEnabled;
1584}
1585
1586void
1587tr_sessionSetAltSpeedFunc( tr_session       * session,
1588                           tr_altSpeedFunc    func,
1589                           void             * userData )
1590{
1591    assert( tr_isSession( session ) );
1592
1593    session->turtle.callback = func;
1594    session->turtle.callbackUserData = userData;
1595}
1596
1597void
1598tr_sessionClearAltSpeedFunc( tr_session * session )
1599{
1600    tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1601}
1602
1603/***
1604****
1605***/
1606
1607void
1608tr_sessionSetPeerLimit( tr_session * session, uint16_t maxGlobalPeers )
1609{
1610    assert( tr_isSession( session ) );
1611
1612    tr_fdSetPeerLimit( session, maxGlobalPeers );
1613}
1614
1615uint16_t
1616tr_sessionGetPeerLimit( const tr_session * session )
1617{
1618    assert( tr_isSession( session ) );
1619
1620    return tr_fdGetPeerLimit( session );
1621}
1622
1623void
1624tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
1625{
1626    assert( tr_isSession( session ) );
1627
1628    session->peerLimitPerTorrent = n;
1629}
1630
1631uint16_t
1632tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1633{
1634    assert( tr_isSession( session ) );
1635
1636    return session->peerLimitPerTorrent;
1637}
1638
1639/***
1640****
1641***/
1642
1643void
1644tr_sessionSetPaused( tr_session * session, tr_bool isPaused )
1645{
1646    assert( tr_isSession( session ) );
1647
1648    session->pauseAddedTorrent = isPaused;
1649}
1650
1651tr_bool
1652tr_sessionGetPaused( const tr_session * session )
1653{
1654    assert( tr_isSession( session ) );
1655
1656    return session->pauseAddedTorrent;
1657}
1658
1659void
1660tr_sessionSetDeleteSource( tr_session * session, tr_bool deleteSource )
1661{
1662    assert( tr_isSession( session ) );
1663
1664    session->deleteSourceTorrent = deleteSource;
1665}
1666
1667tr_bool
1668tr_sessionGetDeleteSource( const tr_session * session )
1669{
1670    assert( tr_isSession( session ) );
1671
1672    return session->deleteSourceTorrent;
1673}
1674
1675/***
1676****
1677***/
1678
1679int
1680tr_sessionGetPieceSpeed_Bps( const tr_session * session, tr_direction dir )
1681{
1682    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed_Bps( session->bandwidth, 0, dir ) : 0;
1683}
1684
1685int
1686tr_sessionGetRawSpeed_Bps( const tr_session * session, tr_direction dir )
1687{
1688    return tr_isSession( session ) ? tr_bandwidthGetRawSpeed_Bps( session->bandwidth, 0, dir ) : 0;
1689}
1690double
1691tr_sessionGetRawSpeed_KBps( const tr_session * session, tr_direction dir )
1692{
1693    return toSpeedKBps( tr_sessionGetRawSpeed_Bps( session, dir ) );
1694}
1695
1696
1697int
1698tr_sessionCountTorrents( const tr_session * session )
1699{
1700    return tr_isSession( session ) ? session->torrentCount : 0;
1701}
1702
1703static int
1704compareTorrentByCur( const void * va, const void * vb )
1705{
1706    const tr_torrent * a = *(const tr_torrent**)va;
1707    const tr_torrent * b = *(const tr_torrent**)vb;
1708    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1709    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1710
1711    if( aCur != bCur )
1712        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1713
1714    return 0;
1715}
1716
1717static void closeBlocklists( tr_session * );
1718
1719static void
1720sessionCloseImpl( void * vsession )
1721{
1722    tr_session *  session = vsession;
1723    tr_torrent *  tor;
1724    int           i, n;
1725    tr_torrent ** torrents;
1726
1727    assert( tr_isSession( session ) );
1728
1729    free_incoming_peer_port( session );
1730
1731    if( session->isLPDEnabled )
1732        tr_lpdUninit( session );
1733
1734    tr_utpClose( session );
1735    tr_udpUninit( session );
1736
1737    event_free( session->saveTimer );
1738    session->saveTimer = NULL;
1739
1740    event_free( session->nowTimer );
1741    session->nowTimer = NULL;
1742
1743    tr_verifyClose( session );
1744    tr_sharedClose( session );
1745    tr_rpcClose( &session->rpcServer );
1746
1747    /* Close the torrents. Get the most active ones first so that
1748     * if we can't get them all closed in a reasonable amount of time,
1749     * at least we get the most important ones first. */
1750    tor = NULL;
1751    n = session->torrentCount;
1752    torrents = tr_new( tr_torrent *, session->torrentCount );
1753    for( i = 0; i < n; ++i )
1754        torrents[i] = tor = tr_torrentNext( session, tor );
1755    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1756    for( i = 0; i < n; ++i )
1757        tr_torrentFree( torrents[i] );
1758    tr_free( torrents );
1759
1760    tr_cacheFree( session->cache );
1761    session->cache = NULL;
1762    tr_announcerClose( session );
1763    tr_statsClose( session );
1764    tr_peerMgrFree( session->peerMgr );
1765    tr_webClose( session, TR_WEB_CLOSE_WHEN_IDLE );
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 )
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 tr_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_bandwidthFree( 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->buffer );
1844    tr_free( session->tag );
1845    tr_free( session->configDir );
1846    tr_free( session->resumeDir );
1847    tr_free( session->torrentDir );
1848    tr_free( session->downloadDir );
1849    tr_free( session->incompleteDir );
1850    tr_free( session->blocklist_url );
1851    tr_free( session->peer_congestion_algorithm );
1852    tr_free( session );
1853}
1854
1855tr_torrent **
1856tr_sessionLoadTorrents( tr_session * session,
1857                        tr_ctor    * ctor,
1858                        int        * setmeCount )
1859{
1860    int           i, n = 0;
1861    struct stat   sb;
1862    DIR *         odir = NULL;
1863    const char *  dirname = tr_getTorrentDir( session );
1864    tr_torrent ** torrents;
1865    tr_list *     l = NULL, *list = NULL;
1866
1867    assert( tr_isSession( session ) );
1868
1869    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1870
1871    if( !stat( dirname, &sb )
1872      && S_ISDIR( sb.st_mode )
1873      && ( ( odir = opendir ( dirname ) ) ) )
1874    {
1875        struct dirent *d;
1876        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1877        {
1878            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
1879            {
1880                tr_torrent * tor;
1881                char * path = tr_buildPath( dirname, d->d_name, NULL );
1882                tr_ctorSetMetainfoFromFile( ctor, path );
1883                if(( tor = tr_torrentNew( ctor, NULL )))
1884                {
1885                    tr_list_append( &list, tor );
1886                    ++n;
1887                }
1888                tr_free( path );
1889            }
1890        }
1891        closedir( odir );
1892    }
1893
1894    torrents = tr_new( tr_torrent *, n );
1895    for( i = 0, l = list; l != NULL; l = l->next )
1896        torrents[i++] = (tr_torrent*) l->data;
1897    assert( i == n );
1898
1899    tr_list_free( &list, NULL );
1900
1901    if( n )
1902        tr_inf( _( "Loaded %d torrents" ), n );
1903
1904    if( setmeCount )
1905        *setmeCount = n;
1906    return torrents;
1907}
1908
1909/***
1910****
1911***/
1912
1913void
1914tr_sessionSetPexEnabled( tr_session * session,
1915                         tr_bool      enabled )
1916{
1917    assert( tr_isSession( session ) );
1918
1919    session->isPexEnabled = enabled != 0;
1920}
1921
1922tr_bool
1923tr_sessionIsPexEnabled( const tr_session * session )
1924{
1925    assert( tr_isSession( session ) );
1926
1927    return session->isPexEnabled;
1928}
1929
1930tr_bool
1931tr_sessionAllowsDHT( const tr_session * session UNUSED )
1932{
1933    return tr_sessionIsDHTEnabled( session );
1934}
1935
1936tr_bool
1937tr_sessionIsDHTEnabled( const tr_session * session )
1938{
1939    assert( tr_isSession( session ) );
1940
1941    return session->isDHTEnabled;
1942}
1943
1944static void
1945toggleDHTImpl(  void * data )
1946{
1947    tr_session * session = data;
1948    assert( tr_isSession( session ) );
1949
1950    tr_udpUninit( session );
1951    session->isDHTEnabled = !session->isDHTEnabled;
1952    tr_udpInit( session );
1953}
1954
1955void
1956tr_sessionSetDHTEnabled( tr_session * session, tr_bool enabled )
1957{
1958    assert( tr_isSession( session ) );
1959    assert( tr_isBool( enabled ) );
1960
1961    if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1962        tr_runInEventThread( session, toggleDHTImpl, session );
1963}
1964
1965/***
1966****
1967***/
1968
1969tr_bool
1970tr_sessionIsUTPEnabled( const tr_session * session )
1971{
1972    assert( tr_isSession( session ) );
1973
1974#ifdef WITH_UTP
1975    return session->isUTPEnabled;
1976#else
1977    return FALSE;
1978#endif
1979}
1980
1981static void
1982toggle_utp(  void * data )
1983{
1984    tr_session * session = data;
1985    assert( tr_isSession( session ) );
1986
1987    session->isUTPEnabled = !session->isUTPEnabled;
1988
1989    tr_udpSetSocketBuffers( session );
1990
1991    /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
1992       explanation. */
1993}
1994
1995void
1996tr_sessionSetUTPEnabled( tr_session * session, tr_bool enabled )
1997{
1998    assert( tr_isSession( session ) );
1999    assert( tr_isBool( enabled ) );
2000
2001    if( ( enabled != 0 ) != ( session->isUTPEnabled != 0 ) )
2002        tr_runInEventThread( session, toggle_utp, session );
2003}
2004
2005/***
2006****
2007***/
2008
2009static void
2010toggleLPDImpl(  void * data )
2011{
2012    tr_session * session = data;
2013    assert( tr_isSession( session ) );
2014
2015    if( session->isLPDEnabled )
2016        tr_lpdUninit( session );
2017
2018    session->isLPDEnabled = !session->isLPDEnabled;
2019
2020    if( session->isLPDEnabled )
2021        tr_lpdInit( session, &session->public_ipv4->addr );
2022}
2023
2024void
2025tr_sessionSetLPDEnabled( tr_session * session, tr_bool enabled )
2026{
2027    assert( tr_isSession( session ) );
2028    assert( tr_isBool( enabled ) );
2029
2030    if( ( enabled != 0 ) != ( session->isLPDEnabled != 0 ) )
2031        tr_runInEventThread( session, toggleLPDImpl, session );
2032}
2033
2034tr_bool
2035tr_sessionIsLPDEnabled( const tr_session * session )
2036{
2037    assert( tr_isSession( session ) );
2038
2039    return session->isLPDEnabled;
2040}
2041
2042tr_bool
2043tr_sessionAllowsLPD( const tr_session * session )
2044{
2045    return tr_sessionIsLPDEnabled( session );
2046}
2047
2048/***
2049****
2050***/
2051
2052void
2053tr_sessionSetCacheLimit_MB( tr_session * session, int max_bytes )
2054{
2055    assert( tr_isSession( session ) );
2056
2057    tr_cacheSetLimit( session->cache, toMemBytes( max_bytes ) );
2058}
2059
2060int
2061tr_sessionGetCacheLimit_MB( const tr_session * session )
2062{
2063    assert( tr_isSession( session ) );
2064
2065    return toMemMB( tr_cacheGetLimit( session->cache ) );
2066}
2067
2068/***
2069****
2070***/
2071
2072void
2073tr_sessionSetLazyBitfieldEnabled( tr_session * session,
2074                                  tr_bool      enabled )
2075{
2076    assert( tr_isSession( session ) );
2077
2078    session->useLazyBitfield = enabled != 0;
2079}
2080
2081tr_bool
2082tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
2083{
2084    assert( tr_isSession( session ) );
2085
2086    return session->useLazyBitfield;
2087}
2088
2089/***
2090****
2091***/
2092
2093struct port_forwarding_data
2094{
2095    tr_bool enabled;
2096    struct tr_shared * shared;
2097};
2098
2099static void
2100setPortForwardingEnabled( void * vdata )
2101{
2102    struct port_forwarding_data * data = vdata;
2103    tr_sharedTraversalEnable( data->shared, data->enabled );
2104    tr_free( data );
2105}
2106
2107void
2108tr_sessionSetPortForwardingEnabled( tr_session  * session, tr_bool enabled )
2109{
2110    struct port_forwarding_data * d;
2111    d = tr_new0( struct port_forwarding_data, 1 );
2112    d->shared = session->shared;
2113    d->enabled = enabled;
2114    tr_runInEventThread( session, setPortForwardingEnabled, d );
2115}
2116
2117tr_bool
2118tr_sessionIsPortForwardingEnabled( const tr_session * session )
2119{
2120    assert( tr_isSession( session ) );
2121
2122    return tr_sharedTraversalIsEnabled( session->shared );
2123}
2124
2125/***
2126****
2127***/
2128
2129static int
2130tr_stringEndsWith( const char * str, const char * end )
2131{
2132    const size_t slen = strlen( str );
2133    const size_t elen = strlen( end );
2134
2135    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
2136}
2137
2138static void
2139loadBlocklists( tr_session * session )
2140{
2141    int         binCount = 0;
2142    int         newCount = 0;
2143    struct stat sb;
2144    char      * dirname;
2145    DIR *       odir = NULL;
2146    tr_list *   list = NULL;
2147    const tr_bool   isEnabled = session->isBlocklistEnabled;
2148
2149    /* walk through the directory and find blocklists */
2150    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
2151    if( !stat( dirname,
2152               &sb ) && S_ISDIR( sb.st_mode )
2153      && ( ( odir = opendir( dirname ) ) ) )
2154    {
2155        struct dirent *d;
2156        for( d = readdir( odir ); d; d = readdir( odir ) )
2157        {
2158            char * filename;
2159
2160            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
2161                                                      */
2162                continue;
2163
2164            filename = tr_buildPath( dirname, d->d_name, NULL );
2165
2166            if( tr_stringEndsWith( filename, ".bin" ) )
2167            {
2168                /* if we don't already have this blocklist, add it */
2169                if( !tr_list_find( list, filename,
2170                                   (TrListCompareFunc)strcmp ) )
2171                {
2172                    tr_list_append( &list,
2173                                   _tr_blocklistNew( filename, isEnabled ) );
2174                    ++binCount;
2175                }
2176            }
2177            else
2178            {
2179                /* strip out the file suffix, if there is one, and add ".bin"
2180                  instead */
2181                tr_blocklist * b;
2182                const char *   dot = strrchr( d->d_name, '.' );
2183                const int      len = dot ? dot - d->d_name
2184                                         : (int)strlen( d->d_name );
2185                char         * tmp = tr_strdup_printf(
2186                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
2187                                        dirname, len, len, d->d_name );
2188                b = _tr_blocklistNew( tmp, isEnabled );
2189                _tr_blocklistSetContent( b, filename );
2190                tr_list_append( &list, b );
2191                ++newCount;
2192                tr_free( tmp );
2193            }
2194
2195            tr_free( filename );
2196        }
2197
2198        closedir( odir );
2199    }
2200
2201    session->blocklists = list;
2202
2203    if( binCount )
2204        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
2205    if( newCount )
2206        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
2207
2208    tr_free( dirname );
2209}
2210
2211static void
2212closeBlocklists( tr_session * session )
2213{
2214    tr_list_free( &session->blocklists,
2215                  (TrListForeachFunc)_tr_blocklistFree );
2216}
2217
2218void
2219tr_sessionReloadBlocklists( tr_session * session )
2220{
2221    closeBlocklists( session );
2222    loadBlocklists( session );
2223
2224    tr_peerMgrOnBlocklistChanged( session->peerMgr );
2225}
2226
2227int
2228tr_blocklistGetRuleCount( const tr_session * session )
2229{
2230    int       n = 0;
2231    tr_list * l;
2232
2233    assert( tr_isSession( session ) );
2234
2235    for( l = session->blocklists; l; l = l->next )
2236        n += _tr_blocklistGetRuleCount( l->data );
2237    return n;
2238}
2239
2240tr_bool
2241tr_blocklistIsEnabled( const tr_session * session )
2242{
2243    assert( tr_isSession( session ) );
2244
2245    return session->isBlocklistEnabled;
2246}
2247
2248void
2249tr_blocklistSetEnabled( tr_session * session,
2250                        tr_bool      isEnabled )
2251{
2252    tr_list * l;
2253
2254    assert( tr_isSession( session ) );
2255
2256    session->isBlocklistEnabled = isEnabled != 0;
2257
2258    for( l=session->blocklists; l!=NULL; l=l->next )
2259        _tr_blocklistSetEnabled( l->data, isEnabled );
2260}
2261
2262tr_bool
2263tr_blocklistExists( const tr_session * session )
2264{
2265    assert( tr_isSession( session ) );
2266
2267    return session->blocklists != NULL;
2268}
2269
2270int
2271tr_blocklistSetContent( tr_session * session, const char * contentFilename )
2272{
2273    tr_list * l;
2274    int ruleCount;
2275    tr_blocklist * b;
2276    const char * defaultName = DEFAULT_BLOCKLIST_FILENAME;
2277    tr_sessionLock( session );
2278
2279    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
2280        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
2281                               defaultName ) )
2282            b = l->data;
2283
2284    if( !b )
2285    {
2286        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
2287        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
2288        tr_list_append( &session->blocklists, b );
2289        tr_free( path );
2290    }
2291
2292    ruleCount = _tr_blocklistSetContent( b, contentFilename );
2293    tr_sessionUnlock( session );
2294    return ruleCount;
2295}
2296
2297tr_bool
2298tr_sessionIsAddressBlocked( const tr_session * session,
2299                            const tr_address * addr )
2300{
2301    tr_list * l;
2302
2303    assert( tr_isSession( session ) );
2304
2305    for( l = session->blocklists; l; l = l->next )
2306        if( _tr_blocklistHasAddress( l->data, addr ) )
2307            return TRUE;
2308    return FALSE;
2309}
2310
2311void
2312tr_blocklistSetURL( tr_session * session, const char * url )
2313{
2314    if( session->blocklist_url != url )
2315    {
2316        tr_free( session->blocklist_url );
2317        session->blocklist_url = tr_strdup( url );
2318    }
2319}
2320
2321const char *
2322tr_blocklistGetURL ( const tr_session * session )
2323{
2324    return session->blocklist_url;
2325}
2326
2327
2328/***
2329****
2330***/
2331
2332static void
2333metainfoLookupInit( tr_session * session )
2334{
2335    struct stat  sb;
2336    const char * dirname = tr_getTorrentDir( session );
2337    DIR *        odir = NULL;
2338    tr_ctor *    ctor = NULL;
2339    tr_benc * lookup;
2340    int n = 0;
2341
2342    assert( tr_isSession( session ) );
2343
2344    /* walk through the directory and find the mappings */
2345    lookup = tr_new0( tr_benc, 1 );
2346    tr_bencInitDict( lookup, 0 );
2347    ctor = tr_ctorNew( session );
2348    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
2349    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
2350    {
2351        struct dirent *d;
2352        while(( d = readdir( odir )))
2353        {
2354            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
2355            {
2356                tr_info inf;
2357                char * path = tr_buildPath( dirname, d->d_name, NULL );
2358                tr_ctorSetMetainfoFromFile( ctor, path );
2359                if( !tr_torrentParse( ctor, &inf ) )
2360                {
2361                    ++n;
2362                    tr_bencDictAddStr( lookup, inf.hashString, path );
2363                }
2364                tr_free( path );
2365            }
2366        }
2367        closedir( odir );
2368    }
2369    tr_ctorFree( ctor );
2370
2371    session->metainfoLookup = lookup;
2372    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
2373}
2374
2375const char*
2376tr_sessionFindTorrentFile( const tr_session * session,
2377                           const char       * hashString )
2378{
2379    const char * filename = NULL;
2380    if( !session->metainfoLookup )
2381        metainfoLookupInit( (tr_session*)session );
2382    tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
2383    return filename;
2384}
2385
2386void
2387tr_sessionSetTorrentFile( tr_session * session,
2388                          const char * hashString,
2389                          const char * filename )
2390{
2391    /* since we walk session->configDir/torrents/ to build the lookup table,
2392     * and tr_sessionSetTorrentFile() is just to tell us there's a new file
2393     * in that same directory, we don't need to do anything here if the
2394     * lookup table hasn't been built yet */
2395    if( session->metainfoLookup )
2396        tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
2397}
2398
2399/***
2400****
2401***/
2402
2403void
2404tr_sessionSetRPCEnabled( tr_session * session,
2405                         tr_bool      isEnabled )
2406{
2407    assert( tr_isSession( session ) );
2408
2409    tr_rpcSetEnabled( session->rpcServer, isEnabled );
2410}
2411
2412tr_bool
2413tr_sessionIsRPCEnabled( const tr_session * session )
2414{
2415    assert( tr_isSession( session ) );
2416
2417    return tr_rpcIsEnabled( session->rpcServer );
2418}
2419
2420void
2421tr_sessionSetRPCPort( tr_session * session,
2422                      tr_port      port )
2423{
2424    assert( tr_isSession( session ) );
2425
2426    tr_rpcSetPort( session->rpcServer, port );
2427}
2428
2429tr_port
2430tr_sessionGetRPCPort( const tr_session * session )
2431{
2432    assert( tr_isSession( session ) );
2433
2434    return tr_rpcGetPort( session->rpcServer );
2435}
2436
2437void
2438tr_sessionSetRPCUrl( tr_session * session,
2439                     const char * url )
2440{
2441    assert( tr_isSession( session ) );
2442
2443    tr_rpcSetUrl( session->rpcServer, url );
2444}
2445
2446const char*
2447tr_sessionGetRPCUrl( const tr_session * session )
2448{
2449    assert( tr_isSession( session ) );
2450
2451    return tr_rpcGetUrl( session->rpcServer );
2452}
2453
2454void
2455tr_sessionSetRPCCallback( tr_session * session,
2456                          tr_rpc_func  func,
2457                          void *       user_data )
2458{
2459    assert( tr_isSession( session ) );
2460
2461    session->rpc_func = func;
2462    session->rpc_func_user_data = user_data;
2463}
2464
2465void
2466tr_sessionSetRPCWhitelist( tr_session * session,
2467                           const char * whitelist )
2468{
2469    assert( tr_isSession( session ) );
2470
2471    tr_rpcSetWhitelist( session->rpcServer, whitelist );
2472}
2473
2474const char*
2475tr_sessionGetRPCWhitelist( const tr_session * session )
2476{
2477    assert( tr_isSession( session ) );
2478
2479    return tr_rpcGetWhitelist( session->rpcServer );
2480}
2481
2482void
2483tr_sessionSetRPCWhitelistEnabled( tr_session * session,
2484                                  tr_bool      isEnabled )
2485{
2486    assert( tr_isSession( session ) );
2487
2488    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
2489}
2490
2491tr_bool
2492tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
2493{
2494    assert( tr_isSession( session ) );
2495
2496    return tr_rpcGetWhitelistEnabled( session->rpcServer );
2497}
2498
2499
2500void
2501tr_sessionSetRPCPassword( tr_session * session,
2502                          const char * password )
2503{
2504    assert( tr_isSession( session ) );
2505
2506    tr_rpcSetPassword( session->rpcServer, password );
2507}
2508
2509const char*
2510tr_sessionGetRPCPassword( const tr_session * session )
2511{
2512    assert( tr_isSession( session ) );
2513
2514    return tr_rpcGetPassword( session->rpcServer );
2515}
2516
2517void
2518tr_sessionSetRPCUsername( tr_session * session,
2519                          const char * username )
2520{
2521    assert( tr_isSession( session ) );
2522
2523    tr_rpcSetUsername( session->rpcServer, username );
2524}
2525
2526const char*
2527tr_sessionGetRPCUsername( const tr_session * session )
2528{
2529    assert( tr_isSession( session ) );
2530
2531    return tr_rpcGetUsername( session->rpcServer );
2532}
2533
2534void
2535tr_sessionSetRPCPasswordEnabled( tr_session * session,
2536                                 tr_bool      isEnabled )
2537{
2538    assert( tr_isSession( session ) );
2539
2540    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2541}
2542
2543tr_bool
2544tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2545{
2546    assert( tr_isSession( session ) );
2547
2548    return tr_rpcIsPasswordEnabled( session->rpcServer );
2549}
2550
2551const char *
2552tr_sessionGetRPCBindAddress( const tr_session * session )
2553{
2554    assert( tr_isSession( session ) );
2555
2556    return tr_rpcGetBindAddress( session->rpcServer );
2557}
2558
2559/****
2560*****
2561****/
2562
2563tr_bool
2564tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session )
2565{
2566    assert( tr_isSession( session ) );
2567
2568    return session->isTorrentDoneScriptEnabled;
2569}
2570
2571void
2572tr_sessionSetTorrentDoneScriptEnabled( tr_session * session, tr_bool isEnabled )
2573{
2574    assert( tr_isSession( session ) );
2575    assert( tr_isBool( isEnabled ) );
2576
2577    session->isTorrentDoneScriptEnabled = isEnabled;
2578}
2579
2580const char *
2581tr_sessionGetTorrentDoneScript( const tr_session * session )
2582{
2583    assert( tr_isSession( session ) );
2584
2585    return session->torrentDoneScript;
2586}
2587
2588void
2589tr_sessionSetTorrentDoneScript( tr_session * session, const char * scriptFilename )
2590{
2591    assert( tr_isSession( session ) );
2592
2593    if( session->torrentDoneScript != scriptFilename )
2594    {
2595        tr_free( session->torrentDoneScript );
2596        session->torrentDoneScript = tr_strdup( scriptFilename );
2597    }
2598}
2599
2600/***
2601****
2602***/
2603
2604void
2605tr_sessionSetWebConfigFunc( tr_session * session, void (*func)(tr_session*, void*, const char* ) )
2606{
2607    session->curl_easy_config_func = func;
2608}
Note: See TracBrowser for help on using the repository browser.