source: trunk/libtransmission/session.c @ 13824

Last change on this file since 13824 was 13824, checked in by jordan, 8 years ago

(libT) copyediting: rename the internal tr_blocklist class 'tr_blocklistFile' to distinguish the private per-file API from the public, global API in libtransmission.h

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