source: trunk/libtransmission/session.c @ 12012

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

(trunk libT) #4048 "use bitsets instead of bitfield in tr_completion" -- done.

Excuse the sprawl. Much of this didn't fit into self-contained commits.

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