source: trunk/libtransmission/session.c @ 12228

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

(trunk libT) still fiddling around with #includes -- this time removing unncecessary libT includes from libT .c files

  • 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 12228 2011-03-25 01:41:57Z jordan $
11 */
12
13#include <assert.h>
14#include <errno.h> /* ENOENT */
15#include <stdlib.h>
16#include <string.h> /* memcpy */
17
18#include <signal.h>
19#include <sys/types.h> /* stat(), umask() */
20#include <sys/stat.h> /* stat(), umask() */
21#include <unistd.h> /* stat */
22#include <dirent.h> /* opendir */
23
24#include <event2/dns.h> /* evdns_base_free() */
25#include <event2/event.h>
26
27//#define TR_SHOW_DEPRECATED
28#include "transmission.h"
29#include "announcer.h"
30#include "bandwidth.h"
31#include "bencode.h"
32#include "blocklist.h"
33#include "cache.h"
34#include "crypto.h"
35#include "fdlimit.h"
36#include "list.h"
37#include "net.h"
38#include "peer-io.h"
39#include "peer-mgr.h"
40#include "platform.h" /* tr_lock */
41#include "port-forwarding.h"
42#include "rpc-server.h"
43#include "session.h"
44#include "stats.h"
45#include "torrent.h"
46#include "tr-dht.h" /* tr_dhtUpkeep() */
47#include "tr-udp.h"
48#include "tr-utp.h"
49#include "tr-lpd.h"
50#include "trevent.h"
51#include "utils.h"
52#include "verify.h"
53#include "version.h"
54#include "web.h"
55
56enum
57{
58#ifdef TR_LIGHTWEIGHT
59    DEFAULT_CACHE_SIZE_MB = 2,
60    DEFAULT_PREFETCH_ENABLED = false,
61#else
62    DEFAULT_CACHE_SIZE_MB = 4,
63    DEFAULT_PREFETCH_ENABLED = true,
64#endif
65    SAVE_INTERVAL_SECS = 360
66};
67
68
69#define dbgmsg( ... ) \
70    do { \
71        if( tr_deepLoggingIsActive( ) ) \
72            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
73    } while( 0 )
74
75static tr_port
76getRandomPort( tr_session * s )
77{
78    return tr_cryptoWeakRandInt( s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow;
79}
80
81/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
82   characters, where x is the major version number, y is the
83   minor version number, z is the maintenance number, and b
84   designates beta (Azureus-style) */
85void
86tr_peerIdInit( uint8_t * buf )
87{
88    int          i;
89    int          val;
90    int          total = 0;
91    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
92    const int    base = 36;
93
94    memcpy( buf, PEERID_PREFIX, 8 );
95
96    tr_cryptoRandBuf( buf+8, 11 );
97    for( i=8; i<19; ++i ) {
98        val = buf[i] % base;
99        total += val;
100        buf[i] = pool[val];
101    }
102
103    val = total % base ? base - ( total % base ) : 0;
104    buf[19] = pool[val];
105    buf[20] = '\0';
106}
107
108/***
109****
110***/
111
112tr_encryption_mode
113tr_sessionGetEncryption( tr_session * session )
114{
115    assert( session );
116
117    return session->encryptionMode;
118}
119
120void
121tr_sessionSetEncryption( tr_session *       session,
122                         tr_encryption_mode mode )
123{
124    assert( session );
125    assert( mode == TR_ENCRYPTION_PREFERRED
126          || mode == TR_ENCRYPTION_REQUIRED
127          || mode == TR_CLEAR_PREFERRED );
128
129    session->encryptionMode = mode;
130}
131
132/***
133****
134***/
135
136struct tr_bindinfo
137{
138    int socket;
139    tr_address addr;
140    struct event * ev;
141};
142
143
144static void
145close_bindinfo( struct tr_bindinfo * b )
146{
147    if( ( b != NULL ) && ( b->socket >=0 ) )
148    {
149        event_free( b->ev );
150        b->ev = NULL;
151        tr_netCloseSocket( b->socket );
152    }
153}
154
155static void
156close_incoming_peer_port( tr_session * session )
157{
158    close_bindinfo( session->public_ipv4 );
159    close_bindinfo( session->public_ipv6 );
160}
161
162static void
163free_incoming_peer_port( tr_session * session )
164{
165    close_bindinfo( session->public_ipv4 );
166    tr_free( session->public_ipv4 );
167    session->public_ipv4 = NULL;
168
169    close_bindinfo( session->public_ipv6 );
170    tr_free( session->public_ipv6 );
171    session->public_ipv6 = NULL;
172}
173
174static void
175accept_incoming_peer( int fd, short what UNUSED, void * vsession )
176{
177    int clientSocket;
178    tr_port clientPort;
179    tr_address clientAddr;
180    tr_session * session = vsession;
181
182    clientSocket = tr_netAccept( session, fd, &clientAddr, &clientPort );
183    if( clientSocket > 0 ) {
184        tr_deepLog( __FILE__, __LINE__, NULL, "new incoming connection %d (%s)",
185                   clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
186        tr_peerMgrAddIncoming( session->peerMgr, &clientAddr, clientPort,
187                               clientSocket, NULL );
188    }
189}
190
191static void
192open_incoming_peer_port( tr_session * session )
193{
194    struct tr_bindinfo * b;
195
196    /* bind an ipv4 port to listen for incoming peers... */
197    b = session->public_ipv4;
198    b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false );
199    if( b->socket >= 0 ) {
200        b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
201        event_add( b->ev, NULL );
202    }
203
204    /* and do the exact same thing for ipv6, if it's supported... */
205    if( tr_net_hasIPv6( session->private_peer_port ) ) {
206        b = session->public_ipv6;
207        b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false );
208        if( b->socket >= 0 ) {
209            b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
210            event_add( b->ev, NULL );
211        }
212    }
213}
214
215const tr_address*
216tr_sessionGetPublicAddress( const tr_session * session, int tr_af_type, bool * is_default_value )
217{
218    const char * default_value;
219    const struct tr_bindinfo * bindinfo;
220
221    switch( tr_af_type )
222    {
223        case TR_AF_INET:
224            bindinfo = session->public_ipv4;
225            default_value = TR_DEFAULT_BIND_ADDRESS_IPV4;
226            break;
227
228        case TR_AF_INET6:
229            bindinfo = session->public_ipv6;
230            default_value = TR_DEFAULT_BIND_ADDRESS_IPV6;
231            break;
232
233        default:
234            bindinfo = NULL;
235            default_value = "";
236            break;
237    }
238
239    if( is_default_value && bindinfo )
240        *is_default_value = !tr_strcmp0( default_value, tr_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( 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
430bool
431tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName )
432{
433    int err = 0;
434    char * filename;
435    tr_benc fileSettings;
436    tr_benc sessionDefaults;
437    tr_benc tmp;
438    bool success = false;
439
440    assert( tr_bencIsDict( d ) );
441
442    /* initializing the defaults: caller may have passed in some app-level defaults.
443     * preserve those and use the session defaults to fill in any missing gaps. */
444    tr_bencInitDict( &sessionDefaults, 0 );
445    tr_sessionGetDefaultSettings( &sessionDefaults );
446    tr_bencMergeDicts( &sessionDefaults, d );
447    tmp = *d; *d = sessionDefaults; sessionDefaults = tmp;
448
449    /* if caller didn't specify a config dir, use the default */
450    if( !configDir || !*configDir )
451        configDir = tr_getDefaultConfigDir( appName );
452
453    /* file settings override the defaults */
454    filename = tr_buildPath( configDir, "settings.json", NULL );
455    err = tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename );
456    if( !err ) {
457        tr_bencMergeDicts( d, &fileSettings );
458        tr_bencFree( &fileSettings );
459    }
460
461    /* cleanup */
462    tr_bencFree( &sessionDefaults );
463    tr_free( filename );
464    success = (err==0) || (err==ENOENT);
465    return success;
466}
467
468void
469tr_sessionSaveSettings( tr_session    * session,
470                        const char    * configDir,
471                        const tr_benc * clientSettings )
472{
473    tr_benc settings;
474    char * filename = tr_buildPath( configDir, "settings.json", NULL );
475
476    assert( tr_bencIsDict( clientSettings ) );
477
478    tr_bencInitDict( &settings, 0 );
479
480    /* the existing file settings are the fallback values */
481    {
482        tr_benc fileSettings;
483        const int err = tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename );
484        if( !err )
485        {
486            tr_bencMergeDicts( &settings, &fileSettings );
487            tr_bencFree( &fileSettings );
488        }
489    }
490
491    /* the client's settings override the file settings */
492    tr_bencMergeDicts( &settings, clientSettings );
493
494    /* the session's true values override the file & client settings */
495    {
496        tr_benc sessionSettings;
497        tr_bencInitDict( &sessionSettings, 0 );
498        tr_sessionGetSettings( session, &sessionSettings );
499        tr_bencMergeDicts( &settings, &sessionSettings );
500        tr_bencFree( &sessionSettings );
501    }
502
503    /* save the result */
504    tr_bencToFile( &settings, TR_FMT_JSON, filename );
505
506    /* cleanup */
507    tr_free( filename );
508    tr_bencFree( &settings );
509}
510
511/***
512****
513***/
514
515/**
516 * Periodically save the .resume files of any torrents whose
517 * status has recently changed. This prevents loss of metadata
518 * in the case of a crash, unclean shutdown, clumsy user, etc.
519 */
520static void
521onSaveTimer( int foo UNUSED, short bar UNUSED, void * vsession )
522{
523    tr_torrent * tor = NULL;
524    tr_session * session = vsession;
525
526    if( tr_cacheFlushDone( session->cache ) )
527        tr_err( "Error while flushing completed pieces from cache" );
528
529    while(( tor = tr_torrentNext( session, tor )))
530        tr_torrentSave( tor );
531
532    tr_statsSaveDirty( session );
533
534    tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
535}
536
537/***
538****
539***/
540
541static void tr_sessionInitImpl( void * );
542
543struct init_data
544{
545    tr_session  * session;
546    const char  * configDir;
547    bool          done;
548    bool          messageQueuingEnabled;
549    tr_benc     * clientSettings;
550};
551
552tr_session *
553tr_sessionInit( const char  * tag,
554                const char  * configDir,
555                bool          messageQueuingEnabled,
556                tr_benc     * clientSettings )
557{
558    int64_t i;
559    tr_session * session;
560    struct init_data data;
561
562    assert( tr_bencIsDict( clientSettings ) );
563
564    tr_timeUpdate( time( NULL ) );
565
566    /* initialize the bare skeleton of the session object */
567    session = tr_new0( tr_session, 1 );
568    session->udp_socket = -1;
569    session->udp6_socket = -1;
570    session->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( &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    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, bool b )
950{
951    assert( tr_isSession( session ) );
952    assert( tr_isBool( b ) );
953
954    session->isIncompleteFileNamingEnabled = b;
955}
956
957bool
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, bool b )
993{
994    assert( tr_isSession( session ) );
995    assert( tr_isBool( b ) );
996
997    session->isIncompleteDirEnabled = b;
998}
999
1000bool
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
1049bool
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                                    bool random )
1112{
1113    assert( tr_isSession( session ) );
1114
1115    session->isPortRandom = random;
1116}
1117
1118bool
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, 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
1154bool
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, 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
1190bool
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
1212bool
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}
1229bool
1230tr_sessionGetActiveSpeedLimit_KBps( const tr_session  * session,
1231                                    tr_direction        dir,
1232                                    double            * setme_KBps )
1233{
1234    int Bps = 0;
1235    const 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 bool isLimited = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &limit_Bps );
1245    const 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             bool enabled, 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                bool * enabled,
1323                bool * changed )
1324{
1325    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    bool enabled;
1354    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, 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
1432bool
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        bool enabled, changed;
1487        testTurtleTime( t, &enabled, &changed );
1488        useAltSpeed( s, t, enabled, true );
1489    }
1490}
1491
1492void
1493tr_sessionUseAltSpeedTime( tr_session * s, 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
1506bool
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, bool enabled )
1575{
1576    useAltSpeed( session, &session->turtle, enabled, true );
1577}
1578
1579bool
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, bool isPaused )
1646{
1647    assert( tr_isSession( session ) );
1648
1649    session->pauseAddedTorrent = isPaused;
1650}
1651
1652bool
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, bool deleteSource )
1662{
1663    assert( tr_isSession( session ) );
1664
1665    session->deleteSourceTorrent = deleteSource;
1666}
1667
1668bool
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_dhtUninit( 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    /* Close the announcer *after* closing the torrents
1762       so that all the &event=stopped messages will be
1763       queued to be sent by tr_announcerClose() */
1764    tr_announcerClose( session );
1765
1766    /* and this goes *after* announcer close so that
1767       it won't be idle until the announce events are sent... */
1768    tr_webClose( session, TR_WEB_CLOSE_WHEN_IDLE );
1769
1770    tr_cacheFree( session->cache );
1771    session->cache = NULL;
1772
1773    /* gotta keep udp running long enough to send out all
1774       the &event=stopped UDP tracker messages */
1775    while( !tr_tracker_udp_is_empty( session ) ) {
1776        tr_tracker_udp_upkeep( session );
1777        tr_wait_msec( 100 );
1778    }
1779
1780    /* we had to wait until UDP trackers were closed before closing these: */
1781    evdns_base_free( session->evdns_base, 0 );
1782    session->evdns_base = NULL;
1783    tr_tracker_udp_close( session );
1784    tr_udpUninit( session );
1785
1786    tr_statsClose( session );
1787    tr_peerMgrFree( session->peerMgr );
1788
1789    closeBlocklists( session );
1790
1791    tr_fdClose( session );
1792
1793    session->isClosed = true;
1794}
1795
1796static int
1797deadlineReached( const time_t deadline )
1798{
1799    return time( NULL ) >= deadline;
1800}
1801
1802#define SHUTDOWN_MAX_SECONDS 20
1803
1804void
1805tr_sessionClose( tr_session * session )
1806{
1807    const time_t deadline = time( NULL ) + SHUTDOWN_MAX_SECONDS;
1808
1809    assert( tr_isSession( session ) );
1810
1811    dbgmsg( "shutting down transmission session %p... now is %zu, deadline is %zu", session, (size_t)time(NULL), (size_t)deadline );
1812
1813    /* close the session */
1814    tr_runInEventThread( session, sessionCloseImpl, session );
1815    while( !session->isClosed && !deadlineReached( deadline ) )
1816    {
1817        dbgmsg( "waiting for the libtransmission thread to finish" );
1818        tr_wait_msec( 100 );
1819    }
1820
1821    /* "shared" and "tracker" have live sockets,
1822     * so we need to keep the transmission thread alive
1823     * for a bit while they tell the router & tracker
1824     * that we're closing now */
1825    while( ( session->shared || session->web || session->announcer || session->announcer_udp )
1826           && !deadlineReached( deadline ) )
1827    {
1828        dbgmsg( "waiting on port unmap (%p) or announcer (%p)... now %zu deadline %zu",
1829                session->shared, session->announcer, (size_t)time(NULL), (size_t)deadline );
1830        tr_wait_msec( 100 );
1831    }
1832
1833    tr_webClose( session, TR_WEB_CLOSE_NOW );
1834
1835    /* close the libtransmission thread */
1836    tr_eventClose( session );
1837    while( session->events != NULL )
1838    {
1839        static bool forced = false;
1840        dbgmsg( "waiting for libtransmission thread to finish... now %zu deadline %zu", (size_t)time(NULL), (size_t)deadline );
1841        tr_wait_msec( 500 );
1842        if( deadlineReached( deadline ) && !forced )
1843        {
1844            dbgmsg( "calling event_loopbreak()" );
1845            forced = true;
1846            event_base_loopbreak( session->event_base );
1847        }
1848        if( deadlineReached( deadline+3 ) )
1849        {
1850            dbgmsg( "deadline+3 reached... calling break...\n" );
1851            break;
1852        }
1853    }
1854
1855    /* free the session memory */
1856    tr_bencFree( &session->removedTorrents );
1857    tr_bandwidthFree( session->bandwidth );
1858    tr_bitfieldDestruct( &session->turtle.minutes );
1859    tr_lockFree( session->lock );
1860    if( session->metainfoLookup ) {
1861        tr_bencFree( session->metainfoLookup );
1862        tr_free( session->metainfoLookup );
1863    }
1864    tr_free( session->torrentDoneScript );
1865    tr_free( session->buffer );
1866    tr_free( session->tag );
1867    tr_free( session->configDir );
1868    tr_free( session->resumeDir );
1869    tr_free( session->torrentDir );
1870    tr_free( session->downloadDir );
1871    tr_free( session->incompleteDir );
1872    tr_free( session->blocklist_url );
1873    tr_free( session->peer_congestion_algorithm );
1874    tr_free( session );
1875}
1876
1877tr_torrent **
1878tr_sessionLoadTorrents( tr_session * session,
1879                        tr_ctor    * ctor,
1880                        int        * setmeCount )
1881{
1882    int           i, n = 0;
1883    struct stat   sb;
1884    DIR *         odir = NULL;
1885    const char *  dirname = tr_getTorrentDir( session );
1886    tr_torrent ** torrents;
1887    tr_list *     l = NULL, *list = NULL;
1888
1889    assert( tr_isSession( session ) );
1890
1891    tr_ctorSetSave( ctor, false ); /* since we already have them */
1892
1893    if( !stat( dirname, &sb )
1894      && S_ISDIR( sb.st_mode )
1895      && ( ( odir = opendir ( dirname ) ) ) )
1896    {
1897        struct dirent *d;
1898        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1899        {
1900            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
1901            {
1902                tr_torrent * tor;
1903                char * path = tr_buildPath( dirname, d->d_name, NULL );
1904                tr_ctorSetMetainfoFromFile( ctor, path );
1905                if(( tor = tr_torrentNew( ctor, NULL )))
1906                {
1907                    tr_list_append( &list, tor );
1908                    ++n;
1909                }
1910                tr_free( path );
1911            }
1912        }
1913        closedir( odir );
1914    }
1915
1916    torrents = tr_new( tr_torrent *, n );
1917    for( i = 0, l = list; l != NULL; l = l->next )
1918        torrents[i++] = (tr_torrent*) l->data;
1919    assert( i == n );
1920
1921    tr_list_free( &list, NULL );
1922
1923    if( n )
1924        tr_inf( _( "Loaded %d torrents" ), n );
1925
1926    if( setmeCount )
1927        *setmeCount = n;
1928    return torrents;
1929}
1930
1931/***
1932****
1933***/
1934
1935void
1936tr_sessionSetPexEnabled( tr_session * session, bool enabled )
1937{
1938    assert( tr_isSession( session ) );
1939
1940    session->isPexEnabled = enabled != 0;
1941}
1942
1943bool
1944tr_sessionIsPexEnabled( const tr_session * session )
1945{
1946    assert( tr_isSession( session ) );
1947
1948    return session->isPexEnabled;
1949}
1950
1951bool
1952tr_sessionAllowsDHT( const tr_session * session UNUSED )
1953{
1954    return tr_sessionIsDHTEnabled( session );
1955}
1956
1957bool
1958tr_sessionIsDHTEnabled( const tr_session * session )
1959{
1960    assert( tr_isSession( session ) );
1961
1962    return session->isDHTEnabled;
1963}
1964
1965static void
1966toggleDHTImpl(  void * data )
1967{
1968    tr_session * session = data;
1969    assert( tr_isSession( session ) );
1970
1971    tr_udpUninit( session );
1972    session->isDHTEnabled = !session->isDHTEnabled;
1973    tr_udpInit( session );
1974}
1975
1976void
1977tr_sessionSetDHTEnabled( tr_session * session, bool enabled )
1978{
1979    assert( tr_isSession( session ) );
1980    assert( tr_isBool( enabled ) );
1981
1982    if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1983        tr_runInEventThread( session, toggleDHTImpl, session );
1984}
1985
1986/***
1987****
1988***/
1989
1990bool
1991tr_sessionIsUTPEnabled( const tr_session * session )
1992{
1993    assert( tr_isSession( session ) );
1994
1995#ifdef WITH_UTP
1996    return session->isUTPEnabled;
1997#else
1998    return false;
1999#endif
2000}
2001
2002static void
2003toggle_utp(  void * data )
2004{
2005    tr_session * session = data;
2006    assert( tr_isSession( session ) );
2007
2008    session->isUTPEnabled = !session->isUTPEnabled;
2009
2010    tr_udpSetSocketBuffers( session );
2011
2012    /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
2013       explanation. */
2014}
2015
2016void
2017tr_sessionSetUTPEnabled( tr_session * session, bool enabled )
2018{
2019    assert( tr_isSession( session ) );
2020    assert( tr_isBool( enabled ) );
2021
2022    if( ( enabled != 0 ) != ( session->isUTPEnabled != 0 ) )
2023        tr_runInEventThread( session, toggle_utp, session );
2024}
2025
2026/***
2027****
2028***/
2029
2030static void
2031toggleLPDImpl(  void * data )
2032{
2033    tr_session * session = data;
2034    assert( tr_isSession( session ) );
2035
2036    if( session->isLPDEnabled )
2037        tr_lpdUninit( session );
2038
2039    session->isLPDEnabled = !session->isLPDEnabled;
2040
2041    if( session->isLPDEnabled )
2042        tr_lpdInit( session, &session->public_ipv4->addr );
2043}
2044
2045void
2046tr_sessionSetLPDEnabled( tr_session * session, bool enabled )
2047{
2048    assert( tr_isSession( session ) );
2049    assert( tr_isBool( enabled ) );
2050
2051    if( ( enabled != 0 ) != ( session->isLPDEnabled != 0 ) )
2052        tr_runInEventThread( session, toggleLPDImpl, session );
2053}
2054
2055bool
2056tr_sessionIsLPDEnabled( const tr_session * session )
2057{
2058    assert( tr_isSession( session ) );
2059
2060    return session->isLPDEnabled;
2061}
2062
2063bool
2064tr_sessionAllowsLPD( const tr_session * session )
2065{
2066    return tr_sessionIsLPDEnabled( session );
2067}
2068
2069/***
2070****
2071***/
2072
2073void
2074tr_sessionSetCacheLimit_MB( tr_session * session, int max_bytes )
2075{
2076    assert( tr_isSession( session ) );
2077
2078    tr_cacheSetLimit( session->cache, toMemBytes( max_bytes ) );
2079}
2080
2081int
2082tr_sessionGetCacheLimit_MB( const tr_session * session )
2083{
2084    assert( tr_isSession( session ) );
2085
2086    return toMemMB( tr_cacheGetLimit( session->cache ) );
2087}
2088
2089/***
2090****
2091***/
2092
2093struct port_forwarding_data
2094{
2095    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, 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
2117bool
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 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
2240bool
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, bool isEnabled )
2250{
2251    tr_list * l;
2252
2253    assert( tr_isSession( session ) );
2254
2255    session->isBlocklistEnabled = isEnabled != 0;
2256
2257    for( l=session->blocklists; l!=NULL; l=l->next )
2258        _tr_blocklistSetEnabled( l->data, isEnabled );
2259}
2260
2261bool
2262tr_blocklistExists( const tr_session * session )
2263{
2264    assert( tr_isSession( session ) );
2265
2266    return session->blocklists != NULL;
2267}
2268
2269int
2270tr_blocklistSetContent( tr_session * session, const char * contentFilename )
2271{
2272    tr_list * l;
2273    int ruleCount;
2274    tr_blocklist * b;
2275    const char * defaultName = DEFAULT_BLOCKLIST_FILENAME;
2276    tr_sessionLock( session );
2277
2278    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
2279        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
2280                               defaultName ) )
2281            b = l->data;
2282
2283    if( !b )
2284    {
2285        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
2286        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
2287        tr_list_append( &session->blocklists, b );
2288        tr_free( path );
2289    }
2290
2291    ruleCount = _tr_blocklistSetContent( b, contentFilename );
2292    tr_sessionUnlock( session );
2293    return ruleCount;
2294}
2295
2296bool
2297tr_sessionIsAddressBlocked( const tr_session * session,
2298                            const tr_address * addr )
2299{
2300    tr_list * l;
2301
2302    assert( tr_isSession( session ) );
2303
2304    for( l = session->blocklists; l; l = l->next )
2305        if( _tr_blocklistHasAddress( l->data, addr ) )
2306            return true;
2307    return false;
2308}
2309
2310void
2311tr_blocklistSetURL( tr_session * session, const char * url )
2312{
2313    if( session->blocklist_url != url )
2314    {
2315        tr_free( session->blocklist_url );
2316        session->blocklist_url = tr_strdup( url );
2317    }
2318}
2319
2320const char *
2321tr_blocklistGetURL ( const tr_session * session )
2322{
2323    return session->blocklist_url;
2324}
2325
2326
2327/***
2328****
2329***/
2330
2331static void
2332metainfoLookupInit( tr_session * session )
2333{
2334    struct stat  sb;
2335    const char * dirname = tr_getTorrentDir( session );
2336    DIR *        odir = NULL;
2337    tr_ctor *    ctor = NULL;
2338    tr_benc * lookup;
2339    int n = 0;
2340
2341    assert( tr_isSession( session ) );
2342
2343    /* walk through the directory and find the mappings */
2344    lookup = tr_new0( tr_benc, 1 );
2345    tr_bencInitDict( lookup, 0 );
2346    ctor = tr_ctorNew( session );
2347    tr_ctorSetSave( ctor, false ); /* since we already have them */
2348    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
2349    {
2350        struct dirent *d;
2351        while(( d = readdir( odir )))
2352        {
2353            if( tr_str_has_suffix( d->d_name, ".torrent" ) )
2354            {
2355                tr_info inf;
2356                char * path = tr_buildPath( dirname, d->d_name, NULL );
2357                tr_ctorSetMetainfoFromFile( ctor, path );
2358                if( !tr_torrentParse( ctor, &inf ) )
2359                {
2360                    ++n;
2361                    tr_bencDictAddStr( lookup, inf.hashString, path );
2362                }
2363                tr_free( path );
2364            }
2365        }
2366        closedir( odir );
2367    }
2368    tr_ctorFree( ctor );
2369
2370    session->metainfoLookup = lookup;
2371    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
2372}
2373
2374const char*
2375tr_sessionFindTorrentFile( const tr_session * session,
2376                           const char       * hashString )
2377{
2378    const char * filename = NULL;
2379    if( !session->metainfoLookup )
2380        metainfoLookupInit( (tr_session*)session );
2381    tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
2382    return filename;
2383}
2384
2385void
2386tr_sessionSetTorrentFile( tr_session * session,
2387                          const char * hashString,
2388                          const char * filename )
2389{
2390    /* since we walk session->configDir/torrents/ to build the lookup table,
2391     * and tr_sessionSetTorrentFile() is just to tell us there's a new file
2392     * in that same directory, we don't need to do anything here if the
2393     * lookup table hasn't been built yet */
2394    if( session->metainfoLookup )
2395        tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
2396}
2397
2398/***
2399****
2400***/
2401
2402void
2403tr_sessionSetRPCEnabled( tr_session * session, bool isEnabled )
2404{
2405    assert( tr_isSession( session ) );
2406
2407    tr_rpcSetEnabled( session->rpcServer, isEnabled );
2408}
2409
2410bool
2411tr_sessionIsRPCEnabled( const tr_session * session )
2412{
2413    assert( tr_isSession( session ) );
2414
2415    return tr_rpcIsEnabled( session->rpcServer );
2416}
2417
2418void
2419tr_sessionSetRPCPort( tr_session * session,
2420                      tr_port      port )
2421{
2422    assert( tr_isSession( session ) );
2423
2424    tr_rpcSetPort( session->rpcServer, port );
2425}
2426
2427tr_port
2428tr_sessionGetRPCPort( const tr_session * session )
2429{
2430    assert( tr_isSession( session ) );
2431
2432    return tr_rpcGetPort( session->rpcServer );
2433}
2434
2435void
2436tr_sessionSetRPCUrl( tr_session * session,
2437                     const char * url )
2438{
2439    assert( tr_isSession( session ) );
2440
2441    tr_rpcSetUrl( session->rpcServer, url );
2442}
2443
2444const char*
2445tr_sessionGetRPCUrl( const tr_session * session )
2446{
2447    assert( tr_isSession( session ) );
2448
2449    return tr_rpcGetUrl( session->rpcServer );
2450}
2451
2452void
2453tr_sessionSetRPCCallback( tr_session * session,
2454                          tr_rpc_func  func,
2455                          void *       user_data )
2456{
2457    assert( tr_isSession( session ) );
2458
2459    session->rpc_func = func;
2460    session->rpc_func_user_data = user_data;
2461}
2462
2463void
2464tr_sessionSetRPCWhitelist( tr_session * session,
2465                           const char * whitelist )
2466{
2467    assert( tr_isSession( session ) );
2468
2469    tr_rpcSetWhitelist( session->rpcServer, whitelist );
2470}
2471
2472const char*
2473tr_sessionGetRPCWhitelist( const tr_session * session )
2474{
2475    assert( tr_isSession( session ) );
2476
2477    return tr_rpcGetWhitelist( session->rpcServer );
2478}
2479
2480void
2481tr_sessionSetRPCWhitelistEnabled( tr_session * session, bool isEnabled )
2482{
2483    assert( tr_isSession( session ) );
2484
2485    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
2486}
2487
2488bool
2489tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
2490{
2491    assert( tr_isSession( session ) );
2492
2493    return tr_rpcGetWhitelistEnabled( session->rpcServer );
2494}
2495
2496
2497void
2498tr_sessionSetRPCPassword( tr_session * session,
2499                          const char * password )
2500{
2501    assert( tr_isSession( session ) );
2502
2503    tr_rpcSetPassword( session->rpcServer, password );
2504}
2505
2506const char*
2507tr_sessionGetRPCPassword( const tr_session * session )
2508{
2509    assert( tr_isSession( session ) );
2510
2511    return tr_rpcGetPassword( session->rpcServer );
2512}
2513
2514void
2515tr_sessionSetRPCUsername( tr_session * session,
2516                          const char * username )
2517{
2518    assert( tr_isSession( session ) );
2519
2520    tr_rpcSetUsername( session->rpcServer, username );
2521}
2522
2523const char*
2524tr_sessionGetRPCUsername( const tr_session * session )
2525{
2526    assert( tr_isSession( session ) );
2527
2528    return tr_rpcGetUsername( session->rpcServer );
2529}
2530
2531void
2532tr_sessionSetRPCPasswordEnabled( tr_session * session, bool isEnabled )
2533{
2534    assert( tr_isSession( session ) );
2535
2536    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2537}
2538
2539bool
2540tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2541{
2542    assert( tr_isSession( session ) );
2543
2544    return tr_rpcIsPasswordEnabled( session->rpcServer );
2545}
2546
2547const char *
2548tr_sessionGetRPCBindAddress( const tr_session * session )
2549{
2550    assert( tr_isSession( session ) );
2551
2552    return tr_rpcGetBindAddress( session->rpcServer );
2553}
2554
2555/****
2556*****
2557****/
2558
2559bool
2560tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session )
2561{
2562    assert( tr_isSession( session ) );
2563
2564    return session->isTorrentDoneScriptEnabled;
2565}
2566
2567void
2568tr_sessionSetTorrentDoneScriptEnabled( tr_session * session, bool isEnabled )
2569{
2570    assert( tr_isSession( session ) );
2571    assert( tr_isBool( isEnabled ) );
2572
2573    session->isTorrentDoneScriptEnabled = isEnabled;
2574}
2575
2576const char *
2577tr_sessionGetTorrentDoneScript( const tr_session * session )
2578{
2579    assert( tr_isSession( session ) );
2580
2581    return session->torrentDoneScript;
2582}
2583
2584void
2585tr_sessionSetTorrentDoneScript( tr_session * session, const char * scriptFilename )
2586{
2587    assert( tr_isSession( session ) );
2588
2589    if( session->torrentDoneScript != scriptFilename )
2590    {
2591        tr_free( session->torrentDoneScript );
2592        session->torrentDoneScript = tr_strdup( scriptFilename );
2593    }
2594}
2595
2596/***
2597****
2598***/
2599
2600void
2601tr_sessionSetWebConfigFunc( tr_session * session, void (*func)(tr_session*, void*, const char* ) )
2602{
2603    session->curl_easy_config_func = func;
2604}
Note: See TracBrowser for help on using the repository browser.