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