Transmission 2.33
[tomato.git] / release / src / router / transmission / libtransmission / session.c
blobb4f4d22abe9c973d666ab529b4a13b31a7c143c6
1 /*
2 * This file Copyright (C) Mnemosyne LLC
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.
10 * $Id: session.c 12545 2011-07-13 03:23:37Z jordan $
13 #include <assert.h>
14 #include <errno.h> /* ENOENT */
15 #include <stdlib.h>
16 #include <string.h> /* memcpy */
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 */
24 #include <event2/dns.h> /* evdns_base_free() */
25 #include <event2/event.h>
27 //#define TR_SHOW_DEPRECATED
28 #include "transmission.h"
29 #include "announcer.h"
30 #include "bandwidth.h"
31 #include "bencode.h"
32 #include "blocklist.h"
33 #include "cache.h"
34 #include "crypto.h"
35 #include "fdlimit.h"
36 #include "list.h"
37 #include "net.h"
38 #include "peer-io.h"
39 #include "peer-mgr.h"
40 #include "platform.h" /* tr_lock, tr_getTorrentDir(), tr_getFreeSpace() */
41 #include "port-forwarding.h"
42 #include "rpc-server.h"
43 #include "session.h"
44 #include "stats.h"
45 #include "torrent.h"
46 #include "tr-dht.h" /* tr_dhtUpkeep() */
47 #include "tr-udp.h"
48 #include "tr-utp.h"
49 #include "tr-lpd.h"
50 #include "trevent.h"
51 #include "utils.h"
52 #include "verify.h"
53 #include "version.h"
54 #include "web.h"
56 enum
58 #ifdef TR_LIGHTWEIGHT
59 DEFAULT_CACHE_SIZE_MB = 2,
60 DEFAULT_PREFETCH_ENABLED = false,
61 #else
62 DEFAULT_CACHE_SIZE_MB = 4,
63 DEFAULT_PREFETCH_ENABLED = true,
64 #endif
65 SAVE_INTERVAL_SECS = 360
69 #define dbgmsg( ... ) \
70 do { \
71 if( tr_deepLoggingIsActive( ) ) \
72 tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
73 } while( 0 )
75 static tr_port
76 getRandomPort( tr_session * s )
78 return tr_cryptoWeakRandInt( s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow;
81 /* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
82 characters, where x is the major version number, y is the
83 minor version number, z is the maintenance number, and b
84 designates beta (Azureus-style) */
85 void
86 tr_peerIdInit( uint8_t * buf )
88 int i;
89 int val;
90 int total = 0;
91 const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
92 const int base = 36;
94 memcpy( buf, PEERID_PREFIX, 8 );
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];
103 val = total % base ? base - ( total % base ) : 0;
104 buf[19] = pool[val];
105 buf[20] = '\0';
108 /***
109 ****
110 ***/
112 tr_encryption_mode
113 tr_sessionGetEncryption( tr_session * session )
115 assert( session );
117 return session->encryptionMode;
120 void
121 tr_sessionSetEncryption( tr_session * session,
122 tr_encryption_mode mode )
124 assert( session );
125 assert( mode == TR_ENCRYPTION_PREFERRED
126 || mode == TR_ENCRYPTION_REQUIRED
127 || mode == TR_CLEAR_PREFERRED );
129 session->encryptionMode = mode;
132 /***
133 ****
134 ***/
136 struct tr_bindinfo
138 int socket;
139 tr_address addr;
140 struct event * ev;
144 static void
145 close_bindinfo( struct tr_bindinfo * b )
147 if( ( b != NULL ) && ( b->socket >=0 ) )
149 event_free( b->ev );
150 b->ev = NULL;
151 tr_netCloseSocket( b->socket );
155 static void
156 close_incoming_peer_port( tr_session * session )
158 close_bindinfo( session->public_ipv4 );
159 close_bindinfo( session->public_ipv6 );
162 static void
163 free_incoming_peer_port( tr_session * session )
165 close_bindinfo( session->public_ipv4 );
166 tr_free( session->public_ipv4 );
167 session->public_ipv4 = NULL;
169 close_bindinfo( session->public_ipv6 );
170 tr_free( session->public_ipv6 );
171 session->public_ipv6 = NULL;
174 static void
175 accept_incoming_peer( int fd, short what UNUSED, void * vsession )
177 int clientSocket;
178 tr_port clientPort;
179 tr_address clientAddr;
180 tr_session * session = vsession;
182 clientSocket = tr_netAccept( session, fd, &clientAddr, &clientPort );
183 if( clientSocket > 0 ) {
184 tr_deepLog( __FILE__, __LINE__, NULL, "new incoming connection %d (%s)",
185 clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
186 tr_peerMgrAddIncoming( session->peerMgr, &clientAddr, clientPort,
187 clientSocket, NULL );
191 static void
192 open_incoming_peer_port( tr_session * session )
194 struct tr_bindinfo * b;
196 /* bind an ipv4 port to listen for incoming peers... */
197 b = session->public_ipv4;
198 b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false );
199 if( b->socket >= 0 ) {
200 b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
201 event_add( b->ev, NULL );
204 /* and do the exact same thing for ipv6, if it's supported... */
205 if( tr_net_hasIPv6( session->private_peer_port ) ) {
206 b = session->public_ipv6;
207 b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false );
208 if( b->socket >= 0 ) {
209 b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
210 event_add( b->ev, NULL );
215 const tr_address*
216 tr_sessionGetPublicAddress( const tr_session * session, int tr_af_type, bool * is_default_value )
218 const char * default_value;
219 const struct tr_bindinfo * bindinfo;
221 switch( tr_af_type )
223 case TR_AF_INET:
224 bindinfo = session->public_ipv4;
225 default_value = TR_DEFAULT_BIND_ADDRESS_IPV4;
226 break;
228 case TR_AF_INET6:
229 bindinfo = session->public_ipv6;
230 default_value = TR_DEFAULT_BIND_ADDRESS_IPV6;
231 break;
233 default:
234 bindinfo = NULL;
235 default_value = "";
236 break;
239 if( is_default_value && bindinfo )
240 *is_default_value = !tr_strcmp0( default_value, tr_address_to_string( &bindinfo->addr ) );
242 return bindinfo ? &bindinfo->addr : NULL;
245 /***
246 ****
247 ***/
249 #ifdef TR_LIGHTWEIGHT
250 #define TR_DEFAULT_ENCRYPTION TR_CLEAR_PREFERRED
251 #else
252 #define TR_DEFAULT_ENCRYPTION TR_ENCRYPTION_PREFERRED
253 #endif
255 static int
256 parse_tos( const char *str )
258 char *p;
259 int value;
261 if( !evutil_ascii_strcasecmp( str, "" ) )
262 return 0;
263 if( !evutil_ascii_strcasecmp( str, "default" ) )
264 return 0;
266 if( !evutil_ascii_strcasecmp( str, "lowcost" ) )
267 return 0x10;
268 if( !evutil_ascii_strcasecmp( str, "mincost" ) )
269 return 0x10;
271 if( !evutil_ascii_strcasecmp( str, "throughput" ) )
272 return 0x08;
273 if( !evutil_ascii_strcasecmp( str, "reliability" ) )
274 return 0x04;
275 if( !evutil_ascii_strcasecmp( str, "lowdelay" ) )
276 return 0x02;
278 value = strtol( str, &p, 0 );
279 if( !p || ( p == str ) )
280 return 0;
282 return value;
285 static const char *
286 format_tos(int value)
288 static char buf[8];
289 switch(value) {
290 case 0: return "default";
291 case 0x10: return "lowcost";
292 case 0x08: return "throughput";
293 case 0x04: return "reliability";
294 case 0x02: return "lowdelay";
295 default:
296 snprintf(buf, 8, "%d", value);
297 return buf;
301 void
302 tr_sessionGetDefaultSettings( tr_benc * d )
304 assert( tr_bencIsDict( d ) );
306 tr_bencDictReserve( d, 60 );
307 tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, false );
308 tr_bencDictAddStr ( d, TR_PREFS_KEY_BLOCKLIST_URL, "http://www.example.com/blocklist" );
309 tr_bencDictAddInt ( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, DEFAULT_CACHE_SIZE_MB );
310 tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, true );
311 tr_bencDictAddBool( d, TR_PREFS_KEY_UTP_ENABLED, true );
312 tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, false );
313 tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR, tr_getDefaultDownloadDir( ) );
314 tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED_KBps, 100 );
315 tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, false );
316 tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION, TR_DEFAULT_ENCRYPTION );
317 tr_bencDictAddInt ( d, TR_PREFS_KEY_IDLE_LIMIT, 30 );
318 tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, false );
319 tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_getDefaultDownloadDir( ) );
320 tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, false );
321 tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF );
322 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
323 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT, atoi( TR_DEFAULT_PEER_LIMIT_TORRENT_STR ) );
324 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT, atoi( TR_DEFAULT_PEER_PORT_STR ) );
325 tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, false );
326 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, 49152 );
327 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, 65535 );
328 tr_bencDictAddStr ( d, TR_PREFS_KEY_PEER_SOCKET_TOS, TR_DEFAULT_PEER_SOCKET_TOS_STR );
329 tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED, true );
330 tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, true );
331 tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION, TR_PREALLOCATE_SPARSE );
332 tr_bencDictAddBool( d, TR_PREFS_KEY_PREFETCH_ENABLED, DEFAULT_PREFETCH_ENABLED );
333 tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO, 2.0 );
334 tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED, false );
335 tr_bencDictAddBool( d, TR_PREFS_KEY_RENAME_PARTIAL_FILES, true );
336 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, false );
337 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS, "0.0.0.0" );
338 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED, false );
339 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD, "" );
340 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, "" );
341 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, TR_DEFAULT_RPC_WHITELIST );
342 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, true );
343 tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, atoi( TR_DEFAULT_RPC_PORT_STR ) );
344 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_URL, TR_DEFAULT_RPC_URL_STR );
345 tr_bencDictAddStr ( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, "" );
346 tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, false );
347 tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED, false );
348 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP_KBps, 50 ); /* half the regular */
349 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN_KBps, 50 ); /* half the regular */
350 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, 540 ); /* 9am */
351 tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, false );
352 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END, 1020 ); /* 5pm */
353 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, TR_SCHED_ALL );
354 tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED_KBps, 100 );
355 tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, false );
356 tr_bencDictAddInt ( d, TR_PREFS_KEY_UMASK, 022 );
357 tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 );
358 tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, TR_DEFAULT_BIND_ADDRESS_IPV4 );
359 tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, TR_DEFAULT_BIND_ADDRESS_IPV6 );
360 tr_bencDictAddBool( d, TR_PREFS_KEY_START, true );
361 tr_bencDictAddBool( d, TR_PREFS_KEY_TRASH_ORIGINAL, false );
364 void
365 tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
367 assert( tr_bencIsDict( d ) );
369 tr_bencDictReserve( d, 60 );
370 tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, tr_blocklistIsEnabled( s ) );
371 tr_bencDictAddStr ( d, TR_PREFS_KEY_BLOCKLIST_URL, tr_blocklistGetURL( s ) );
372 tr_bencDictAddInt ( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, tr_sessionGetCacheLimit_MB( s ) );
373 tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, s->isDHTEnabled );
374 tr_bencDictAddBool( d, TR_PREFS_KEY_UTP_ENABLED, s->isUTPEnabled );
375 tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, s->isLPDEnabled );
376 tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR, s->downloadDir );
377 tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED_KBps, tr_sessionGetSpeedLimit_KBps( s, TR_DOWN ) );
378 tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, tr_sessionIsSpeedLimited( s, TR_DOWN ) );
379 tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION, s->encryptionMode );
380 tr_bencDictAddInt ( d, TR_PREFS_KEY_IDLE_LIMIT, tr_sessionGetIdleLimit( s ) );
381 tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, tr_sessionIsIdleLimited( s ) );
382 tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_sessionGetIncompleteDir( s ) );
383 tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, tr_sessionIsIncompleteDirEnabled( s ) );
384 tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, tr_getMessageLevel( ) );
385 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, s->peerLimit );
386 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT, s->peerLimitPerTorrent );
387 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT, tr_sessionGetPeerPort( s ) );
388 tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, s->isPortRandom );
389 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, s->randomPortLow );
390 tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, s->randomPortHigh );
391 tr_bencDictAddStr ( d, TR_PREFS_KEY_PEER_SOCKET_TOS, format_tos(s->peerSocketTOS) );
392 tr_bencDictAddStr ( d, TR_PREFS_KEY_PEER_CONGESTION_ALGORITHM, s->peer_congestion_algorithm );
393 tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED, s->isPexEnabled );
394 tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, tr_sessionIsPortForwardingEnabled( s ) );
395 tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION, s->preallocationMode );
396 tr_bencDictAddInt ( d, TR_PREFS_KEY_PREFETCH_ENABLED, s->isPrefetchEnabled );
397 tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO, s->desiredRatio );
398 tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED, s->isRatioLimited );
399 tr_bencDictAddBool( d, TR_PREFS_KEY_RENAME_PARTIAL_FILES, tr_sessionIsIncompleteFileNamingEnabled( s ) );
400 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, tr_sessionIsRPCPasswordEnabled( s ) );
401 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS, tr_sessionGetRPCBindAddress( s ) );
402 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED, tr_sessionIsRPCEnabled( s ) );
403 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD, tr_sessionGetRPCPassword( s ) );
404 tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, tr_sessionGetRPCPort( s ) );
405 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_URL, tr_sessionGetRPCUrl( s ) );
406 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, tr_sessionGetRPCUsername( s ) );
407 tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, tr_sessionGetRPCWhitelist( s ) );
408 tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled( s ) );
409 tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, tr_sessionIsTorrentDoneScriptEnabled( s ) );
410 tr_bencDictAddStr ( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, tr_sessionGetTorrentDoneScript( s ) );
411 tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED, tr_sessionUsesAltSpeed( s ) );
412 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP_KBps, tr_sessionGetAltSpeed_KBps( s, TR_UP ) );
413 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN_KBps, tr_sessionGetAltSpeed_KBps( s, TR_DOWN ) );
414 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, tr_sessionGetAltSpeedBegin( s ) );
415 tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, tr_sessionUsesAltSpeedTime( s ) );
416 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END, tr_sessionGetAltSpeedEnd( s ) );
417 tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, tr_sessionGetAltSpeedDay( s ) );
418 tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED_KBps, tr_sessionGetSpeedLimit_KBps( s, TR_UP ) );
419 tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, tr_sessionIsSpeedLimited( s, TR_UP ) );
420 tr_bencDictAddInt ( d, TR_PREFS_KEY_UMASK, s->umask );
421 tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
422 tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, tr_address_to_string( &s->public_ipv4->addr ) );
423 tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, tr_address_to_string( &s->public_ipv6->addr ) );
424 tr_bencDictAddBool( d, TR_PREFS_KEY_START, !tr_sessionGetPaused( s ) );
425 tr_bencDictAddBool( d, TR_PREFS_KEY_TRASH_ORIGINAL, tr_sessionGetDeleteSource( s ) );
428 bool
429 tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName )
431 int err = 0;
432 char * filename;
433 tr_benc fileSettings;
434 tr_benc sessionDefaults;
435 tr_benc tmp;
436 bool success = false;
438 assert( tr_bencIsDict( d ) );
440 /* initializing the defaults: caller may have passed in some app-level defaults.
441 * preserve those and use the session defaults to fill in any missing gaps. */
442 tr_bencInitDict( &sessionDefaults, 0 );
443 tr_sessionGetDefaultSettings( &sessionDefaults );
444 tr_bencMergeDicts( &sessionDefaults, d );
445 tmp = *d; *d = sessionDefaults; sessionDefaults = tmp;
447 /* if caller didn't specify a config dir, use the default */
448 if( !configDir || !*configDir )
449 configDir = tr_getDefaultConfigDir( appName );
451 /* file settings override the defaults */
452 filename = tr_buildPath( configDir, "settings.json", NULL );
453 err = tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename );
454 if( !err ) {
455 tr_bencMergeDicts( d, &fileSettings );
456 tr_bencFree( &fileSettings );
459 /* cleanup */
460 tr_bencFree( &sessionDefaults );
461 tr_free( filename );
462 success = (err==0) || (err==ENOENT);
463 return success;
466 void
467 tr_sessionSaveSettings( tr_session * session,
468 const char * configDir,
469 const tr_benc * clientSettings )
471 tr_benc settings;
472 char * filename = tr_buildPath( configDir, "settings.json", NULL );
474 assert( tr_bencIsDict( clientSettings ) );
476 tr_bencInitDict( &settings, 0 );
478 /* the existing file settings are the fallback values */
480 tr_benc fileSettings;
481 const int err = tr_bencLoadFile( &fileSettings, TR_FMT_JSON, filename );
482 if( !err )
484 tr_bencMergeDicts( &settings, &fileSettings );
485 tr_bencFree( &fileSettings );
489 /* the client's settings override the file settings */
490 tr_bencMergeDicts( &settings, clientSettings );
492 /* the session's true values override the file & client settings */
494 tr_benc sessionSettings;
495 tr_bencInitDict( &sessionSettings, 0 );
496 tr_sessionGetSettings( session, &sessionSettings );
497 tr_bencMergeDicts( &settings, &sessionSettings );
498 tr_bencFree( &sessionSettings );
501 /* save the result */
502 tr_bencToFile( &settings, TR_FMT_JSON, filename );
504 /* cleanup */
505 tr_free( filename );
506 tr_bencFree( &settings );
509 /***
510 ****
511 ***/
514 * Periodically save the .resume files of any torrents whose
515 * status has recently changed. This prevents loss of metadata
516 * in the case of a crash, unclean shutdown, clumsy user, etc.
518 static void
519 onSaveTimer( int foo UNUSED, short bar UNUSED, void * vsession )
521 tr_torrent * tor = NULL;
522 tr_session * session = vsession;
524 if( tr_cacheFlushDone( session->cache ) )
525 tr_err( "Error while flushing completed pieces from cache" );
527 while(( tor = tr_torrentNext( session, tor )))
528 tr_torrentSave( tor );
530 tr_statsSaveDirty( session );
532 tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
535 /***
536 ****
537 ***/
539 static void tr_sessionInitImpl( void * );
541 struct init_data
543 tr_session * session;
544 const char * configDir;
545 bool done;
546 bool messageQueuingEnabled;
547 tr_benc * clientSettings;
550 tr_session *
551 tr_sessionInit( const char * tag,
552 const char * configDir,
553 bool messageQueuingEnabled,
554 tr_benc * clientSettings )
556 int64_t i;
557 tr_session * session;
558 struct init_data data;
560 assert( tr_bencIsDict( clientSettings ) );
562 tr_timeUpdate( time( NULL ) );
564 /* initialize the bare skeleton of the session object */
565 session = tr_new0( tr_session, 1 );
566 session->udp_socket = -1;
567 session->udp6_socket = -1;
568 session->lock = tr_lockNew( );
569 session->cache = tr_cacheNew( 1024*1024*2 );
570 session->tag = tr_strdup( tag );
571 session->magicNumber = SESSION_MAGIC_NUMBER;
572 tr_bandwidthConstruct( &session->bandwidth, session, NULL );
573 tr_peerIdInit( session->peer_id );
574 tr_bencInitList( &session->removedTorrents, 0 );
576 /* nice to start logging at the very beginning */
577 if( tr_bencDictFindInt( clientSettings, TR_PREFS_KEY_MSGLEVEL, &i ) )
578 tr_setMessageLevel( i );
580 /* start the libtransmission thread */
581 tr_netInit( ); /* must go before tr_eventInit */
582 tr_eventInit( session );
583 assert( session->events != NULL );
585 /* run the rest in the libtransmission thread */
586 data.done = false;
587 data.session = session;
588 data.configDir = configDir;
589 data.messageQueuingEnabled = messageQueuingEnabled;
590 data.clientSettings = clientSettings;
591 tr_runInEventThread( session, tr_sessionInitImpl, &data );
592 while( !data.done )
593 tr_wait_msec( 100 );
595 return session;
598 static void turtleCheckClock( tr_session * s, struct tr_turtle_info * t );
600 static void
601 onNowTimer( int foo UNUSED, short bar UNUSED, void * vsession )
603 int usec;
604 const int min = 100;
605 const int max = 999999;
606 struct timeval tv;
607 tr_torrent * tor = NULL;
608 tr_session * session = vsession;
609 const time_t now = time( NULL );
611 assert( tr_isSession( session ) );
612 assert( session->nowTimer != NULL );
615 *** tr_session things to do once per second
618 tr_timeUpdate( now );
620 tr_dhtUpkeep( session );
622 if( session->turtle.isClockEnabled )
623 turtleCheckClock( session, &session->turtle );
625 while(( tor = tr_torrentNext( session, tor ))) {
626 if( tor->isRunning ) {
627 if( tr_torrentIsSeed( tor ) )
628 ++tor->secondsSeeding;
629 else
630 ++tor->secondsDownloading;
635 *** Set the timer
638 /* schedule the next timer for right after the next second begins */
639 gettimeofday( &tv, NULL );
640 usec = 1000000 - tv.tv_usec;
641 if( usec > max ) usec = max;
642 if( usec < min ) usec = min;
643 tr_timerAdd( session->nowTimer, 0, usec );
644 /* fprintf( stderr, "time %zu sec, %zu microsec\n", (size_t)tr_time(), (size_t)tv.tv_usec ); */
647 static void loadBlocklists( tr_session * session );
649 static void
650 tr_sessionInitImpl( void * vdata )
652 tr_benc settings;
653 struct init_data * data = vdata;
654 tr_benc * clientSettings = data->clientSettings;
655 tr_session * session = data->session;
657 assert( tr_amInEventThread( session ) );
658 assert( tr_bencIsDict( clientSettings ) );
660 dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p",
661 &session->bandwidth );
663 tr_bencInitDict( &settings, 0 );
664 tr_sessionGetDefaultSettings( &settings );
665 tr_bencMergeDicts( &settings, clientSettings );
667 assert( session->event_base != NULL );
668 session->nowTimer = evtimer_new( session->event_base, onNowTimer, session );
669 onNowTimer( 0, 0, session );
671 #ifndef WIN32
672 /* Don't exit when writing on a broken socket */
673 signal( SIGPIPE, SIG_IGN );
674 #endif
676 tr_setMessageQueuing( data->messageQueuingEnabled );
678 tr_setConfigDir( session, data->configDir );
680 session->peerMgr = tr_peerMgrNew( session );
682 session->shared = tr_sharedInit( session );
685 *** Blocklist
689 char * filename = tr_buildPath( session->configDir, "blocklists", NULL );
690 tr_mkdirp( filename, 0777 );
691 tr_free( filename );
692 loadBlocklists( session );
695 assert( tr_isSession( session ) );
697 session->saveTimer = evtimer_new( session->event_base, onSaveTimer, session );
698 tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 );
700 tr_announcerInit( session );
702 /* first %s is the application name
703 second %s is the version number */
704 tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
706 tr_statsInit( session );
708 tr_webInit( session );
710 tr_sessionSet( session, &settings );
712 tr_udpInit( session );
714 if( session->isLPDEnabled )
715 tr_lpdInit( session, &session->public_ipv4->addr );
717 /* cleanup */
718 tr_bencFree( &settings );
719 data->done = true;
722 static void turtleBootstrap( tr_session *, struct tr_turtle_info * );
723 static void setPeerPort( tr_session * session, tr_port port );
725 static void
726 sessionSetImpl( void * vdata )
728 int64_t i;
729 double d;
730 bool boolVal;
731 const char * str;
732 struct tr_bindinfo b;
733 struct init_data * data = vdata;
734 tr_session * session = data->session;
735 tr_benc * settings = data->clientSettings;
736 struct tr_turtle_info * turtle = &session->turtle;
738 assert( tr_isSession( session ) );
739 assert( tr_bencIsDict( settings ) );
740 assert( tr_amInEventThread( session ) );
742 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MSGLEVEL, &i ) )
743 tr_setMessageLevel( i );
745 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_UMASK, &i ) ) {
746 session->umask = (mode_t)i;
747 umask( session->umask );
750 /* misc features */
751 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
752 tr_sessionSetCacheLimit_MB( session, i );
753 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
754 tr_sessionSetPeerLimitPerTorrent( session, i );
755 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal ) )
756 tr_sessionSetPexEnabled( session, boolVal );
757 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_DHT_ENABLED, &boolVal ) )
758 tr_sessionSetDHTEnabled( session, boolVal );
759 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_UTP_ENABLED, &boolVal ) )
760 tr_sessionSetUTPEnabled( session, boolVal );
761 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LPD_ENABLED, &boolVal ) )
762 tr_sessionSetLPDEnabled( session, boolVal );
763 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ENCRYPTION, &i ) )
764 tr_sessionSetEncryption( session, i );
765 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &str ) )
766 session->peerSocketTOS = parse_tos( str );
767 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_PEER_CONGESTION_ALGORITHM, &str ) )
768 session->peer_congestion_algorithm = tr_strdup(str);
769 else
770 session->peer_congestion_algorithm = tr_strdup("");
771 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal ) )
772 tr_blocklistSetEnabled( session, boolVal );
773 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_BLOCKLIST_URL, &str ) )
774 tr_blocklistSetURL( session, str );
775 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_START, &boolVal ) )
776 tr_sessionSetPaused( session, !boolVal );
777 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_TRASH_ORIGINAL, &boolVal) )
778 tr_sessionSetDeleteSource( session, boolVal );
780 /* files and directories */
781 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PREFETCH_ENABLED, &boolVal ) )
782 session->isPrefetchEnabled = boolVal;
783 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PREALLOCATION, &i ) )
784 session->preallocationMode = i;
785 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ) )
786 tr_sessionSetDownloadDir( session, str );
787 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_INCOMPLETE_DIR, &str ) )
788 tr_sessionSetIncompleteDir( session, str );
789 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, &boolVal ) )
790 tr_sessionSetIncompleteDirEnabled( session, boolVal );
791 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_RENAME_PARTIAL_FILES, &boolVal ) )
792 tr_sessionSetIncompleteFileNamingEnabled( session, boolVal );
794 /* rpc server */
795 if( session->rpcServer != NULL ) /* close the old one */
796 tr_rpcClose( &session->rpcServer );
797 session->rpcServer = tr_rpcInit( session, settings );
799 /* public addresses */
801 free_incoming_peer_port( session );
803 str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
804 tr_bencDictFindStr( settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
805 if( !tr_address_from_string( &b.addr, str ) || ( b.addr.type != TR_AF_INET ) )
806 b.addr = tr_inaddr_any;
807 b.socket = -1;
808 session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
810 str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
811 tr_bencDictFindStr( settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
812 if( !tr_address_from_string( &b.addr, str ) || ( b.addr.type != TR_AF_INET6 ) )
813 b.addr = tr_in6addr_any;
814 b.socket = -1;
815 session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
817 /* incoming peer port */
818 if( tr_bencDictFindInt ( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ) )
819 session->randomPortLow = i;
820 if( tr_bencDictFindInt ( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ) )
821 session->randomPortHigh = i;
822 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, &boolVal ) )
823 tr_sessionSetPeerPortRandomOnStart( session, boolVal );
824 if( !tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_PORT, &i ) )
825 i = session->private_peer_port;
826 setPeerPort( session, boolVal ? getRandomPort( session ) : i );
827 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PORT_FORWARDING, &boolVal ) )
828 tr_sessionSetPortForwardingEnabled( session, boolVal );
830 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &i ) )
831 session->peerLimit = i;
836 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i ) )
837 session->uploadSlotsPerTorrent = i;
839 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_USPEED_KBps, &i ) )
840 tr_sessionSetSpeedLimit_KBps( session, TR_UP, i );
841 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_USPEED_ENABLED, &boolVal ) )
842 tr_sessionLimitSpeed( session, TR_UP, boolVal );
844 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_DSPEED_KBps, &i ) )
845 tr_sessionSetSpeedLimit_KBps( session, TR_DOWN, i );
846 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_DSPEED_ENABLED, &boolVal ) )
847 tr_sessionLimitSpeed( session, TR_DOWN, boolVal );
849 if( tr_bencDictFindReal( settings, TR_PREFS_KEY_RATIO, &d ) )
850 tr_sessionSetRatioLimit( session, d );
851 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_RATIO_ENABLED, &boolVal ) )
852 tr_sessionSetRatioLimited( session, boolVal );
854 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_IDLE_LIMIT, &i ) )
855 tr_sessionSetIdleLimit( session, i );
856 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, &boolVal ) )
857 tr_sessionSetIdleLimited( session, boolVal );
860 *** Turtle Mode
863 /* update the turtle mode's fields */
864 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_UP_KBps, &i ) )
865 turtle->speedLimit_Bps[TR_UP] = toSpeedBytes( i );
866 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_DOWN_KBps, &i ) )
867 turtle->speedLimit_Bps[TR_DOWN] = toSpeedBytes( i );
868 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, &i ) )
869 turtle->beginMinute = i;
870 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_END, &i ) )
871 turtle->endMinute = i;
872 if( tr_bencDictFindInt( settings, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, &i ) )
873 turtle->days = i;
874 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, &boolVal ) )
875 turtle->isClockEnabled = boolVal;
876 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_ALT_SPEED_ENABLED, &boolVal ) )
877 turtle->isEnabled = boolVal;
878 turtleBootstrap( session, turtle );
881 *** Scripts
884 if( tr_bencDictFindBool( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, &boolVal ) )
885 tr_sessionSetTorrentDoneScriptEnabled( session, boolVal );
886 if( tr_bencDictFindStr( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, &str ) )
887 tr_sessionSetTorrentDoneScript( session, str );
889 data->done = true;
892 void
893 tr_sessionSet( tr_session * session, struct tr_benc * settings )
895 struct init_data data;
896 data.done = false;
897 data.session = session;
898 data.clientSettings = settings;
900 /* run the rest in the libtransmission thread */
901 tr_runInEventThread( session, sessionSetImpl, &data );
902 while( !data.done )
903 tr_wait_msec( 100 );
906 /***
907 ****
908 ***/
910 void
911 tr_sessionSetDownloadDir( tr_session * session, const char * dir )
913 assert( tr_isSession( session ) );
915 if( session->downloadDir != dir )
917 tr_free( session->downloadDir );
918 session->downloadDir = tr_strdup( dir );
922 const char *
923 tr_sessionGetDownloadDir( const tr_session * session )
925 assert( tr_isSession( session ) );
927 return session->downloadDir;
930 int64_t
931 tr_sessionGetDownloadDirFreeSpace( const tr_session * session )
933 assert( tr_isSession( session ) );
935 return tr_getFreeSpace( session->downloadDir );
938 /***
939 ****
940 ***/
942 void
943 tr_sessionSetIncompleteFileNamingEnabled( tr_session * session, bool b )
945 assert( tr_isSession( session ) );
946 assert( tr_isBool( b ) );
948 session->isIncompleteFileNamingEnabled = b;
951 bool
952 tr_sessionIsIncompleteFileNamingEnabled( const tr_session * session )
954 assert( tr_isSession( session ) );
956 return session->isIncompleteFileNamingEnabled;
959 /***
960 ****
961 ***/
964 void
965 tr_sessionSetIncompleteDir( tr_session * session, const char * dir )
967 assert( tr_isSession( session ) );
969 if( session->incompleteDir != dir )
971 tr_free( session->incompleteDir );
973 session->incompleteDir = tr_strdup( dir );
977 const char*
978 tr_sessionGetIncompleteDir( const tr_session * session )
980 assert( tr_isSession( session ) );
982 return session->incompleteDir;
985 void
986 tr_sessionSetIncompleteDirEnabled( tr_session * session, bool b )
988 assert( tr_isSession( session ) );
989 assert( tr_isBool( b ) );
991 session->isIncompleteDirEnabled = b;
994 bool
995 tr_sessionIsIncompleteDirEnabled( const tr_session * session )
997 assert( tr_isSession( session ) );
999 return session->isIncompleteDirEnabled;
1002 /***
1003 ****
1004 ***/
1006 void
1007 tr_sessionLock( tr_session * session )
1009 assert( tr_isSession( session ) );
1011 tr_lockLock( session->lock );
1014 void
1015 tr_sessionUnlock( tr_session * session )
1017 assert( tr_isSession( session ) );
1019 tr_lockUnlock( session->lock );
1022 bool
1023 tr_sessionIsLocked( const tr_session * session )
1025 return tr_isSession( session ) && tr_lockHave( session->lock );
1028 /***********************************************************************
1029 * tr_setBindPort
1030 ***********************************************************************
1032 **********************************************************************/
1034 static void
1035 peerPortChanged( void * session )
1037 tr_torrent * tor = NULL;
1039 assert( tr_isSession( session ) );
1041 close_incoming_peer_port( session );
1042 open_incoming_peer_port( session );
1043 tr_sharedPortChanged( session );
1045 while(( tor = tr_torrentNext( session, tor )))
1046 tr_torrentChangeMyPort( tor );
1049 static void
1050 setPeerPort( tr_session * session, tr_port port )
1052 session->private_peer_port = port;
1053 session->public_peer_port = port;
1055 tr_runInEventThread( session, peerPortChanged, session );
1058 void
1059 tr_sessionSetPeerPort( tr_session * session, tr_port port )
1061 if( tr_isSession( session ) && ( session->private_peer_port != port ) )
1063 setPeerPort( session, port );
1067 tr_port
1068 tr_sessionGetPeerPort( const tr_session * session )
1070 return tr_isSession( session ) ? session->private_peer_port : 0;
1073 tr_port
1074 tr_sessionSetPeerPortRandom( tr_session * session )
1076 assert( tr_isSession( session ) );
1078 tr_sessionSetPeerPort( session, getRandomPort( session ) );
1079 return session->private_peer_port;
1082 void
1083 tr_sessionSetPeerPortRandomOnStart( tr_session * session,
1084 bool random )
1086 assert( tr_isSession( session ) );
1088 session->isPortRandom = random;
1091 bool
1092 tr_sessionGetPeerPortRandomOnStart( tr_session * session )
1094 assert( tr_isSession( session ) );
1096 return session->isPortRandom;
1099 tr_port_forwarding
1100 tr_sessionGetPortForwarding( const tr_session * session )
1102 assert( tr_isSession( session ) );
1104 return tr_sharedTraversalStatus( session->shared );
1107 /***
1108 ****
1109 ***/
1111 void
1112 tr_sessionSetRatioLimited( tr_session * session, bool isLimited )
1114 assert( tr_isSession( session ) );
1116 session->isRatioLimited = isLimited;
1119 void
1120 tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
1122 assert( tr_isSession( session ) );
1124 session->desiredRatio = desiredRatio;
1127 bool
1128 tr_sessionIsRatioLimited( const tr_session * session )
1130 assert( tr_isSession( session ) );
1132 return session->isRatioLimited;
1135 double
1136 tr_sessionGetRatioLimit( const tr_session * session )
1138 assert( tr_isSession( session ) );
1140 return session->desiredRatio;
1143 /***
1144 ****
1145 ***/
1147 void
1148 tr_sessionSetIdleLimited( tr_session * session, bool isLimited )
1150 assert( tr_isSession( session ) );
1152 session->isIdleLimited = isLimited;
1155 void
1156 tr_sessionSetIdleLimit( tr_session * session, uint16_t idleMinutes )
1158 assert( tr_isSession( session ) );
1160 session->idleLimitMinutes = idleMinutes;
1163 bool
1164 tr_sessionIsIdleLimited( const tr_session * session )
1166 assert( tr_isSession( session ) );
1168 return session->isIdleLimited;
1171 uint16_t
1172 tr_sessionGetIdleLimit( const tr_session * session )
1174 assert( tr_isSession( session ) );
1176 return session->idleLimitMinutes;
1179 /***
1180 ****
1181 **** SPEED LIMITS
1182 ****
1183 ***/
1185 bool
1186 tr_sessionGetActiveSpeedLimit_Bps( const tr_session * session, tr_direction dir, int * setme_Bps )
1188 int isLimited = true;
1190 if( !tr_isSession( session ) )
1191 return false;
1193 if( tr_sessionUsesAltSpeed( session ) )
1194 *setme_Bps = tr_sessionGetAltSpeed_Bps( session, dir );
1195 else if( tr_sessionIsSpeedLimited( session, dir ) )
1196 *setme_Bps = tr_sessionGetSpeedLimit_Bps( session, dir );
1197 else
1198 isLimited = false;
1200 return isLimited;
1202 bool
1203 tr_sessionGetActiveSpeedLimit_KBps( const tr_session * session,
1204 tr_direction dir,
1205 double * setme_KBps )
1207 int Bps = 0;
1208 const bool is_active = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &Bps );
1209 *setme_KBps = toSpeedKBps( Bps );
1210 return is_active;
1213 static void
1214 updateBandwidth( tr_session * session, tr_direction dir )
1216 int limit_Bps = 0;
1217 const bool isLimited = tr_sessionGetActiveSpeedLimit_Bps( session, dir, &limit_Bps );
1218 const bool zeroCase = isLimited && !limit_Bps;
1220 tr_bandwidthSetLimited( &session->bandwidth, dir, isLimited && !zeroCase );
1222 tr_bandwidthSetDesiredSpeed_Bps( &session->bandwidth, dir, limit_Bps );
1225 enum
1227 MINUTES_PER_HOUR = 60,
1228 MINUTES_PER_DAY = MINUTES_PER_HOUR * 24,
1229 MINUTES_PER_WEEK = MINUTES_PER_DAY * 7
1232 static void
1233 turtleUpdateTable( struct tr_turtle_info * t )
1235 int day;
1236 tr_bitfield * b = &t->minutes;
1238 tr_bitfieldSetHasNone( b );
1240 for( day=0; day<7; ++day )
1242 if( t->days & (1<<day) )
1244 int i;
1245 const time_t begin = t->beginMinute;
1246 time_t end = t->endMinute;
1248 if( end <= begin )
1249 end += MINUTES_PER_DAY;
1251 for( i=begin; i<end; ++i )
1252 tr_bitfieldAdd( b, (i+day*MINUTES_PER_DAY) % MINUTES_PER_WEEK );
1257 static void
1258 altSpeedToggled( void * vsession )
1260 tr_session * session = vsession;
1261 struct tr_turtle_info * t = &session->turtle;
1263 assert( tr_isSession( session ) );
1265 updateBandwidth( session, TR_UP );
1266 updateBandwidth( session, TR_DOWN );
1268 if( t->callback != NULL )
1269 (*t->callback)( session, t->isEnabled, t->changedByUser, t->callbackUserData );
1272 static void
1273 useAltSpeed( tr_session * s, struct tr_turtle_info * t,
1274 bool enabled, bool byUser )
1276 assert( tr_isSession( s ) );
1277 assert( t != NULL );
1278 assert( tr_isBool( enabled ) );
1279 assert( tr_isBool( byUser ) );
1281 if( t->isEnabled != enabled )
1283 t->isEnabled = enabled;
1284 t->changedByUser = byUser;
1285 tr_runInEventThread( s, altSpeedToggled, s );
1290 * @param enabled whether turtle should be on/off according to the scheduler
1291 * @param changed whether that's different from the previous minute
1293 static void
1294 testTurtleTime( const struct tr_turtle_info * t,
1295 bool * enabled,
1296 bool * changed )
1298 bool e;
1299 struct tm tm;
1300 size_t minute_of_the_week;
1301 const time_t now = tr_time( );
1303 tr_localtime_r( &now, &tm );
1305 minute_of_the_week = tm.tm_wday * MINUTES_PER_DAY
1306 + tm.tm_hour * MINUTES_PER_HOUR
1307 + tm.tm_min;
1308 if( minute_of_the_week >= MINUTES_PER_WEEK ) /* leap minutes? */
1309 minute_of_the_week = MINUTES_PER_WEEK - 1;
1311 e = tr_bitfieldHas( &t->minutes, minute_of_the_week );
1312 if( enabled != NULL )
1313 *enabled = e;
1315 if( changed != NULL )
1317 const size_t prev = minute_of_the_week > 0 ? minute_of_the_week - 1
1318 : MINUTES_PER_WEEK - 1;
1319 *changed = e != tr_bitfieldHas( &t->minutes, prev );
1323 static void
1324 turtleCheckClock( tr_session * s, struct tr_turtle_info * t )
1326 bool enabled;
1327 bool changed;
1329 assert( t->isClockEnabled );
1331 testTurtleTime( t, &enabled, &changed );
1333 if( changed )
1335 tr_inf( "Time to turn %s turtle mode!", (enabled?"on":"off") );
1336 useAltSpeed( s, t, enabled, false );
1340 /* Called after the turtle's fields are loaded from an outside source.
1341 * It initializes the implementation fields
1342 * and turns on turtle mode if the clock settings say to. */
1343 static void
1344 turtleBootstrap( tr_session * session, struct tr_turtle_info * turtle )
1346 turtle->changedByUser = false;
1348 tr_bitfieldConstruct( &turtle->minutes, MINUTES_PER_WEEK );
1350 turtleUpdateTable( turtle );
1352 if( turtle->isClockEnabled )
1353 testTurtleTime( turtle, &turtle->isEnabled, NULL );
1355 altSpeedToggled( session );
1358 /***
1359 **** Primary session speed limits
1360 ***/
1362 void
1363 tr_sessionSetSpeedLimit_Bps( tr_session * s, tr_direction d, int Bps )
1365 assert( tr_isSession( s ) );
1366 assert( tr_isDirection( d ) );
1367 assert( Bps >= 0 );
1369 s->speedLimit_Bps[d] = Bps;
1371 updateBandwidth( s, d );
1373 void
1374 tr_sessionSetSpeedLimit_KBps( tr_session * s, tr_direction d, int KBps )
1376 tr_sessionSetSpeedLimit_Bps( s, d, toSpeedBytes( KBps ) );
1380 tr_sessionGetSpeedLimit_Bps( const tr_session * s, tr_direction d )
1382 assert( tr_isSession( s ) );
1383 assert( tr_isDirection( d ) );
1385 return s->speedLimit_Bps[d];
1388 tr_sessionGetSpeedLimit_KBps( const tr_session * s, tr_direction d )
1390 return toSpeedKBps( tr_sessionGetSpeedLimit_Bps( s, d ) );
1393 void
1394 tr_sessionLimitSpeed( tr_session * s, tr_direction d, bool b )
1396 assert( tr_isSession( s ) );
1397 assert( tr_isDirection( d ) );
1398 assert( tr_isBool( b ) );
1400 s->speedLimitEnabled[d] = b;
1402 updateBandwidth( s, d );
1405 bool
1406 tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1408 assert( tr_isSession( s ) );
1409 assert( tr_isDirection( d ) );
1411 return s->speedLimitEnabled[d];
1414 /***
1415 **** Alternative speed limits that are used during scheduled times
1416 ***/
1418 void
1419 tr_sessionSetAltSpeed_Bps( tr_session * s, tr_direction d, int Bps )
1421 assert( tr_isSession( s ) );
1422 assert( tr_isDirection( d ) );
1423 assert( Bps >= 0 );
1425 s->turtle.speedLimit_Bps[d] = Bps;
1427 updateBandwidth( s, d );
1430 void
1431 tr_sessionSetAltSpeed_KBps( tr_session * s, tr_direction d, int KBps )
1433 tr_sessionSetAltSpeed_Bps( s, d, toSpeedBytes( KBps ) );
1437 tr_sessionGetAltSpeed_Bps( const tr_session * s, tr_direction d )
1439 assert( tr_isSession( s ) );
1440 assert( tr_isDirection( d ) );
1442 return s->turtle.speedLimit_Bps[d];
1445 tr_sessionGetAltSpeed_KBps( const tr_session * s, tr_direction d )
1447 return toSpeedKBps( tr_sessionGetAltSpeed_Bps( s, d ) );
1450 static void
1451 userPokedTheClock( tr_session * s, struct tr_turtle_info * t )
1453 tr_dbg( "Refreshing the turtle mode clock due to user changes" );
1455 turtleUpdateTable( t );
1457 if( t->isClockEnabled )
1459 bool enabled, changed;
1460 testTurtleTime( t, &enabled, &changed );
1461 useAltSpeed( s, t, enabled, true );
1465 void
1466 tr_sessionUseAltSpeedTime( tr_session * s, bool b )
1468 struct tr_turtle_info * t = &s->turtle;
1470 assert( tr_isSession( s ) );
1471 assert( tr_isBool ( b ) );
1473 if( t->isClockEnabled != b ) {
1474 t->isClockEnabled = b;
1475 userPokedTheClock( s, t );
1479 bool
1480 tr_sessionUsesAltSpeedTime( const tr_session * s )
1482 assert( tr_isSession( s ) );
1484 return s->turtle.isClockEnabled;
1487 void
1488 tr_sessionSetAltSpeedBegin( tr_session * s, int minute )
1490 assert( tr_isSession( s ) );
1491 assert( 0<=minute && minute<(60*24) );
1493 if( s->turtle.beginMinute != minute ) {
1494 s->turtle.beginMinute = minute;
1495 userPokedTheClock( s, &s->turtle );
1500 tr_sessionGetAltSpeedBegin( const tr_session * s )
1502 assert( tr_isSession( s ) );
1504 return s->turtle.beginMinute;
1507 void
1508 tr_sessionSetAltSpeedEnd( tr_session * s, int minute )
1510 assert( tr_isSession( s ) );
1511 assert( 0<=minute && minute<(60*24) );
1513 if( s->turtle.endMinute != minute ) {
1514 s->turtle.endMinute = minute;
1515 userPokedTheClock( s, &s->turtle );
1520 tr_sessionGetAltSpeedEnd( const tr_session * s )
1522 assert( tr_isSession( s ) );
1524 return s->turtle.endMinute;
1527 void
1528 tr_sessionSetAltSpeedDay( tr_session * s, tr_sched_day days )
1530 assert( tr_isSession( s ) );
1532 if( s->turtle.days != days ) {
1533 s->turtle.days = days;
1534 userPokedTheClock( s, &s->turtle );
1538 tr_sched_day
1539 tr_sessionGetAltSpeedDay( const tr_session * s )
1541 assert( tr_isSession( s ) );
1543 return s->turtle.days;
1546 void
1547 tr_sessionUseAltSpeed( tr_session * session, bool enabled )
1549 useAltSpeed( session, &session->turtle, enabled, true );
1552 bool
1553 tr_sessionUsesAltSpeed( const tr_session * s )
1555 assert( tr_isSession( s ) );
1557 return s->turtle.isEnabled;
1560 void
1561 tr_sessionSetAltSpeedFunc( tr_session * session,
1562 tr_altSpeedFunc func,
1563 void * userData )
1565 assert( tr_isSession( session ) );
1567 session->turtle.callback = func;
1568 session->turtle.callbackUserData = userData;
1571 void
1572 tr_sessionClearAltSpeedFunc( tr_session * session )
1574 tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1577 /***
1578 ****
1579 ***/
1581 void
1582 tr_sessionSetPeerLimit( tr_session * session, uint16_t n )
1584 assert( tr_isSession( session ) );
1586 session->peerLimit = n;
1589 uint16_t
1590 tr_sessionGetPeerLimit( const tr_session * session )
1592 assert( tr_isSession( session ) );
1594 return session->peerLimit;
1597 void
1598 tr_sessionSetPeerLimitPerTorrent( tr_session * session, uint16_t n )
1600 assert( tr_isSession( session ) );
1602 session->peerLimitPerTorrent = n;
1605 uint16_t
1606 tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1608 assert( tr_isSession( session ) );
1610 return session->peerLimitPerTorrent;
1613 /***
1614 ****
1615 ***/
1617 void
1618 tr_sessionSetPaused( tr_session * session, bool isPaused )
1620 assert( tr_isSession( session ) );
1622 session->pauseAddedTorrent = isPaused;
1625 bool
1626 tr_sessionGetPaused( const tr_session * session )
1628 assert( tr_isSession( session ) );
1630 return session->pauseAddedTorrent;
1633 void
1634 tr_sessionSetDeleteSource( tr_session * session, bool deleteSource )
1636 assert( tr_isSession( session ) );
1638 session->deleteSourceTorrent = deleteSource;
1641 bool
1642 tr_sessionGetDeleteSource( const tr_session * session )
1644 assert( tr_isSession( session ) );
1646 return session->deleteSourceTorrent;
1649 /***
1650 ****
1651 ***/
1654 tr_sessionGetPieceSpeed_Bps( const tr_session * session, tr_direction dir )
1656 return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed_Bps( &session->bandwidth, 0, dir ) : 0;
1660 tr_sessionGetRawSpeed_Bps( const tr_session * session, tr_direction dir )
1662 return tr_isSession( session ) ? tr_bandwidthGetRawSpeed_Bps( &session->bandwidth, 0, dir ) : 0;
1664 double
1665 tr_sessionGetRawSpeed_KBps( const tr_session * session, tr_direction dir )
1667 return toSpeedKBps( tr_sessionGetRawSpeed_Bps( session, dir ) );
1672 tr_sessionCountTorrents( const tr_session * session )
1674 return tr_isSession( session ) ? session->torrentCount : 0;
1677 static int
1678 compareTorrentByCur( const void * va, const void * vb )
1680 const tr_torrent * a = *(const tr_torrent**)va;
1681 const tr_torrent * b = *(const tr_torrent**)vb;
1682 const uint64_t aCur = a->downloadedCur + a->uploadedCur;
1683 const uint64_t bCur = b->downloadedCur + b->uploadedCur;
1685 if( aCur != bCur )
1686 return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1688 return 0;
1691 static void closeBlocklists( tr_session * );
1693 static void
1694 sessionCloseImpl( void * vsession )
1696 tr_session * session = vsession;
1697 tr_torrent * tor;
1698 int i, n;
1699 tr_torrent ** torrents;
1701 assert( tr_isSession( session ) );
1703 free_incoming_peer_port( session );
1705 if( session->isLPDEnabled )
1706 tr_lpdUninit( session );
1708 tr_utpClose( session );
1709 tr_dhtUninit( session );
1711 event_free( session->saveTimer );
1712 session->saveTimer = NULL;
1714 event_free( session->nowTimer );
1715 session->nowTimer = NULL;
1717 tr_verifyClose( session );
1718 tr_sharedClose( session );
1719 tr_rpcClose( &session->rpcServer );
1721 /* Close the torrents. Get the most active ones first so that
1722 * if we can't get them all closed in a reasonable amount of time,
1723 * at least we get the most important ones first. */
1724 tor = NULL;
1725 n = session->torrentCount;
1726 torrents = tr_new( tr_torrent *, session->torrentCount );
1727 for( i = 0; i < n; ++i )
1728 torrents[i] = tor = tr_torrentNext( session, tor );
1729 qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1730 for( i = 0; i < n; ++i )
1731 tr_torrentFree( torrents[i] );
1732 tr_free( torrents );
1734 /* Close the announcer *after* closing the torrents
1735 so that all the &event=stopped messages will be
1736 queued to be sent by tr_announcerClose() */
1737 tr_announcerClose( session );
1739 /* and this goes *after* announcer close so that
1740 it won't be idle until the announce events are sent... */
1741 tr_webClose( session, TR_WEB_CLOSE_WHEN_IDLE );
1743 tr_cacheFree( session->cache );
1744 session->cache = NULL;
1746 /* gotta keep udp running long enough to send out all
1747 the &event=stopped UDP tracker messages */
1748 while( !tr_tracker_udp_is_idle( session ) ) {
1749 tr_tracker_udp_upkeep( session );
1750 tr_wait_msec( 100 );
1753 /* we had to wait until UDP trackers were closed before closing these: */
1754 evdns_base_free( session->evdns_base, 0 );
1755 session->evdns_base = NULL;
1756 tr_tracker_udp_close( session );
1757 tr_udpUninit( session );
1759 tr_statsClose( session );
1760 tr_peerMgrFree( session->peerMgr );
1762 closeBlocklists( session );
1764 tr_fdClose( session );
1766 session->isClosed = true;
1769 static int
1770 deadlineReached( const time_t deadline )
1772 return time( NULL ) >= deadline;
1775 #define SHUTDOWN_MAX_SECONDS 20
1777 void
1778 tr_sessionClose( tr_session * session )
1780 const time_t deadline = time( NULL ) + SHUTDOWN_MAX_SECONDS;
1782 assert( tr_isSession( session ) );
1784 dbgmsg( "shutting down transmission session %p... now is %zu, deadline is %zu", session, (size_t)time(NULL), (size_t)deadline );
1786 /* close the session */
1787 tr_runInEventThread( session, sessionCloseImpl, session );
1788 while( !session->isClosed && !deadlineReached( deadline ) )
1790 dbgmsg( "waiting for the libtransmission thread to finish" );
1791 tr_wait_msec( 100 );
1794 /* "shared" and "tracker" have live sockets,
1795 * so we need to keep the transmission thread alive
1796 * for a bit while they tell the router & tracker
1797 * that we're closing now */
1798 while( ( session->shared || session->web || session->announcer || session->announcer_udp )
1799 && !deadlineReached( deadline ) )
1801 dbgmsg( "waiting on port unmap (%p) or announcer (%p)... now %zu deadline %zu",
1802 session->shared, session->announcer, (size_t)time(NULL), (size_t)deadline );
1803 tr_wait_msec( 100 );
1806 tr_webClose( session, TR_WEB_CLOSE_NOW );
1808 /* close the libtransmission thread */
1809 tr_eventClose( session );
1810 while( session->events != NULL )
1812 static bool forced = false;
1813 dbgmsg( "waiting for libtransmission thread to finish... now %zu deadline %zu", (size_t)time(NULL), (size_t)deadline );
1814 tr_wait_msec( 500 );
1815 if( deadlineReached( deadline ) && !forced )
1817 dbgmsg( "calling event_loopbreak()" );
1818 forced = true;
1819 event_base_loopbreak( session->event_base );
1821 if( deadlineReached( deadline+3 ) )
1823 dbgmsg( "deadline+3 reached... calling break...\n" );
1824 break;
1828 /* free the session memory */
1829 tr_bencFree( &session->removedTorrents );
1830 tr_bandwidthDestruct( &session->bandwidth );
1831 tr_bitfieldDestruct( &session->turtle.minutes );
1832 tr_lockFree( session->lock );
1833 if( session->metainfoLookup ) {
1834 tr_bencFree( session->metainfoLookup );
1835 tr_free( session->metainfoLookup );
1837 tr_free( session->torrentDoneScript );
1838 tr_free( session->tag );
1839 tr_free( session->configDir );
1840 tr_free( session->resumeDir );
1841 tr_free( session->torrentDir );
1842 tr_free( session->downloadDir );
1843 tr_free( session->incompleteDir );
1844 tr_free( session->blocklist_url );
1845 tr_free( session->peer_congestion_algorithm );
1846 tr_free( session );
1849 struct sessionLoadTorrentsData
1851 tr_session * session;
1852 tr_ctor * ctor;
1853 int * setmeCount;
1854 tr_torrent ** torrents;
1855 bool done;
1858 static void
1859 sessionLoadTorrents( void * vdata )
1861 int i;
1862 int n = 0;
1863 struct stat sb;
1864 DIR * odir = NULL;
1865 tr_list * l = NULL;
1866 tr_list * list = NULL;
1867 struct sessionLoadTorrentsData * data = vdata;
1868 const char * dirname = tr_getTorrentDir( data->session );
1870 assert( tr_isSession( data->session ) );
1872 tr_ctorSetSave( data->ctor, false ); /* since we already have them */
1874 if( !stat( dirname, &sb )
1875 && S_ISDIR( sb.st_mode )
1876 && ( ( odir = opendir ( dirname ) ) ) )
1878 struct dirent *d;
1879 for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1881 if( tr_str_has_suffix( d->d_name, ".torrent" ) )
1883 tr_torrent * tor;
1884 char * path = tr_buildPath( dirname, d->d_name, NULL );
1885 tr_ctorSetMetainfoFromFile( data->ctor, path );
1886 if(( tor = tr_torrentNew( data->ctor, NULL )))
1888 tr_list_prepend( &list, tor );
1889 ++n;
1891 tr_free( path );
1894 closedir( odir );
1897 data->torrents = tr_new( tr_torrent *, n );
1898 for( i = 0, l = list; l != NULL; l = l->next )
1899 data->torrents[i++] = (tr_torrent*) l->data;
1900 assert( i == n );
1902 tr_list_free( &list, NULL );
1904 if( n )
1905 tr_inf( _( "Loaded %d torrents" ), n );
1907 if( data->setmeCount )
1908 *data->setmeCount = n;
1910 data->done = true;
1913 tr_torrent **
1914 tr_sessionLoadTorrents( tr_session * session,
1915 tr_ctor * ctor,
1916 int * setmeCount )
1918 struct sessionLoadTorrentsData data;
1920 data.session = session;
1921 data.ctor = ctor;
1922 data.setmeCount = setmeCount;
1923 data.torrents = NULL;
1924 data.done = false;
1926 tr_runInEventThread( session, sessionLoadTorrents, &data );
1927 while( !data.done )
1928 tr_wait_msec( 100 );
1930 return data.torrents;
1933 /***
1934 ****
1935 ***/
1937 void
1938 tr_sessionSetPexEnabled( tr_session * session, bool enabled )
1940 assert( tr_isSession( session ) );
1942 session->isPexEnabled = enabled != 0;
1945 bool
1946 tr_sessionIsPexEnabled( const tr_session * session )
1948 assert( tr_isSession( session ) );
1950 return session->isPexEnabled;
1953 bool
1954 tr_sessionAllowsDHT( const tr_session * session )
1956 return tr_sessionIsDHTEnabled( session );
1959 bool
1960 tr_sessionIsDHTEnabled( const tr_session * session )
1962 assert( tr_isSession( session ) );
1964 return session->isDHTEnabled;
1967 static void
1968 toggleDHTImpl( void * data )
1970 tr_session * session = data;
1971 assert( tr_isSession( session ) );
1973 tr_udpUninit( session );
1974 session->isDHTEnabled = !session->isDHTEnabled;
1975 tr_udpInit( session );
1978 void
1979 tr_sessionSetDHTEnabled( tr_session * session, bool enabled )
1981 assert( tr_isSession( session ) );
1982 assert( tr_isBool( enabled ) );
1984 if( ( enabled != 0 ) != ( session->isDHTEnabled != 0 ) )
1985 tr_runInEventThread( session, toggleDHTImpl, session );
1988 /***
1989 ****
1990 ***/
1992 bool
1993 tr_sessionIsUTPEnabled( const tr_session * session )
1995 assert( tr_isSession( session ) );
1997 #ifdef WITH_UTP
1998 return session->isUTPEnabled;
1999 #else
2000 return false;
2001 #endif
2004 static void
2005 toggle_utp( void * data )
2007 tr_session * session = data;
2008 assert( tr_isSession( session ) );
2010 session->isUTPEnabled = !session->isUTPEnabled;
2012 tr_udpSetSocketBuffers( session );
2014 /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
2015 explanation. */
2018 void
2019 tr_sessionSetUTPEnabled( tr_session * session, bool enabled )
2021 assert( tr_isSession( session ) );
2022 assert( tr_isBool( enabled ) );
2024 if( ( enabled != 0 ) != ( session->isUTPEnabled != 0 ) )
2025 tr_runInEventThread( session, toggle_utp, session );
2028 /***
2029 ****
2030 ***/
2032 static void
2033 toggleLPDImpl( void * data )
2035 tr_session * session = data;
2036 assert( tr_isSession( session ) );
2038 if( session->isLPDEnabled )
2039 tr_lpdUninit( session );
2041 session->isLPDEnabled = !session->isLPDEnabled;
2043 if( session->isLPDEnabled )
2044 tr_lpdInit( session, &session->public_ipv4->addr );
2047 void
2048 tr_sessionSetLPDEnabled( tr_session * session, bool enabled )
2050 assert( tr_isSession( session ) );
2051 assert( tr_isBool( enabled ) );
2053 if( ( enabled != 0 ) != ( session->isLPDEnabled != 0 ) )
2054 tr_runInEventThread( session, toggleLPDImpl, session );
2057 bool
2058 tr_sessionIsLPDEnabled( const tr_session * session )
2060 assert( tr_isSession( session ) );
2062 return session->isLPDEnabled;
2065 bool
2066 tr_sessionAllowsLPD( const tr_session * session )
2068 return tr_sessionIsLPDEnabled( session );
2071 /***
2072 ****
2073 ***/
2075 void
2076 tr_sessionSetCacheLimit_MB( tr_session * session, int max_bytes )
2078 assert( tr_isSession( session ) );
2080 tr_cacheSetLimit( session->cache, toMemBytes( max_bytes ) );
2084 tr_sessionGetCacheLimit_MB( const tr_session * session )
2086 assert( tr_isSession( session ) );
2088 return toMemMB( tr_cacheGetLimit( session->cache ) );
2091 /***
2092 ****
2093 ***/
2095 struct port_forwarding_data
2097 bool enabled;
2098 struct tr_shared * shared;
2101 static void
2102 setPortForwardingEnabled( void * vdata )
2104 struct port_forwarding_data * data = vdata;
2105 tr_sharedTraversalEnable( data->shared, data->enabled );
2106 tr_free( data );
2109 void
2110 tr_sessionSetPortForwardingEnabled( tr_session * session, bool enabled )
2112 struct port_forwarding_data * d;
2113 d = tr_new0( struct port_forwarding_data, 1 );
2114 d->shared = session->shared;
2115 d->enabled = enabled;
2116 tr_runInEventThread( session, setPortForwardingEnabled, d );
2119 bool
2120 tr_sessionIsPortForwardingEnabled( const tr_session * session )
2122 assert( tr_isSession( session ) );
2124 return tr_sharedTraversalIsEnabled( session->shared );
2127 /***
2128 ****
2129 ***/
2131 static int
2132 tr_stringEndsWith( const char * str, const char * end )
2134 const size_t slen = strlen( str );
2135 const size_t elen = strlen( end );
2137 return slen >= elen && !memcmp( &str[slen - elen], end, elen );
2140 static void
2141 loadBlocklists( tr_session * session )
2143 int binCount = 0;
2144 int newCount = 0;
2145 struct stat sb;
2146 char * dirname;
2147 DIR * odir = NULL;
2148 tr_list * list = NULL;
2149 const bool isEnabled = session->isBlocklistEnabled;
2151 /* walk through the directory and find blocklists */
2152 dirname = tr_buildPath( session->configDir, "blocklists", NULL );
2153 if( !stat( dirname,
2154 &sb ) && S_ISDIR( sb.st_mode )
2155 && ( ( odir = opendir( dirname ) ) ) )
2157 struct dirent *d;
2158 for( d = readdir( odir ); d; d = readdir( odir ) )
2160 char * filename;
2162 if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
2164 continue;
2166 filename = tr_buildPath( dirname, d->d_name, NULL );
2168 if( tr_stringEndsWith( filename, ".bin" ) )
2170 /* if we don't already have this blocklist, add it */
2171 if( !tr_list_find( list, filename,
2172 (TrListCompareFunc)strcmp ) )
2174 tr_list_append( &list,
2175 _tr_blocklistNew( filename, isEnabled ) );
2176 ++binCount;
2179 else
2181 /* strip out the file suffix, if there is one, and add ".bin"
2182 instead */
2183 tr_blocklist * b;
2184 const char * dot = strrchr( d->d_name, '.' );
2185 const int len = dot ? dot - d->d_name
2186 : (int)strlen( d->d_name );
2187 char * tmp = tr_strdup_printf(
2188 "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
2189 dirname, len, len, d->d_name );
2190 b = _tr_blocklistNew( tmp, isEnabled );
2191 _tr_blocklistSetContent( b, filename );
2192 tr_list_append( &list, b );
2193 ++newCount;
2194 tr_free( tmp );
2197 tr_free( filename );
2200 closedir( odir );
2203 session->blocklists = list;
2205 if( binCount )
2206 tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
2207 if( newCount )
2208 tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
2210 tr_free( dirname );
2213 static void
2214 closeBlocklists( tr_session * session )
2216 tr_list_free( &session->blocklists,
2217 (TrListForeachFunc)_tr_blocklistFree );
2220 void
2221 tr_sessionReloadBlocklists( tr_session * session )
2223 closeBlocklists( session );
2224 loadBlocklists( session );
2226 tr_peerMgrOnBlocklistChanged( session->peerMgr );
2230 tr_blocklistGetRuleCount( const tr_session * session )
2232 int n = 0;
2233 tr_list * l;
2235 assert( tr_isSession( session ) );
2237 for( l = session->blocklists; l; l = l->next )
2238 n += _tr_blocklistGetRuleCount( l->data );
2239 return n;
2242 bool
2243 tr_blocklistIsEnabled( const tr_session * session )
2245 assert( tr_isSession( session ) );
2247 return session->isBlocklistEnabled;
2250 void
2251 tr_blocklistSetEnabled( tr_session * session, bool isEnabled )
2253 tr_list * l;
2255 assert( tr_isSession( session ) );
2257 session->isBlocklistEnabled = isEnabled != 0;
2259 for( l=session->blocklists; l!=NULL; l=l->next )
2260 _tr_blocklistSetEnabled( l->data, isEnabled );
2263 bool
2264 tr_blocklistExists( const tr_session * session )
2266 assert( tr_isSession( session ) );
2268 return session->blocklists != NULL;
2272 tr_blocklistSetContent( tr_session * session, const char * contentFilename )
2274 tr_list * l;
2275 int ruleCount;
2276 tr_blocklist * b;
2277 const char * defaultName = DEFAULT_BLOCKLIST_FILENAME;
2278 tr_sessionLock( session );
2280 for( b = NULL, l = session->blocklists; !b && l; l = l->next )
2281 if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
2282 defaultName ) )
2283 b = l->data;
2285 if( !b )
2287 char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
2288 b = _tr_blocklistNew( path, session->isBlocklistEnabled );
2289 tr_list_append( &session->blocklists, b );
2290 tr_free( path );
2293 ruleCount = _tr_blocklistSetContent( b, contentFilename );
2294 tr_sessionUnlock( session );
2295 return ruleCount;
2298 bool
2299 tr_sessionIsAddressBlocked( const tr_session * session,
2300 const tr_address * addr )
2302 tr_list * l;
2304 assert( tr_isSession( session ) );
2306 for( l = session->blocklists; l; l = l->next )
2307 if( _tr_blocklistHasAddress( l->data, addr ) )
2308 return true;
2309 return false;
2312 void
2313 tr_blocklistSetURL( tr_session * session, const char * url )
2315 if( session->blocklist_url != url )
2317 tr_free( session->blocklist_url );
2318 session->blocklist_url = tr_strdup( url );
2322 const char *
2323 tr_blocklistGetURL ( const tr_session * session )
2325 return session->blocklist_url;
2329 /***
2330 ****
2331 ***/
2333 static void
2334 metainfoLookupInit( tr_session * session )
2336 struct stat sb;
2337 const char * dirname = tr_getTorrentDir( session );
2338 DIR * odir = NULL;
2339 tr_ctor * ctor = NULL;
2340 tr_benc * lookup;
2341 int n = 0;
2343 assert( tr_isSession( session ) );
2345 /* walk through the directory and find the mappings */
2346 lookup = tr_new0( tr_benc, 1 );
2347 tr_bencInitDict( lookup, 0 );
2348 ctor = tr_ctorNew( session );
2349 tr_ctorSetSave( ctor, false ); /* since we already have them */
2350 if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
2352 struct dirent *d;
2353 while(( d = readdir( odir )))
2355 if( tr_str_has_suffix( d->d_name, ".torrent" ) )
2357 tr_info inf;
2358 char * path = tr_buildPath( dirname, d->d_name, NULL );
2359 tr_ctorSetMetainfoFromFile( ctor, path );
2360 if( !tr_torrentParse( ctor, &inf ) )
2362 ++n;
2363 tr_bencDictAddStr( lookup, inf.hashString, path );
2365 tr_free( path );
2368 closedir( odir );
2370 tr_ctorFree( ctor );
2372 session->metainfoLookup = lookup;
2373 tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
2376 const char*
2377 tr_sessionFindTorrentFile( const tr_session * session,
2378 const char * hashString )
2380 const char * filename = NULL;
2381 if( !session->metainfoLookup )
2382 metainfoLookupInit( (tr_session*)session );
2383 tr_bencDictFindStr( session->metainfoLookup, hashString, &filename );
2384 return filename;
2387 void
2388 tr_sessionSetTorrentFile( tr_session * session,
2389 const char * hashString,
2390 const char * filename )
2392 /* since we walk session->configDir/torrents/ to build the lookup table,
2393 * and tr_sessionSetTorrentFile() is just to tell us there's a new file
2394 * in that same directory, we don't need to do anything here if the
2395 * lookup table hasn't been built yet */
2396 if( session->metainfoLookup )
2397 tr_bencDictAddStr( session->metainfoLookup, hashString, filename );
2400 /***
2401 ****
2402 ***/
2404 void
2405 tr_sessionSetRPCEnabled( tr_session * session, bool isEnabled )
2407 assert( tr_isSession( session ) );
2409 tr_rpcSetEnabled( session->rpcServer, isEnabled );
2412 bool
2413 tr_sessionIsRPCEnabled( const tr_session * session )
2415 assert( tr_isSession( session ) );
2417 return tr_rpcIsEnabled( session->rpcServer );
2420 void
2421 tr_sessionSetRPCPort( tr_session * session,
2422 tr_port port )
2424 assert( tr_isSession( session ) );
2426 tr_rpcSetPort( session->rpcServer, port );
2429 tr_port
2430 tr_sessionGetRPCPort( const tr_session * session )
2432 assert( tr_isSession( session ) );
2434 return tr_rpcGetPort( session->rpcServer );
2437 void
2438 tr_sessionSetRPCUrl( tr_session * session,
2439 const char * url )
2441 assert( tr_isSession( session ) );
2443 tr_rpcSetUrl( session->rpcServer, url );
2446 const char*
2447 tr_sessionGetRPCUrl( const tr_session * session )
2449 assert( tr_isSession( session ) );
2451 return tr_rpcGetUrl( session->rpcServer );
2454 void
2455 tr_sessionSetRPCCallback( tr_session * session,
2456 tr_rpc_func func,
2457 void * user_data )
2459 assert( tr_isSession( session ) );
2461 session->rpc_func = func;
2462 session->rpc_func_user_data = user_data;
2465 void
2466 tr_sessionSetRPCWhitelist( tr_session * session,
2467 const char * whitelist )
2469 assert( tr_isSession( session ) );
2471 tr_rpcSetWhitelist( session->rpcServer, whitelist );
2474 const char*
2475 tr_sessionGetRPCWhitelist( const tr_session * session )
2477 assert( tr_isSession( session ) );
2479 return tr_rpcGetWhitelist( session->rpcServer );
2482 void
2483 tr_sessionSetRPCWhitelistEnabled( tr_session * session, bool isEnabled )
2485 assert( tr_isSession( session ) );
2487 tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
2490 bool
2491 tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
2493 assert( tr_isSession( session ) );
2495 return tr_rpcGetWhitelistEnabled( session->rpcServer );
2499 void
2500 tr_sessionSetRPCPassword( tr_session * session,
2501 const char * password )
2503 assert( tr_isSession( session ) );
2505 tr_rpcSetPassword( session->rpcServer, password );
2508 const char*
2509 tr_sessionGetRPCPassword( const tr_session * session )
2511 assert( tr_isSession( session ) );
2513 return tr_rpcGetPassword( session->rpcServer );
2516 void
2517 tr_sessionSetRPCUsername( tr_session * session,
2518 const char * username )
2520 assert( tr_isSession( session ) );
2522 tr_rpcSetUsername( session->rpcServer, username );
2525 const char*
2526 tr_sessionGetRPCUsername( const tr_session * session )
2528 assert( tr_isSession( session ) );
2530 return tr_rpcGetUsername( session->rpcServer );
2533 void
2534 tr_sessionSetRPCPasswordEnabled( tr_session * session, bool isEnabled )
2536 assert( tr_isSession( session ) );
2538 tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
2541 bool
2542 tr_sessionIsRPCPasswordEnabled( const tr_session * session )
2544 assert( tr_isSession( session ) );
2546 return tr_rpcIsPasswordEnabled( session->rpcServer );
2549 const char *
2550 tr_sessionGetRPCBindAddress( const tr_session * session )
2552 assert( tr_isSession( session ) );
2554 return tr_rpcGetBindAddress( session->rpcServer );
2557 /****
2558 *****
2559 ****/
2561 bool
2562 tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session )
2564 assert( tr_isSession( session ) );
2566 return session->isTorrentDoneScriptEnabled;
2569 void
2570 tr_sessionSetTorrentDoneScriptEnabled( tr_session * session, bool isEnabled )
2572 assert( tr_isSession( session ) );
2573 assert( tr_isBool( isEnabled ) );
2575 session->isTorrentDoneScriptEnabled = isEnabled;
2578 const char *
2579 tr_sessionGetTorrentDoneScript( const tr_session * session )
2581 assert( tr_isSession( session ) );
2583 return session->torrentDoneScript;
2586 void
2587 tr_sessionSetTorrentDoneScript( tr_session * session, const char * scriptFilename )
2589 assert( tr_isSession( session ) );
2591 if( session->torrentDoneScript != scriptFilename )
2593 tr_free( session->torrentDoneScript );
2594 session->torrentDoneScript = tr_strdup( scriptFilename );