source: trunk/libtransmission/session.c @ 12183

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

(trunk libT) as a followup to r12182, move LPD's periodic upkeep timer into the tr-lpd.c module where it can be started & stopped with the pre-existing tr_lpdInit() and tr_lpdUninit() functions.

  • 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 12183 2011-03-17 13:16:23Z 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    const time_t now = time( NULL );
613
614    assert( tr_isSession( session ) );
615    assert( session->nowTimer != NULL );
616
617    /**
618    ***  tr_session things to do once per second
619    **/
620
621    tr_timeUpdate( now );
622
623    tr_dhtUpkeep( session );
624
625    if( session->turtle.isClockEnabled )
626        turtleCheckClock( session, &session->turtle );
627
628    while(( tor = tr_torrentNext( session, tor ))) {
629        if( tor->isRunning ) {
630            if( tr_torrentIsSeed( tor ) )
631                ++tor->secondsSeeding;
632            else
633                ++tor->secondsDownloading;
634        }
635    }
636
637    /**
638    ***  Set the timer
639    **/
640
641    /* schedule the next timer for right after the next second begins */
642    gettimeofday( &tv, NULL );
643    usec = 1000000 - tv.tv_usec;
644    if( usec > max ) usec = max;
645    if( usec < min ) usec = min;
646    tr_timerAdd( session->nowTimer, 0, usec );
647    /* fprintf( stderr, "time %zu sec, %zu microsec\n", (size_t)tr_time(), (size_t)tv.tv_usec ); */
648}
649
650static void loadBlocklists( tr_session * session );
651
652static void
653tr_sessionInitImpl( void * vdata )
654{
655    tr_benc settings;
656    struct init_data * data = vdata;
657    tr_benc * clientSettings = data->clientSettings;
658    tr_session * session = data->session;
659
660    assert( tr_amInEventThread( session ) );
661    assert( tr_bencIsDict( clientSettings ) );
662
663    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p",
664            session->bandwidth );
665
666    tr_bencInitDict( &settings, 0 );
667    tr_sessionGetDefaultSettings( data->configDir, &settings );
668    tr_bencMergeDicts( &settings, clientSettings );
669
670    assert( session->event_base != NULL );
671    session->nowTimer = evtimer_new( session->event_base, onNowTimer, session );
672    onNowTimer( 0, 0, session );
673
674#ifndef WIN32
675    /* Don't exit when writing on a broken socket */
676    signal( SIGPIPE, SIG_IGN );
677#endif
678
679    tr_setMessageQueuing( data->messageQueuingEnabled );
680
681    tr_setConfigDir( session, data->configDir );
682
683    session->peerMgr = tr_peerMgrNew( session );
684
685    session->shared = tr_sharedInit( session );
686
687    /**
688    ***  Blocklist
689    **/
690
691    {
692        char * filename = tr_buildPath( session->configDir, "blocklists", NULL );
693        tr_mkdirp( filename, 0777 );
694        tr_free( filename );
695        loadBlocklists( session );
696    }
697
698    assert( tr_isSession( session ) );
699
700    session->saveTimer = evtimer_new( session->event_base, onSaveTimer, session );
701    tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
702
703    tr_announcerInit( session );
704
705    /* first %s is the application name
706       second %s is the version number */
707    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
708
709    tr_statsInit( session );
710
711    tr_webInit( session );
712
713    tr_sessionSet( session, &settings );
714
715    tr_udpInit( session );
716
717    if( session->isLPDEnabled )
718        tr_lpdInit( session, &session->public_ipv4->addr );
719
720    /* cleanup */
721    tr_bencFree( &settings );
722    data->done = TRUE;
723}
724
725static void turtleBootstrap( tr_session *, struct tr_turtle_info * );
726static void setPeerPort( tr_session * session, tr_port port );
727
728static void
729sessionSetImpl( void * vdata )
730{
731    int64_t i;
732    double  d;
733    tr_bool boolVal;
734    const char * str;
735    struct tr_bindinfo b;
736    struct init_data * data = vdata;
737    tr_session * session = data->session;
738    tr_benc * settings = data->clientSettings;
739    struct tr_turtle_info * turtle = &session->turtle;
740
741    assert( tr_isSession( session ) );
742    assert( tr_bencIsDict( settings ) );
743    assert( tr_amInEventThread( session ) );
744
745    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MSGLEVEL, &i ) )
746        tr_setMessageLevel( i );
747
748    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_UMASK, &i ) ) {
749        session->umask = (mode_t)i;
750        umask( session->umask );
751    }
752
753    /* misc features */
754    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
755        tr_sessionSetCacheLimit_MB( session, i );
756    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
757        tr_sessionSetPeerLimitPerTorrent( session, i );
758    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal ) )
759        tr_sessionSetPexEnabled( session, boolVal );
760    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_DHT_ENABLED, &boolVal ) )
761        tr_sessionSetDHTEnabled( session, boolVal );
762    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_UTP_ENABLED, &boolVal ) )
763        tr_sessionSetUTPEnabled( session, boolVal );
764    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LPD_ENABLED, &boolVal ) )
765        tr_sessionSetLPDEnabled( session, boolVal );
766    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ENCRYPTION, &i ) )
767        tr_sessionSetEncryption( session, i );
768    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &str ) )
769        session->peerSocketTOS = parse_tos( str );
770    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_PEER_CONGESTION_ALGORITHM, &str ) )
771        session->peer_congestion_algorithm = tr_strdup(str);
772    else
773        session->peer_congestion_algorithm = tr_strdup("");
774    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal ) )
775        tr_blocklistSetEnabled( session, boolVal );
776    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_BLOCKLIST_URL, &str ) )
777        tr_blocklistSetURL( session, str );
778    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_START, &boolVal ) )
779        tr_sessionSetPaused( session, !boolVal );
780    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_TRASH_ORIGINAL, &boolVal) )
781        tr_sessionSetDeleteSource( session, boolVal );
782
783    /* files and directories */
784    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PREFETCH_ENABLED, &boolVal ) )
785        session->isPrefetchEnabled = boolVal;
786    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PREALLOCATION, &i ) )
787        session->preallocationMode = i;
788    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ) )
789        tr_sessionSetDownloadDir( session, str );
790    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_INCOMPLETE_DIR, &str ) )
791        tr_sessionSetIncompleteDir( session, str );
792    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, &boolVal ) )
793        tr_sessionSetIncompleteDirEnabled( session, boolVal );
794    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_RENAME_PARTIAL_FILES, &boolVal ) )
795        tr_sessionSetIncompleteFileNamingEnabled( session, boolVal );
796
797    /* rpc server */
798    if( session->rpcServer != NULL ) /* close the old one */
799        tr_rpcClose( &session->rpcServer );
800    session->rpcServer = tr_rpcInit( session, settings );
801
802    /* public addresses */
803
804    free_incoming_peer_port( session );
805
806    str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
807    tr_bencDictFindStr( settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
808    if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET ) )
809        b.addr = tr_inaddr_any;
810    b.socket = -1;
811    session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
812
813    str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
814    tr_bencDictFindStr( settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
815    if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET6 ) )
816        b.addr = tr_in6addr_any;
817    b.socket = -1;
818    session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
819
820    /* incoming peer port */
821    if( tr_bencDictFindInt ( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ) )
822        session->randomPortLow = i;
823    if( tr_bencDictFindInt ( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ) )
824        session->randomPortHigh = i;
825    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, &boolVal ) )
826        tr_sessionSetPeerPortRandomOnStart( session, boolVal );
827    if( !tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_PORT, &i ) )
828        i = session->private_peer_port;
829    setPeerPort( session, boolVal ? getRandomPort( session ) : i );
830    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PORT_FORWARDING, &boolVal ) )
831        tr_sessionSetPortForwardingEnabled( session, boolVal );
832
833    /* file and peer socket limits */
834    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &i ) )
835        tr_fdSetPeerLimit( session, i );
836    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ) )
837        tr_fdSetFileLimit( session, i );
838
839    /**
840    **/
841
842    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i ) )
843        session->uploadSlotsPerTorrent = i;
844
845    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_USPEED_KBps, &i ) )
846        tr_sessionSetSpeedLimit_KBps( session, TR_UP, i );
847    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_USPEED_ENABLED, &boolVal ) )
848        tr_sessionLimitSpeed( session, TR_UP, boolVal );
849
850    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_DSPEED_KBps, &i ) )
851        tr_sessionSetSpeedLimit_KBps( session, TR_DOWN, i );
852    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_DSPEED_ENABLED, &boolVal ) )
853        tr_sessionLimitSpeed( session, TR_DOWN, boolVal );
854
855    if( tr_bencDictFindReal( settings, TR_PREFS_KEY_RATIO, &d ) )
856        tr_sessionSetRatioLimit( session, d );
857    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_RATIO_ENABLED, &boolVal ) )
858        tr_sessionSetRatioLimited( session, boolVal );
859
860    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_IDLE_LIMIT, &i ) )
861        tr_sessionSetIdleLimit( session, i );
862    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, &boolVal ) )
863        tr_sessionSetIdleLimited( session, boolVal );
864
865    /**
866    ***  Turtle Mode
867    **/
868
869    /* update the turtle mode's fields */
870    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_UP_KBps, &i ) )
871        turtle->speedLimit_Bps[TR_UP] = toSpeedBytes( i );
872    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_DOWN_KBps, &i ) )
873        turtle->speedLimit_Bps[TR_DOWN] = toSpeedBytes( i );
874    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, &i ) )
875        turtle->beginMinute = i;
876    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_END, &i ) )
877        turtle->endMinute = i;
878    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, &i ) )
879        turtle->days = i;
880    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, &boolVal ) )
881        turtle->isClockEnabled = boolVal;
882    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_ALT_SPEED_ENABLED, &boolVal ) )
883        turtle->isEnabled = boolVal;
884    turtleBootstrap( session, turtle );
885
886    /**
887    ***  Scripts
888    **/
889
890    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, &boolVal ) )
891        tr_sessionSetTorrentDoneScriptEnabled( session, boolVal );
892    if( tr_bencDictFindStr( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, &str ) )
893        tr_sessionSetTorrentDoneScript( session, str );
894
895    data->done = TRUE;
896}
897
898void
899tr_sessionSet( tr_session * session, struct tr_benc  * settings )
900{
901    struct init_data data;
902    data.done = FALSE;
903    data.session = session;
904    data.clientSettings = settings;
905
906    /* run the rest in the libtransmission thread */
907    tr_runInEventThread( session, sessionSetImpl, &data );
908    while( !data.done )
909        tr_wait_msec( 100 );
910}
911
912/***
913****
914***/
915
916void
917tr_sessionSetDownloadDir( tr_session * session, const char * dir )
918{
919    assert( tr_isSession( session ) );
920
921    if( session->downloadDir != dir )
922    {
923        tr_free( session->downloadDir );
924        session->downloadDir = tr_strdup( dir );
925    }
926}
927
928const char *
929tr_sessionGetDownloadDir( const tr_session * session )
930{
931    assert( tr_isSession( session ) );
932
933    return session->downloadDir;
934}
935
936int64_t
937tr_sessionGetDownloadDirFreeSpace( const tr_session * session )
938{
939    assert( tr_isSession( session ) );
940
941    return tr_getFreeSpace( session->downloadDir );
942}
943
944/***
945****
946***/
947
948void
949tr_sessionSetIncompleteFileNamingEnabled( tr_session * session, tr_bool b )
950{
951    assert( tr_isSession( session ) );
952    assert( tr_isBool( b ) );
953
954    session->isIncompleteFileNamingEnabled = b;
955}
956
957tr_bool
958tr_sessionIsIncompleteFileNamingEnabled( const tr_session * session )
959{
960    assert( tr_isSession( session ) );
961
962    return session->isIncompleteFileNamingEnabled;
963}
964
965/***
966****
967***/
968
969
970void
971tr_sessionSetIncompleteDir( tr_session * session, const char * dir )
972{
973    assert( tr_isSession( session ) );
974
975    if( session->incompleteDir != dir )
976    {
977        tr_free( session->incompleteDir );
978
979        session->incompleteDir = tr_strdup( dir );
980    }
981}
982
983const char*
984tr_sessionGetIncompleteDir( const tr_session * session )
985{
986    assert( tr_isSession( session ) );
987
988    return session->incompleteDir;
989}
990
991void
992tr_sessionSetIncompleteDirEnabled( tr_session * session, tr_bool b )
993{
994    assert( tr_isSession( session ) );
995    assert( tr_isBool( b ) );
996
997    session->isIncompleteDirEnabled = b;
998}
999
1000tr_bool
1001tr_sessionIsIncompleteDirEnabled( const tr_session * session )
1002{
1003    assert( tr_isSession( session ) );
1004
1005    return session->isIncompleteDirEnabled;
1006}
1007
1008/***
1009****
1010***/
1011
1012void*
1013tr_sessionGetBuffer( tr_session * session )
1014{
1015    assert( tr_isSession( session ) );
1016    assert( !session->bufferInUse );
1017    assert( tr_amInEventThread( session ) );
1018
1019    session->bufferInUse = TRUE;
1020    return session->buffer;
1021}
1022
1023void
1024tr_sessionReleaseBuffer( tr_session * session )
1025{
1026    assert( tr_isSession( session ) );
1027    assert( session->bufferInUse );
1028    assert( tr_amInEventThread( session ) );
1029
1030    session->bufferInUse = FALSE;
1031}
1032
1033void
1034tr_sessionLock( tr_session * session )
1035{
1036    assert( tr_isSession( session ) );
1037
1038    tr_lockLock( session->lock );
1039}
1040
1041void
1042tr_sessionUnlock( tr_session * session )
1043{
1044    assert( tr_isSession( session ) );
1045
1046    tr_lockUnlock( session->lock );
1047}
1048
1049tr_bool
1050tr_sessionIsLocked( const tr_session * session )
1051{
1052    return tr_isSession( session ) && tr_lockHave( session->lock );
1053}
1054
1055/***********************************************************************
1056 * tr_setBindPort
1057 ***********************************************************************
1058 *
1059 **********************************************************************/
1060
1061static void
1062peerPortChanged( void * session )
1063{
1064    tr_torrent * tor = NULL;
1065
1066    assert( tr_isSession( session ) );
1067
1068    close_incoming_peer_port( session );
1069    open_incoming_peer_port( session );
1070    tr_sharedPortChanged( session );
1071
1072    while(( tor = tr_torrentNext( session, tor )))
1073        tr_torrentChangeMyPort( tor );
1074}
1075
1076static void
1077setPeerPort( tr_session * session, tr_port port )
1078{
1079    session->private_peer_port = port;
1080    session->public_peer_port = port;
1081
1082    tr_runInEventThread( session, peerPortChanged, session );
1083}
1084
1085void
1086tr_sessionSetPeerPort( tr_session * session, tr_port port )
1087{
1088    if( tr_isSession( session ) && ( session->private_peer_port != port ) )
1089    {
1090        setPeerPort( session, port );
1091    }
1092}
1093
1094tr_port
1095tr_sessionGetPeerPort( const tr_session * session )
1096{
1097    return tr_isSession( session ) ? session->private_peer_port : 0;
1098}
1099
1100tr_port
1101tr_sessionSetPeerPortRandom( tr_session * session )
1102{
1103    assert( tr_isSession( session ) );
1104
1105    tr_sessionSetPeerPort( session, getRandomPort( session ) );
1106    return session->private_peer_port;
1107}
1108
1109void
1110tr_sessionSetPeerPortRandomOnStart( tr_session * session,
1111                                    tr_bool random )
1112{
1113    assert( tr_isSession( session ) );
1114
1115    session->isPortRandom = random;
1116}
1117
1118tr_bool
1119tr_sessionGetPeerPortRandomOnStart( tr_session * session )
1120{
1121    assert( tr_isSession( session ) );
1122
1123    return session->isPortRandom;
1124}
1125
1126tr_port_forwarding
1127tr_sessionGetPortForwarding( const tr_session * session )
1128{
1129    assert( tr_isSession( session ) );
1130
1131    return tr_sharedTraversalStatus( session->shared );
1132}
1133
1134/***
1135****
1136***/
1137
1138void
1139tr_sessionSetRatioLimited( tr_session * session, tr_bool isLimited )
1140{
1141    assert( tr_isSession( session ) );
1142
1143    session->isRatioLimited = isLimited;
1144}
1145
1146void
1147tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
1148{
1149    assert( tr_isSession( session ) );
1150
1151    session->desiredRatio = desiredRatio;
1152}
1153
1154tr_bool
1155tr_sessionIsRatioLimited( const tr_session  * session )
1156{
1157    assert( tr_isSession( session ) );
1158
1159    return session->isRatioLimited;
1160}
1161
1162double
1163tr_sessionGetRatioLimit( const tr_session * session )
1164{
1165    assert( tr_isSession( session ) );
1166
1167    return session->desiredRatio;
1168}
1169
1170/***
1171****
1172***/
1173
1174void
1175tr_sessionSetIdleLimited( tr_session * session, tr_bool isLimited )
1176{
1177    assert( tr_isSession( session ) );
1178
1179    session->isIdleLimited = isLimited;
1180}
1181
1182void
1183tr_sessionSetIdleLimit( tr_session * session, uint16_t idleMinutes )
1184{
1185    assert( tr_isSession( session ) );
1186
1187    session->idleLimitMinutes = idleMinutes;
1188}
1189
1190tr_bool
1191tr_sessionIsIdleLimited( const tr_session  * session )
1192{
1193    assert( tr_isSession( session ) );
1194
1195    return session->isIdleLimited;
1196}
1197
1198uint16_t
1199tr_sessionGetIdleLimit( const tr_session * session )
1200{
1201    assert( tr_isSession( session ) );
1202
1203    return session->idleLimitMinutes;
1204}
1205
1206/***
1207****
1208****  SPEED LIMITS
1209****
1210***/
1211
1212tr_bool
1213tr_sessionGetActiveSpeedLimit_Bps( const tr_session * session, tr_direction dir, int * setme_Bps )
1214{
1215    int isLimited = TRUE;
1216
1217    if( !tr_isSession( session ) )
1218        return FALSE;
1219
1220    if( tr_sessionUsesAltSpeed( session ) )
1221        *setme_Bps = tr_sessionGetAltSpeed_Bps( session, dir );
1222    else if( tr_sessionIsSpeedLimited( session, dir ) )
1223        *setme_Bps = tr_sessionGetSpeedLimit_Bps( session, dir );
1224    else
1225        isLimited = FALSE;
1226
1227    return isLimited;
1228}
1229tr_bool
1230tr_sessionGetActiveSpeedLimit_KBps( const tr_session  * session,
1231                                    tr_direction        dir,
1232                                    double            * setme_KBps )
1233{
1234    int Bps = 0;
1235    const tr_bool is_active = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &Bps );
1236    *setme_KBps = toSpeedKBps( Bps );
1237    return is_active;
1238}
1239
1240static void
1241updateBandwidth( tr_session * session, tr_direction dir )
1242{
1243    int limit_Bps = 0;
1244    const tr_bool isLimited = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &limit_Bps );
1245    const tr_bool zeroCase = isLimited && !limit_Bps;
1246
1247    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited && !zeroCase );
1248
1249    tr_bandwidthSetDesiredSpeed_Bps( session->bandwidth, dir, limit_Bps );
1250}
1251
1252enum
1253{
1254    MINUTES_PER_HOUR = 60,
1255    MINUTES_PER_DAY = MINUTES_PER_HOUR * 24,
1256    MINUTES_PER_WEEK = MINUTES_PER_DAY * 7
1257};
1258
1259static void
1260turtleUpdateTable( struct tr_turtle_info * t )
1261{
1262    int day;
1263    tr_bitfield * b = &t->minutes;
1264
1265    tr_bitfieldClear( b );
1266
1267    for( day=0; day<7; ++day )
1268    {
1269        if( t->days & (1<<day) )
1270        {
1271            int i;
1272            const time_t begin = t->beginMinute;
1273            time_t end = t->endMinute;
1274
1275            if( end <= begin )
1276                end += MINUTES_PER_DAY;
1277
1278            for( i=begin; i<end; ++i )
1279                tr_bitfieldAdd( b, (i+day*MINUTES_PER_DAY) % MINUTES_PER_WEEK );
1280        }
1281    }
1282}
1283
1284static void
1285altSpeedToggled( void * vsession )
1286{
1287    tr_session * session = vsession;
1288    struct tr_turtle_info * t = &session->turtle;
1289
1290    assert( tr_isSession( session ) );
1291
1292    updateBandwidth( session, TR_UP );
1293    updateBandwidth( session, TR_DOWN );
1294
1295    if( t->callback != NULL )
1296        (*t->callback)( session, t->isEnabled, t->changedByUser, t->callbackUserData );
1297}
1298
1299static void
1300useAltSpeed( tr_session * s, struct tr_turtle_info * t,
1301             tr_bool enabled, tr_bool byUser )
1302{
1303    assert( tr_isSession( s ) );
1304    assert( t != NULL );
1305    assert( tr_isBool( enabled ) );
1306    assert( tr_isBool( byUser ) );
1307
1308    if( t->isEnabled != enabled )
1309    {
1310        t->isEnabled = enabled;
1311        t->changedByUser = byUser;
1312        tr_runInEventThread( s, altSpeedToggled, s );
1313    }
1314}
1315
1316/**
1317 * @param enabled whether turtle should be on/off according to the scheduler
1318 * @param changed whether that's different from the previous minute
1319 */
1320static void
1321testTurtleTime( const struct tr_turtle_info * t,
1322                tr_bool * enabled,
1323                tr_bool * changed )
1324{
1325    tr_bool e;
1326    struct tm tm;
1327    size_t minute_of_the_week;
1328    const time_t now = tr_time( );
1329
1330    tr_localtime_r( &now, &tm );
1331
1332    minute_of_the_week = tm.tm_wday * MINUTES_PER_DAY
1333                       + tm.tm_hour * MINUTES_PER_HOUR
1334                       + tm.tm_min;
1335    if( minute_of_the_week >= MINUTES_PER_WEEK ) /* leap minutes? */
1336        minute_of_the_week = MINUTES_PER_WEEK - 1;
1337
1338    e = tr_bitfieldHasFast( &t->minutes, minute_of_the_week );
1339    if( enabled != NULL )
1340        *enabled = e;
1341
1342    if( changed != NULL )
1343    {
1344        const size_t prev = minute_of_the_week > 0 ? minute_of_the_week - 1
1345                                                   : MINUTES_PER_WEEK - 1;
1346        *changed = e != tr_bitfieldHasFast( &t->minutes, prev );
1347    }
1348}
1349
1350static void
1351turtleCheckClock( tr_session * s, struct tr_turtle_info * t )
1352{
1353    tr_bool enabled;
1354    tr_bool changed;
1355
1356    assert( t->isClockEnabled );
1357
1358    testTurtleTime( t, &enabled, &changed );
1359
1360    if( changed )
1361    {
1362        tr_inf( "Time to turn %s turtle mode!", (enabled?"on":"off") );
1363        useAltSpeed( s, t, enabled, FALSE );
1364    }
1365}
1366
1367/* Called after the turtle's fields are loaded from an outside source.
1368 * It initializes the implementation fields
1369 * and turns on turtle mode if the clock settings say to. */
1370static void
1371turtleBootstrap( tr_session * session, struct tr_turtle_info * turtle )
1372{
1373    turtle->changedByUser = FALSE;
1374
1375    tr_bitfieldConstruct( &turtle->minutes, MINUTES_PER_WEEK );
1376
1377    turtleUpdateTable( turtle );
1378
1379    if( turtle->isClockEnabled )
1380        testTurtleTime( turtle, &turtle->isEnabled, NULL );
1381
1382    altSpeedToggled( session );
1383}
1384
1385/***
1386****  Primary session speed limits
1387***/
1388
1389void
1390tr_sessionSetSpeedLimit_Bps( tr_session * s, tr_direction d, int Bps )
1391{
1392    assert( tr_isSession( s ) );
1393    assert( tr_isDirection( d ) );
1394    assert( Bps >= 0 );
1395
1396    s->speedLimit_Bps[d] = Bps;
1397
1398    updateBandwidth( s, d );
1399}
1400void
1401tr_sessionSetSpeedLimit_KBps( tr_session * s, tr_direction d, int KBps )
1402{
1403    tr_sessionSetSpeedLimit_Bps( s, d, toSpeedBytes( KBps ) );
1404}
1405
1406int
1407tr_sessionGetSpeedLimit_Bps( const tr_session * s, tr_direction d )
1408{
1409    assert( tr_isSession( s ) );
1410    assert( tr_isDirection( d ) );
1411
1412    return s->speedLimit_Bps[d];
1413}
1414int
1415tr_sessionGetSpeedLimit_KBps( const tr_session * s, tr_direction d )
1416{
1417    return toSpeedKBps( tr_sessionGetSpeedLimit_Bps( s, d ) );
1418}
1419
1420void
1421tr_sessionLimitSpeed( tr_session * s, tr_direction d, tr_bool b )
1422{
1423    assert( tr_isSession( s ) );
1424    assert( tr_isDirection( d ) );
1425    assert( tr_isBool( b ) );
1426
1427    s->speedLimitEnabled[d] = b;
1428
1429    updateBandwidth( s, d );
1430}
1431
1432tr_bool
1433tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1434{
1435    assert( tr_isSession( s ) );
1436    assert( tr_isDirection( d ) );
1437
1438    return s->speedLimitEnabled[d];
1439}
1440
1441/***
1442****  Alternative speed limits that are used during scheduled times
1443***/
1444
1445void
1446tr_sessionSetAltSpeed_Bps( tr_session * s, tr_direction d, int Bps )
1447{
1448    assert( tr_isSession( s ) );
1449    assert( tr_isDirection( d ) );
1450    assert( Bps >= 0 );
1451
1452    s->turtle.speedLimit_Bps[d] = Bps;
1453
1454    updateBandwidth( s, d );
1455}
1456
1457void
1458tr_sessionSetAltSpeed_KBps( tr_session * s, tr_direction d, int KBps )
1459{
1460    tr_sessionSetAltSpeed_Bps( s, d, toSpeedBytes( KBps ) );
1461}
1462
1463int
1464tr_sessionGetAltSpeed_Bps( const tr_session * s, tr_direction d )
1465{
1466    assert( tr_isSession( s ) );
1467    assert( tr_isDirection( d ) );
1468
1469    return s->turtle.speedLimit_Bps[d];
1470}
1471int
1472tr_sessionGetAltSpeed_KBps( const tr_session * s, tr_direction d )
1473{
1474    return toSpeedKBps( tr_sessionGetAltSpeed_Bps( s, d ) );
1475}
1476
1477static void
1478userPokedTheClock( tr_session * s, struct tr_turtle_info * t )
1479{
1480    tr_dbg( "Refreshing the turtle mode clock due to user changes" );
1481
1482    turtleUpdateTable( t );
1483
1484    if( t->isClockEnabled )
1485    {
1486        tr_bool enabled, changed;
1487        testTurtleTime( t, &enabled, &changed );
1488        useAltSpeed( s, t, enabled, TRUE );
1489    }
1490}
1491
1492void
1493tr_sessionUseAltSpeedTime( tr_session * s, tr_bool b )
1494{
1495    struct tr_turtle_info * t = &s->turtle;
1496
1497    assert( tr_isSession( s ) );
1498    assert( tr_isBool ( b ) );
1499
1500    if( t->isClockEnabled != b ) {
1501        t->isClockEnabled = b;
1502        userPokedTheClock( s, t );
1503    }
1504}
1505
1506tr_bool
1507tr_sessionUsesAltSpeedTime( const tr_session * s )
1508{
1509    assert( tr_isSession( s ) );
1510
1511    return s->turtle.isClockEnabled;
1512}
1513
1514void
1515tr_sessionSetAltSpeedBegin( tr_session * s, int minute )
1516{
1517    assert( tr_isSession( s ) );
1518    assert( 0<=minute && minute<(60*24) );
1519
1520    if( s->turtle.beginMinute != minute ) {
1521        s->turtle.beginMinute = minute;
1522        userPokedTheClock( s, &s->turtle );
1523    }
1524}
1525
1526int
1527tr_sessionGetAltSpeedBegin( const tr_session * s )
1528{
1529    assert( tr_isSession( s ) );
1530
1531    return s->turtle.beginMinute;
1532}
1533
1534void
1535tr_sessionSetAltSpeedEnd( tr_session * s, int minute )
1536{
1537    assert( tr_isSession( s ) );
1538    assert( 0<=minute && minute<(60*24) );
1539
1540    if( s->turtle.endMinute != minute ) {
1541        s->turtle.endMinute = minute;
1542        userPokedTheClock( s, &s->turtle );
1543    }
1544}
1545
1546int
1547tr_sessionGetAltSpeedEnd( const tr_session * s )
1548{
1549    assert( tr_isSession( s ) );
1550
1551    return s->turtle.endMinute;
1552}
1553
1554void
1555tr_sessionSetAltSpeedDay( tr_session * s, tr_sched_day days )
1556{
1557    assert( tr_isSession( s ) );
1558
1559    if( s->turtle.days != days ) {
1560        s->turtle.days = days;
1561        userPokedTheClock( s, &s->turtle );
1562    }
1563}
1564
1565tr_sched_day
1566tr_sessionGetAltSpeedDay( const tr_session * s )
1567{
1568    assert( tr_isSession( s ) );
1569
1570    return s->turtle.days;
1571}
1572
1573void
1574tr_sessionUseAltSpeed( tr_session * session, tr_bool enabled )
1575{
1576    useAltSpeed( session, &session->turtle, enabled, TRUE );
1577}
1578
1579tr_bool
1580tr_sessionUsesAltSpeed( const tr_session * s )
1581{
1582    assert( tr_isSession( s ) );
1583
1584    return s->turtle.isEnabled;
1585}
1586
1587void
1588tr_sessionSetAltSpeedFunc( tr_session       * session,
1589                           tr_altSpeedFunc    func,
1590                           void             * userData )
1591{
1592    assert( tr_isSession( session ) );
1593
1594    session->turtle.callback = func;
1595    session->turtle.callbackUserData = userData;
1596}
1597
1598void
1599tr_sessionClearAltSpeedFunc( tr_session * session )
1600{
1601    tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1602}
1603
1604/***
1605****
1606***/
1607
1608void
1609tr_sessionSetPeerLimit( tr_session * session, uint16_t maxGlobalPeers )
1610{
1611    assert( tr_isSession( session ) );
1612
1613    tr_fdSetPeerLimit( session, maxGlobalPeers );
1614}
1615
1616uint16_t
1617tr_sessionGetPeerLimit( const tr_session * session )
1618{
1619    assert( tr_isSession( session ) );
1620
1621    return tr_fdGetPeerLimit( session );
1622}
1623
1624void
1625tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
1626{
1627    assert( tr_isSession( session ) );
1628
1629    session->peerLimitPerTorrent = n;
1630}
1631
1632uint16_t
1633tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1634{
1635    assert( tr_isSession( session ) );
1636
1637    return session->peerLimitPerTorrent;
1638}
1639
1640/***
1641****
1642***/
1643
1644void
1645tr_sessionSetPaused( tr_session * session, tr_bool isPaused )
1646{
1647    assert( tr_isSession( session ) );
1648
1649    session->pauseAddedTorrent = isPaused;
1650}
1651
1652tr_bool
1653tr_sessionGetPaused( const tr_session * session )
1654{
1655    assert( tr_isSession( session ) );
1656
1657    return session->pauseAddedTorrent;
1658}
1659
1660void
1661tr_sessionSetDeleteSource( tr_session * session, tr_bool deleteSource )
1662{
1663    assert( tr_isSession( session ) );
1664
1665    session->deleteSourceTorrent = deleteSource;
1666}
1667
1668tr_bool
1669tr_sessionGetDeleteSource( const tr_session * session )
1670{
1671    assert( tr_isSession( session ) );
1672
1673    return session->deleteSourceTorrent;
1674}
1675
1676/***
1677****
1678***/
1679
1680int
1681tr_sessionGetPieceSpeed_Bps( const tr_session * session, tr_direction dir )
1682{
1683    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed_Bps( session->bandwidth, 0, dir ) : 0;
1684}
1685
1686int
1687tr_sessionGetRawSpeed_Bps( const tr_session * session, tr_direction dir )
1688{
1689    return tr_isSession( session ) ? tr_bandwidthGetRawSpeed_Bps( session->bandwidth, 0, dir ) : 0;
1690}
1691double
1692tr_sessionGetRawSpeed_KBps( const tr_session * session, tr_direction dir )
1693{
1694    return toSpeedKBps( tr_sessionGetRawSpeed_Bps( session, dir ) );
1695}
1696
1697
1698int
1699tr_sessionCountTorrents( const tr_session * session )
1700{
1701    return tr_isSession( session ) ? session->torrentCount : 0;
1702}
1703
1704static int
1705compareTorrentByCur( const void * va, const void * vb )
1706{
1707    const tr_torrent * a = *(const tr_torrent**)va;
1708    const tr_torrent * b = *(const tr_torrent**)vb;
1709    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1710    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1711
1712    if( aCur != bCur )
1713        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1714
1715    return 0;
1716}
1717
1718static void closeBlocklists( tr_session * );
1719
1720static void
1721sessionCloseImpl( void * vsession )
1722{
1723    tr_session *  session = vsession;
1724    tr_torrent *  tor;
1725    int           i, n;
1726    tr_torrent ** torrents;
1727
1728    assert( tr_isSession( session ) );
1729
1730    free_incoming_peer_port( session );
1731
1732    if( session->isLPDEnabled )
1733        tr_lpdUninit( session );
1734
1735    tr_utpClose( session );
1736    tr_udpUninit( session );
1737
1738    event_free( session->saveTimer );
1739    session->saveTimer = NULL;
1740
1741    event_free( session->nowTimer );
1742    session->nowTimer = NULL;
1743
1744    tr_verifyClose( session );
1745    tr_sharedClose( session );
1746    tr_rpcClose( &session->rpcServer );
1747
1748    /* Close the torrents. Get the most active ones first so that
1749     * if we can't get them all closed in a reasonable amount of time,
1750     * at least we get the most important ones first. */
1751    tor = NULL;
1752    n = session->torrentCount;
1753    torrents = tr_new( tr_torrent *, session->torrentCount );
1754    for( i = 0; i < n; ++i )
1755        torrents[i] = tor = tr_torrentNext( session, tor );
1756    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1757    for( i = 0; i < n; ++i )
1758        tr_torrentFree( torrents[i] );
1759    tr_free( torrents );
1760
1761    tr_cacheFree( session->cache );
1762    session->cache = NULL;
1763    tr_announcerClose( session );
1764    tr_statsClose( session );
1765    tr_peerMgrFree( session->peerMgr );
1766    tr_webClose( session, TR_WEB_CLOSE_WHEN_IDLE );
1767
1768    closeBlocklists( session );
1769
1770    tr_fdClose( session );
1771
1772    session->isClosed = TRUE;
1773}
1774
1775static int
1776deadlineReached( const time_t deadline )
1777{
1778    return time( NULL ) >= deadline;
1779}
1780
1781#define SHUTDOWN_MAX_SECONDS 20
1782
1783void
1784tr_sessionClose( tr_session * session )
1785{
1786    const time_t deadline = time( NULL ) + SHUTDOWN_MAX_SECONDS;
1787
1788    assert( tr_isSession( session ) );
1789
1790    dbgmsg( "shutting down transmission session %p... now is %zu, deadline is %zu", session, (size_t)time(NULL), (size_t)deadline );
1791
1792    /* close the session */
1793    tr_runInEventThread( session, sessionCloseImpl, session );
1794    while( !session->isClosed && !deadlineReached( deadline ) )
1795    {
1796        dbgmsg( "waiting for the libtransmission thread to finish" );
1797        tr_wait_msec( 100 );
1798    }
1799
1800    /* "shared" and "tracker" have live sockets,
1801     * so we need to keep the transmission thread alive
1802     * for a bit while they tell the router & tracker
1803     * that we're closing now */
1804    while( ( session->shared || session->web || session->announcer )
1805           && !deadlineReached( deadline ) )
1806    {
1807        dbgmsg( "waiting on port unmap (%p) or announcer (%p)... now %zu deadline %zu",
1808                session->shared, session->announcer, (size_t)time(NULL), (size_t)deadline );
1809        tr_wait_msec( 100 );
1810    }
1811
1812    tr_webClose( session, TR_WEB_CLOSE_NOW );
1813
1814    /* close the libtransmission thread */
1815    tr_eventClose( session );
1816    while( session->events != NULL )
1817    {
1818        static tr_bool forced = FALSE;
1819        dbgmsg( "waiting for libtransmission thread to finish... now %zu deadline %zu", (size_t)time(NULL), (size_t)deadline );
1820        tr_wait_msec( 500 );
1821        if( deadlineReached( deadline ) && !forced )
1822        {
1823            dbgmsg( "calling event_loopbreak()" );
1824            forced = TRUE;
1825            event_base_loopbreak( session->event_base );
1826        }
1827        if( deadlineReached( deadline+3 ) )
1828        {
1829            dbgmsg( "deadline+3 reached... calling break...\n" );
1830            break;
1831        }
1832    }
1833
1834    /* free the session memory */
1835    tr_bencFree( &session->removedTorrents );
1836    tr_bandwidthFree( session->bandwidth );
1837    tr_bitfieldDestruct( &session->turtle.minutes );
1838    tr_lockFree( session->lock );
1839    if( session->metainfoLookup ) {
1840        tr_bencFree( session->metainfoLookup );
1841        tr_free( session->metainfoLookup );
1842    }
1843    tr_free( session->torrentDoneScript );
1844    tr_free( session->buffer );
1845    tr_free( session->tag );
1846    tr_free( session->configDir );
1847    tr_free( session->resumeDir );
1848    tr_free( session->torrentDir );
1849    tr_free( session->downloadDir );
1850    tr_free( session->incompleteDir );
1851    tr_free( session->blocklist_url );
1852    tr_free( session->peer_congestion_algorithm );
1853    tr_free( session );
1854}
1855
1856tr_torrent **
1857tr_sessionLoadTorrents( tr_session * session,
1858                        tr_ctor    * ctor,
1859                        int        * setmeCount )
1860{
1861    int           i, n = 0;
1862    struct stat   sb;
1863    DIR *         odir = NULL;
1864    const char *  dirname = tr_getTorrentDir( session );
1865    tr_torrent ** torrents;
1866    tr_list *     l = NULL, *list = NULL;
1867
1868    assert( tr_isSession( session ) );
1869
1870    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1871
1872    if( !stat( dirname, &sb )
1873      && S_ISDIR( sb.st_mode )
1874      && ( ( odir = opendir ( dirname ) ) ) )
1875    {
1876        struct dirent *d;
1877        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1878        {
1879            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
1880            {
1881                tr_torrent * tor;
1882                char * path = tr_buildPath( dirname, d->d_name, NULL );
1883                tr_ctorSetMetainfoFromFile( ctor, path );
1884                if(( tor = tr_torrentNew( ctor, NULL )))
1885                {
1886                    tr_list_append( &list, tor );
1887                    ++n;
1888                }
1889                tr_free( path );
1890            }
1891        }
1892        closedir( odir );
1893    }
1894
1895    torrents = tr_new( tr_torrent *, n );
1896    for( i = 0, l = list; l != NULL; l = l->next )
1897        torrents[i++] = (tr_torrent*) l->data;
1898    assert( i == n );
1899
1900    tr_list_free( &list, NULL );
1901
1902    if( n )
1903        tr_inf( _( "Loaded %d torrents" ), n );
1904
1905    if( setmeCount )
1906        *setmeCount = n;
1907    return torrents;
1908}
1909
1910/***
1911****
1912***/
1913
1914void
1915tr_sessionSetPexEnabled( tr_session * session,
1916                         tr_bool      enabled )
1917{
1918    assert( tr_isSession( session ) );
1919
1920    session->isPexEnabled = enabled != 0;
1921}
1922
1923tr_bool
1924tr_sessionIsPexEnabled( const tr_session * session )
1925{
1926    assert( tr_isSession( session ) );
1927
1928    return session->isPexEnabled;
1929}
1930
1931tr_bool
1932tr_sessionAllowsDHT( const tr_session * session UNUSED )
1933{
1934    return tr_sessionIsDHTEnabled( session );
1935}
1936
1937tr_bool
1938tr_sessionIsDHTEnabled( const tr_session * session )
1939{
1940    assert( tr_isSession( session ) );
1941
1942    return session->isDHTEnabled;
1943}
1944
1945static void
1946toggleDHTImpl(  void * data )
1947{
1948    tr_session * session = data;
1949    assert( tr_isSession( session ) );
1950
1951    tr_udpUninit( session );
1952    session->isDHTEnabled = !session->isDHTEnabled;
1953    tr_udpInit( session );
1954}
1955
1956void
1957tr_sessionSetDHTEnabled( tr_session * session, tr_bool enabled )
1958{
1959    assert( tr_isSession( session ) );
1960    assert( tr_isBool( enabled ) );
1961
1962    if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1963        tr_runInEventThread( session, toggleDHTImpl, session );
1964}
1965
1966/***
1967****
1968***/
1969
1970tr_bool
1971tr_sessionIsUTPEnabled( const tr_session * session )
1972{
1973    assert( tr_isSession( session ) );
1974
1975#ifdef WITH_UTP
1976    return session->isUTPEnabled;
1977#else
1978    return FALSE;
1979#endif
1980}
1981
1982static void
1983toggle_utp(  void * data )
1984{
1985    tr_session * session = data;
1986    assert( tr_isSession( session ) );
1987
1988    session->isUTPEnabled = !session->isUTPEnabled;
1989
1990    tr_udpSetSocketBuffers( session );
1991
1992    /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
1993       explanation. */
1994}
1995
1996void
1997tr_sessionSetUTPEnabled( tr_session * session, tr_bool enabled )
1998{
1999    assert( tr_isSession( session ) );
2000    assert( tr_isBool( enabled ) );
2001
2002    if( ( enabled != 0 ) != ( session->isUTPEnabled != 0 ) )
2003        tr_runInEventThread( session, toggle_utp, session );
2004}
2005
2006/***
2007****
2008***/
2009
2010static void
2011toggleLPDImpl(  void * data )
2012{
2013    tr_session * session = data;
2014    assert( tr_isSession( session ) );
2015
2016    if( session->isLPDEnabled )
2017        tr_lpdUninit( session );
2018
2019    session->isLPDEnabled = !session->isLPDEnabled;
2020
2021    if( session->isLPDEnabled )
2022        tr_lpdInit( session, &session->public_ipv4->addr );
2023}
2024
2025void
2026tr_sessionSetLPDEnabled( tr_session * session, tr_bool enabled )
2027{
2028    assert( tr_isSession( session ) );
2029    assert( tr_isBool( enabled ) );
2030
2031    if( ( enabled != 0 ) != ( session->isLPDEnabled != 0 ) )
2032        tr_runInEventThread( session, toggleLPDImpl, session );
2033}
2034
2035tr_bool
2036tr_sessionIsLPDEnabled( const tr_session * session )
2037{
2038    assert( tr_isSession( session ) );
2039
2040    return session->isLPDEnabled;
2041}
2042
2043tr_bool
2044tr_sessionAllowsLPD( const tr_session * session )
2045{
2046    return tr_sessionIsLPDEnabled( session );
2047}
2048
2049/***
2050****
2051***/
2052
2053void
2054tr_sessionSetCacheLimit_MB( tr_session * session, int max_bytes )
2055{
2056    assert( tr_isSession( session ) );
2057
2058    tr_cacheSetLimit( session->cache, toMemBytes( max_bytes ) );
2059}
2060
2061int
2062tr_sessionGetCacheLimit_MB( const tr_session * session )
2063{
2064    assert( tr_isSession( session ) );
2065
2066    return toMemMB( tr_cacheGetLimit( session->cache ) );
2067}
2068
2069/***
2070****
2071***/
2072
2073void
2074tr_sessionSetLazyBitfieldEnabled( tr_session * session,
2075                                  tr_bool      enabled )
2076{
2077    assert( tr_isSession( session ) );
2078
2079    session->useLazyBitfield = enabled != 0;
2080}
2081
2082tr_bool
2083tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
2084{
2085    assert( tr_isSession( session ) );
2086
2087    return session->useLazyBitfield;
2088}
2089
2090/***
2091****
2092***/
2093
2094struct port_forwarding_data
2095{
2096    tr_bool enabled;
2097    struct tr_shared * shared;
2098};
2099
2100static void
2101setPortForwardingEnabled( void * vdata )
2102{
2103    struct port_forwarding_data * data = vdata;
2104    tr_sharedTraversalEnable( data->shared, data->enabled );
2105    tr_free( data );
2106}
2107
2108void
2109tr_sessionSetPortForwardingEnabled( tr_session  * session, tr_bool enabled )
2110{
2111    struct port_forwarding_data * d;
2112    d = tr_new0( struct port_forwarding_data, 1 );
2113    d->shared = session->shared;
2114    d->enabled = enabled;
2115    tr_runInEventThread( session, setPortForwardingEnabled, d );
2116}
2117
2118tr_bool
2119tr_sessionIsPortForwardingEnabled( const tr_session * session )
2120{
2121    assert( tr_isSession( session ) );
2122
2123    return tr_sharedTraversalIsEnabled( session->shared );
2124}
2125
2126/***
2127****
2128***/
2129
2130static int
2131tr_stringEndsWith( const char * str, const char * end )
2132{
2133    const size_t slen = strlen( str );
2134    const size_t elen = strlen( end );
2135
2136    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
2137}
2138
2139static void
2140loadBlocklists( tr_session * session )
2141{
2142    int         binCount = 0;
2143    int         newCount = 0;
2144    struct stat sb;
2145    char      * dirname;
2146    DIR *       odir = NULL;
2147    tr_list *   list = NULL;
2148    const tr_bool   isEnabled = session->isBlocklistEnabled;
2149
2150    /* walk through the directory and find blocklists */
2151    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
2152    if( !stat( dirname,
2153               &sb ) && S_ISDIR( sb.st_mode )
2154      && ( ( odir = opendir( dirname ) ) ) )
2155    {
2156        struct dirent *d;
2157        for( d = readdir( odir ); d; d = readdir( odir ) )
2158        {
2159            char * filename;
2160
2161            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
2162                                                      */
2163                continue;
2164
2165            filename = tr_buildPath( dirname, d->d_name, NULL );
2166
2167            if( tr_stringEndsWith( filename, ".bin" ) )
2168            {
2169                /* if we don't already have this blocklist, add it */
2170                if( !tr_list_find( list, filename,
2171                                   (TrListCompareFunc)strcmp ) )
2172                {
2173                    tr_list_append( &list,
2174                                   _tr_blocklistNew( filename, isEnabled ) );
2175                    ++binCount;
2176                }
2177            }
2178            else
2179            {
2180                /* strip out the file suffix, if there is one, and add ".bin"
2181                  instead */
2182                tr_blocklist * b;
2183                const char *   dot = strrchr( d->d_name, '.' );
2184                const int      len = dot ? dot - d->d_name
2185                                         : (int)strlen( d->d_name );
2186                char         * tmp = tr_strdup_printf(
2187                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
2188                                        dirname, len, len, d->d_name );
2189                b = _tr_blocklistNew( tmp, isEnabled );
2190                _tr_blocklistSetContent( b, filename );
2191                tr_list_append( &list, b );
2192                ++newCount;
2193                tr_free( tmp );
2194            }
2195
2196            tr_free( filename );
2197        }
2198
2199        closedir( odir );
2200    }
2201
2202    session->blocklists = list;
2203
2204    if( binCount )
2205        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
2206    if( newCount )
2207        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
2208
2209    tr_free( dirname );
2210}
2211
2212static void
2213closeBlocklists( tr_session * session )
2214{
2215    tr_list_free( &session->blocklists,
2216                  (TrListForeachFunc)_tr_blocklistFree );
2217}
2218
2219void
2220tr_sessionReloadBlocklists( tr_session * session )
2221{
2222    closeBlocklists( session );
2223    loadBlocklists( session );
2224
2225    tr_peerMgrOnBlocklistChanged( session->peerMgr );
2226}
2227
2228int
2229tr_blocklistGetRuleCount( const tr_session * session )
2230{
2231    int       n = 0;
2232    tr_list * l;
2233
2234    assert( tr_isSession( session ) );
2235
2236    for( l = session->blocklists; l; l = l->next )
2237        n += _tr_blocklistGetRuleCount( l->data );
2238    return n;
2239}
2240
2241tr_bool
2242tr_blocklistIsEnabled( const tr_session * session )
2243{
2244    assert( tr_isSession( session ) );
2245
2246    return session->isBlocklistEnabled;
2247}
2248
2249void
2250tr_blocklistSetEnabled( tr_session * session,
2251                        tr_bool      isEnabled )
2252{
2253    tr_list * l;
2254
2255    assert( tr_isSession( session ) );
2256
2257    session->isBlocklistEnabled = isEnabled != 0;
2258
2259    for( l=session->blocklists; l!=NULL; l=l->next )
2260        _tr_blocklistSetEnabled( l->data, isEnabled );
2261}
2262
2263tr_bool
2264tr_blocklistExists( const tr_session * session )
2265{
2266    assert( tr_isSession( session ) );
2267
2268    return session->blocklists != NULL;
2269}
2270
2271int
2272tr_blocklistSetContent( tr_session * session, const char * contentFilename )
2273{
2274    tr_list * l;
2275    int ruleCount;
2276    tr_blocklist * b;
2277    const char * defaultName = DEFAULT_BLOCKLIST_FILENAME;
2278    tr_sessionLock( session );
2279
2280    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
2281        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
2282                               defaultName ) )
2283            b = l->data;
2284
2285    if( !b )
2286    {
2287        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
2288        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
2289        tr_list_append( &session->blocklists, b );
2290        tr_free( path );
2291    }
2292
2293    ruleCount = _tr_blocklistSetContent( b, contentFilename );
2294    tr_sessionUnlock( session );
2295    return ruleCount;
2296}
2297
2298tr_bool
2299tr_sessionIsAddressBlocked( const tr_session * session,
2300                            const tr_address * addr )
2301{
2302    tr_list * l;
2303
2304    assert( tr_isSession( session ) );
2305
2306    for( l = session->blocklists; l; l = l->next )
2307        if( _tr_blocklistHasAddress( l->data, addr ) )
2308            return TRUE;
2309    return FALSE;
2310}
2311
2312void
2313tr_blocklistSetURL( tr_session * session, const char * url )
2314{
2315    if( session->blocklist_url != url )
2316    {
2317        tr_free( session->blocklist_url );
2318        session->blocklist_url = tr_strdup( url );
2319    }
2320}
2321
2322const char *
2323tr_blocklistGetURL ( const tr_session * session )
2324{
2325    return session->blocklist_url;
2326}
2327
2328
2329/***
2330****
2331***/
2332
2333static void
2334metainfoLookupInit( tr_session * session )
2335{
2336    struct stat  sb;
2337    const char * dirname = tr_getTorrentDir( session );
2338    DIR *        odir = NULL;
2339    tr_ctor *    ctor = NULL;
2340    tr_benc * lookup;
2341    int n = 0;
2342
2343    assert( tr_isSession( session ) );
2344
2345    /* walk through the directory and find the mappings */
2346    lookup = tr_new0( tr_benc, 1 );
2347    tr_bencInitDict( lookup, 0 );
2348    ctor = tr_ctorNew( session );
2349    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
2350    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
2351    {
2352        struct dirent *d;
2353        while(( d = readdir( odir )))
2354        {
2355            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
2356            {
2357                tr_info inf;
2358                char * path = tr_buildPath( dirname, d->d_name, NULL );
2359                tr_ctorSetMetainfoFromFile( ctor, path );
2360                if( !tr_torrentParse( ctor, &inf ) )
2361                {
2362                    ++n;
2363                    tr_bencDictAddStr( lookup, inf.hashString, path );
2364                }
2365                tr_free( path );
2366            }
2367        }
2368        closedir( odir );
2369    }
2370    tr_ctorFree( ctor );
2371
2372    session->metainfoLookup = lookup;
2373    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
2374}
2375
2376const char*
2377tr_sessionFindTorrentFile( const tr_session * session,
2378                           const char       * hashString )
2379{
2380    const char * filename = NULL;
2381    if( !session->metainfoLookup )
2382        metainfoLookupInit( (tr_session*)session );
2383    tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
2384    return filename;
2385}
2386
2387void
2388tr_sessionSetTorrentFile( tr_session * session,
2389                          const char * hashString,
2390                          const char * filename )
2391{
2392    /* since we walk session->configDir/torrents/ to build the lookup table,
2393     * and tr_sessionSetTorrentFile() is just to tell us there's a new file
2394     * in that same directory, we don't need to do anything here if the
2395     * lookup table hasn't been built yet */
2396    if( session->metainfoLookup )
2397        tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
2398}
2399
2400/***
2401****
2402***/
2403
2404void
2405tr_sessionSetRPCEnabled( tr_session * session,
2406                         tr_bool      isEnabled )
2407{
2408    assert( tr_isSession( session ) );
2409
2410    tr_rpcSetEnabled( session->rpcServer, isEnabled );
2411}
2412
2413tr_bool
2414tr_sessionIsRPCEnabled( const tr_session * session )
2415{
2416    assert( tr_isSession( session ) );
2417
2418    return tr_rpcIsEnabled( session->rpcServer );
2419}
2420
2421void
2422tr_sessionSetRPCPort( tr_session * session,
2423                      tr_port      port )
2424{
2425    assert( tr_isSession( session ) );
2426
2427    tr_rpcSetPort( session->rpcServer, port );
2428}
2429
2430tr_port
2431tr_sessionGetRPCPort( const tr_session * session )
2432{
2433    assert( tr_isSession( session ) );
2434
2435    return tr_rpcGetPort( session->rpcServer );
2436}
2437
2438void
2439tr_sessionSetRPCUrl( tr_session * session,
2440                     const char * url )
2441{
2442    assert( tr_isSession( session ) );
2443
2444    tr_rpcSetUrl( session->rpcServer, url );
2445}
2446
2447const char*
2448tr_sessionGetRPCUrl( const tr_session * session )
2449{
2450    assert( tr_isSession( session ) );
2451
2452    return tr_rpcGetUrl( session->rpcServer );
2453}
2454
2455void
2456tr_sessionSetRPCCallback( tr_session * session,
2457                          tr_rpc_func  func,
2458                          void *       user_data )
2459{
2460    assert( tr_isSession( session ) );
2461
2462    session->rpc_func = func;
2463    session->rpc_func_user_data = user_data;
2464}
2465
2466void
2467tr_sessionSetRPCWhitelist( tr_session * session,
2468                           const char * whitelist )
2469{
2470    assert( tr_isSession( session ) );
2471
2472    tr_rpcSetWhitelist( session->rpcServer, whitelist );
2473}
2474
2475const char*
2476tr_sessionGetRPCWhitelist( const tr_session * session )
2477{
2478    assert( tr_isSession( session ) );
2479
2480    return tr_rpcGetWhitelist( session->rpcServer );
2481}
2482
2483void
2484tr_sessionSetRPCWhitelistEnabled( tr_session * session,
2485                                  tr_bool      isEnabled )
2486{
2487    assert( tr_isSession( session ) );
2488
2489    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
2490}
2491
2492tr_bool
2493tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
2494{
2495    assert( tr_isSession( session ) );
2496
2497    return tr_rpcGetWhitelistEnabled( session->rpcServer );
2498}
2499
2500
2501void
2502tr_sessionSetRPCPassword( tr_session * session,
2503                          const char * password )
2504{
2505    assert( tr_isSession( session ) );
2506
2507    tr_rpcSetPassword( session->rpcServer, password );
2508}
2509
2510const char*
2511tr_sessionGetRPCPassword( const tr_session * session )
2512{
2513    assert( tr_isSession( session ) );
2514
2515    return tr_rpcGetPassword( session->rpcServer );
2516}
2517
2518void
2519tr_sessionSetRPCUsername( tr_session * session,
2520                          const char * username )
2521{
2522    assert( tr_isSession( session ) );
2523
2524    tr_rpcSetUsername( session->rpcServer, username );
2525}
2526
2527const char*
2528tr_sessionGetRPCUsername( const tr_session * session )
2529{
2530    assert( tr_isSession( session ) );
2531
2532    return tr_rpcGetUsername( session->rpcServer );
2533}
2534
2535void
2536tr_sessionSetRPCPasswordEnabled( tr_session * session,
2537                                 tr_bool      isEnabled )
2538{
2539    assert( tr_isSession( session ) );
2540
2541    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2542}
2543
2544tr_bool
2545tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2546{
2547    assert( tr_isSession( session ) );
2548
2549    return tr_rpcIsPasswordEnabled( session->rpcServer );
2550}
2551
2552const char *
2553tr_sessionGetRPCBindAddress( const tr_session * session )
2554{
2555    assert( tr_isSession( session ) );
2556
2557    return tr_rpcGetBindAddress( session->rpcServer );
2558}
2559
2560/****
2561*****
2562****/
2563
2564tr_bool
2565tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session )
2566{
2567    assert( tr_isSession( session ) );
2568
2569    return session->isTorrentDoneScriptEnabled;
2570}
2571
2572void
2573tr_sessionSetTorrentDoneScriptEnabled( tr_session * session, tr_bool isEnabled )
2574{
2575    assert( tr_isSession( session ) );
2576    assert( tr_isBool( isEnabled ) );
2577
2578    session->isTorrentDoneScriptEnabled = isEnabled;
2579}
2580
2581const char *
2582tr_sessionGetTorrentDoneScript( const tr_session * session )
2583{
2584    assert( tr_isSession( session ) );
2585
2586    return session->torrentDoneScript;
2587}
2588
2589void
2590tr_sessionSetTorrentDoneScript( tr_session * session, const char * scriptFilename )
2591{
2592    assert( tr_isSession( session ) );
2593
2594    if( session->torrentDoneScript != scriptFilename )
2595    {
2596        tr_free( session->torrentDoneScript );
2597        session->torrentDoneScript = tr_strdup( scriptFilename );
2598    }
2599}
2600
2601/***
2602****
2603***/
2604
2605void
2606tr_sessionSetWebConfigFunc( tr_session * session, void (*func)(tr_session*, void*, const char* ) )
2607{
2608    session->curl_easy_config_func = func;
2609}
Note: See TracBrowser for help on using the repository browser.