source: trunk/libtransmission/session.c @ 11960

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

add configure script switch to enable/disable utp

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