~ubuntu-branches/ubuntu/lucid/transmission/lucid

« back to all changes in this revision

Viewing changes to .pc/disable_web_ui.patch/libtransmission/session.c

  • Committer: Bazaar Package Importer
  • Author(s): Krzysztof Klimonda, Krzysztof Klimonda, Chris Coulson
  • Date: 2010-03-03 02:55:26 UTC
  • mfrom: (1.1.34 upstream) (2.1.17 sid)
  • Revision ID: james.westby@ubuntu.com-20100303025526-qcjmpnlvk9jv3y5o
Tags: 1.92-0ubuntu1
[ Krzysztof Klimonda ]
* New upstream release (LP: #538034), rebased on debian testing.
  Remaining changes:
  - debian/control:
    + Added replaces & provides clutch (now included as part of transmission).
      Can be removed in lucid+1
    + Added liblaunchpad-integration-dev and lsb-release to Build-Depends
  - debian/rules:
    + create a po template during package build.
  - debian/patches/01_lpi.patch:
    + integrate transmission with launchpad
  - debian/patches/20_add_x-ubuntu-gettext-domain.diff:
    + add x-ubuntu-gettext-domain to .desktop file.
  - debian/transmission-daemon.default:
    - remove --auth from OPTIONS
  - debian/control, debian/rules:
    + build transmission gtk+ client with both gconf and libcanberra support.
  - debian/patches/dont_build_libevent.patch:
    + disable libevent in configure.ac and Makefile.am because we use autotools
      to regenerate build files.
  - lucid/debian/patches/updateminiupnpcstrings_double_escape_slash.patch:
    + Deleted as the bug is fixed upstream
* Fixes bugs:
  - Fix directory selection error in GTK+ 2.19 (LP: #518692)
  - Transmission "Set Location" - dialog doesn't disappear (LP: #529037)
  - The "Torrent Options" dialog's Torrent Priority row gets too much
    vertical stretch (LP: #527299)
  - "Open Folder" behavior can be confusing for single-file torrents
    (LP: #505861)
* Refreshed 99_autoreconf.patch

[ Chris Coulson ]
* debian/patches/disable_web_ui.patch:
  - Disable the web UI by default again (LP: #542194)

Show diffs side-by-side

added added

removed removed

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