source: trunk/libtransmission/session.c @ 13700

Last change on this file since 13700 was 13700, checked in by jordan, 9 years ago

(trunk, libT) #3833 'freespace' argument for 'session-get' RPC method -- use TR_PATH_MAX instead of PATH_MAX for session.downloadDirFsType and session.downloadDirBlkDev

  • Property svn:keywords set to Date Rev Author Id
File size: 76.0 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 13700 2012-12-27 20:22:32Z 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    session->downloadDirBlkDev = tr_malloc (TR_PATH_MAX + 1);
594    session->downloadDirFsType = tr_malloc (TR_PATH_MAX + 1);
595    tr_bandwidthConstruct (&session->bandwidth, session, NULL);
596    tr_peerIdInit (session->peer_id);
597    tr_variantInitList (&session->removedTorrents, 0);
598
599    /* nice to start logging at the very beginning */
600    if (tr_variantDictFindInt (clientSettings, TR_KEY_message_level, &i))
601        tr_setMessageLevel (i);
602
603    /* start the libtransmission thread */
604    tr_netInit (); /* must go before tr_eventInit */
605    tr_eventInit (session);
606    assert (session->events != NULL);
607
608    /* run the rest in the libtransmission thread */
609    data.done = false;
610    data.session = session;
611    data.configDir = configDir;
612    data.messageQueuingEnabled = messageQueuingEnabled;
613    data.clientSettings = clientSettings;
614    tr_runInEventThread (session, tr_sessionInitImpl, &data);
615    while (!data.done)
616        tr_wait_msec (100);
617
618    return session;
619}
620
621static void turtleCheckClock (tr_session * s, struct tr_turtle_info * t);
622
623static void
624onNowTimer (int foo UNUSED, short bar UNUSED, void * vsession)
625{
626    int usec;
627    const int min = 100;
628    const int max = 999999;
629    struct timeval tv;
630    tr_torrent * tor = NULL;
631    tr_session * session = vsession;
632    const time_t now = time (NULL);
633
634    assert (tr_isSession (session));
635    assert (session->nowTimer != NULL);
636
637    /**
638    ***  tr_session things to do once per second
639    **/
640
641    tr_timeUpdate (now);
642
643    tr_dhtUpkeep (session);
644
645    if (session->turtle.isClockEnabled)
646        turtleCheckClock (session, &session->turtle);
647
648    while ((tor = tr_torrentNext (session, tor))) {
649        if (tor->isRunning) {
650            if (tr_torrentIsSeed (tor))
651                ++tor->secondsSeeding;
652            else
653                ++tor->secondsDownloading;
654        }
655    }
656
657    /**
658    ***  Set the timer
659    **/
660
661    /* schedule the next timer for right after the next second begins */
662    gettimeofday (&tv, NULL);
663    usec = 1000000 - tv.tv_usec;
664    if (usec > max) usec = max;
665    if (usec < min) usec = min;
666    tr_timerAdd (session->nowTimer, 0, usec);
667    /* fprintf (stderr, "time %zu sec, %zu microsec\n", (size_t)tr_time (), (size_t)tv.tv_usec); */
668}
669
670static void loadBlocklists (tr_session * session);
671
672static void
673tr_sessionInitImpl (void * vdata)
674{
675    tr_variant settings;
676    struct init_data * data = vdata;
677    tr_variant * clientSettings = data->clientSettings;
678    tr_session * session = data->session;
679
680    assert (tr_amInEventThread (session));
681    assert (tr_variantIsDict (clientSettings));
682
683    dbgmsg ("tr_sessionInit: the session's top-level bandwidth object is %p",
684            &session->bandwidth);
685
686    tr_variantInitDict (&settings, 0);
687    tr_sessionGetDefaultSettings (&settings);
688    tr_variantMergeDicts (&settings, clientSettings);
689
690    assert (session->event_base != NULL);
691    session->nowTimer = evtimer_new (session->event_base, onNowTimer, session);
692    onNowTimer (0, 0, session);
693
694#ifndef WIN32
695    /* Don't exit when writing on a broken socket */
696    signal (SIGPIPE, SIG_IGN);
697#endif
698
699    tr_setMessageQueuing (data->messageQueuingEnabled);
700
701    tr_setConfigDir (session, data->configDir);
702
703    session->peerMgr = tr_peerMgrNew (session);
704
705    session->shared = tr_sharedInit (session);
706
707    /**
708    ***  Blocklist
709    **/
710
711    {
712        char * filename = tr_buildPath (session->configDir, "blocklists", NULL);
713        tr_mkdirp (filename, 0777);
714        tr_free (filename);
715        loadBlocklists (session);
716    }
717
718    assert (tr_isSession (session));
719
720    session->saveTimer = evtimer_new (session->event_base, onSaveTimer, session);
721    tr_timerAdd (session->saveTimer, SAVE_INTERVAL_SECS, 0);
722
723    tr_announcerInit (session);
724
725    /* first %s is the application name
726       second %s is the version number */
727    tr_inf (_("%s %s started"), TR_NAME, LONG_VERSION_STRING);
728
729    tr_statsInit (session);
730
731    tr_webInit (session);
732
733    tr_sessionSet (session, &settings);
734
735    tr_udpInit (session);
736
737    if (session->isLPDEnabled)
738        tr_lpdInit (session, &session->public_ipv4->addr);
739
740    /* cleanup */
741    tr_variantFree (&settings);
742    data->done = true;
743}
744
745static void turtleBootstrap (tr_session *, struct tr_turtle_info *);
746static void setPeerPort (tr_session * session, tr_port port);
747
748static void
749sessionSetImpl (void * vdata)
750{
751    int64_t i;
752    double  d;
753    bool boolVal;
754    const char * str;
755    struct tr_bindinfo b;
756    struct init_data * data = vdata;
757    tr_session * session = data->session;
758    tr_variant * settings = data->clientSettings;
759    struct tr_turtle_info * turtle = &session->turtle;
760
761    assert (tr_isSession (session));
762    assert (tr_variantIsDict (settings));
763    assert (tr_amInEventThread (session));
764
765    if (tr_variantDictFindInt (settings, TR_KEY_message_level, &i))
766        tr_setMessageLevel (i);
767
768    if (tr_variantDictFindInt (settings, TR_KEY_umask, &i)) {
769        session->umask = (mode_t)i;
770        umask (session->umask);
771    }
772
773    /* misc features */
774    if (tr_variantDictFindInt (settings, TR_KEY_cache_size_mb, &i))
775        tr_sessionSetCacheLimit_MB (session, i);
776    if (tr_variantDictFindInt (settings, TR_KEY_peer_limit_per_torrent, &i))
777        tr_sessionSetPeerLimitPerTorrent (session, i);
778    if (tr_variantDictFindBool (settings, TR_KEY_pex_enabled, &boolVal))
779        tr_sessionSetPexEnabled (session, boolVal);
780    if (tr_variantDictFindBool (settings, TR_KEY_dht_enabled, &boolVal))
781        tr_sessionSetDHTEnabled (session, boolVal);
782    if (tr_variantDictFindBool (settings, TR_KEY_utp_enabled, &boolVal))
783        tr_sessionSetUTPEnabled (session, boolVal);
784    if (tr_variantDictFindBool (settings, TR_KEY_lpd_enabled, &boolVal))
785        tr_sessionSetLPDEnabled (session, boolVal);
786    if (tr_variantDictFindInt (settings, TR_KEY_encryption, &i))
787        tr_sessionSetEncryption (session, i);
788    if (tr_variantDictFindStr (settings, TR_KEY_peer_socket_tos, &str, NULL))
789        session->peerSocketTOS = parse_tos (str);
790    if (tr_variantDictFindStr (settings, TR_KEY_peer_congestion_algorithm, &str, NULL))
791        session->peer_congestion_algorithm = tr_strdup (str);
792    else
793        session->peer_congestion_algorithm = tr_strdup ("");
794    if (tr_variantDictFindBool (settings, TR_KEY_blocklist_enabled, &boolVal))
795        tr_blocklistSetEnabled (session, boolVal);
796    if (tr_variantDictFindStr (settings, TR_KEY_blocklist_url, &str, NULL))
797        tr_blocklistSetURL (session, str);
798    if (tr_variantDictFindBool (settings, TR_KEY_start_added_torrents, &boolVal))
799        tr_sessionSetPaused (session, !boolVal);
800    if (tr_variantDictFindBool (settings, TR_KEY_trash_original_torrent_files, &boolVal))
801        tr_sessionSetDeleteSource (session, boolVal);
802
803    /* torrent queues */
804    if (tr_variantDictFindInt (settings, TR_KEY_queue_stalled_minutes, &i))
805        tr_sessionSetQueueStalledMinutes (session, i);
806    if (tr_variantDictFindBool (settings, TR_KEY_queue_stalled_enabled, &boolVal))
807        tr_sessionSetQueueStalledEnabled (session, boolVal);
808    if (tr_variantDictFindInt (settings, TR_KEY_download_queue_size, &i))
809        tr_sessionSetQueueSize (session, TR_DOWN, i);
810    if (tr_variantDictFindBool (settings, TR_KEY_download_queue_enabled, &boolVal))
811        tr_sessionSetQueueEnabled (session, TR_DOWN, boolVal);
812    if (tr_variantDictFindInt (settings, TR_KEY_seed_queue_size, &i))
813        tr_sessionSetQueueSize (session, TR_UP, i);
814    if (tr_variantDictFindBool (settings, TR_KEY_seed_queue_enabled, &boolVal))
815        tr_sessionSetQueueEnabled (session, TR_UP, boolVal);
816
817    /* files and directories */
818    if (tr_variantDictFindBool (settings, TR_KEY_prefetch_enabled, &boolVal))
819        session->isPrefetchEnabled = boolVal;
820    if (tr_variantDictFindInt (settings, TR_KEY_preallocation, &i))
821        session->preallocationMode = i;
822    if (tr_variantDictFindStr (settings, TR_KEY_download_dir, &str, NULL))
823        tr_sessionSetDownloadDir (session, str);
824    if (tr_variantDictFindStr (settings, TR_KEY_incomplete_dir, &str, NULL))
825        tr_sessionSetIncompleteDir (session, str);
826    if (tr_variantDictFindBool (settings, TR_KEY_incomplete_dir_enabled, &boolVal))
827        tr_sessionSetIncompleteDirEnabled (session, boolVal);
828    if (tr_variantDictFindBool (settings, TR_KEY_rename_partial_files, &boolVal))
829        tr_sessionSetIncompleteFileNamingEnabled (session, boolVal);
830
831    /* rpc server */
832    if (session->rpcServer != NULL) /* close the old one */
833        tr_rpcClose (&session->rpcServer);
834    session->rpcServer = tr_rpcInit (session, settings);
835
836    /* public addresses */
837
838    free_incoming_peer_port (session);
839
840    tr_variantDictFindStr (settings, TR_KEY_bind_address_ipv4, &str, NULL);
841    if (!tr_address_from_string (&b.addr, str) || (b.addr.type != TR_AF_INET))
842        b.addr = tr_inaddr_any;
843    b.socket = -1;
844    session->public_ipv4 = tr_memdup (&b, sizeof (struct tr_bindinfo));
845
846    tr_variantDictFindStr (settings, TR_KEY_bind_address_ipv6, &str, NULL);
847    if (!tr_address_from_string (&b.addr, str) || (b.addr.type != TR_AF_INET6))
848        b.addr = tr_in6addr_any;
849    b.socket = -1;
850    session->public_ipv6 = tr_memdup (&b, sizeof (struct tr_bindinfo));
851
852    /* incoming peer port */
853    if (tr_variantDictFindInt (settings, TR_KEY_peer_port_random_low, &i))
854        session->randomPortLow = i;
855    if (tr_variantDictFindInt (settings, TR_KEY_peer_port_random_high, &i))
856        session->randomPortHigh = i;
857    if (tr_variantDictFindBool (settings, TR_KEY_peer_port_random_on_start, &boolVal))
858        tr_sessionSetPeerPortRandomOnStart (session, boolVal);
859    if (!tr_variantDictFindInt (settings, TR_KEY_peer_port, &i))
860        i = session->private_peer_port;
861    setPeerPort (session, boolVal ? getRandomPort (session) : i);
862    if (tr_variantDictFindBool (settings, TR_KEY_port_forwarding_enabled, &boolVal))
863        tr_sessionSetPortForwardingEnabled (session, boolVal);
864
865    if (tr_variantDictFindInt (settings, TR_KEY_peer_limit_global, &i))
866        session->peerLimit = i;
867
868    /**
869    **/
870
871    if (tr_variantDictFindInt (settings, TR_KEY_upload_slots_per_torrent, &i))
872        session->uploadSlotsPerTorrent = i;
873
874    if (tr_variantDictFindInt (settings, TR_KEY_speed_limit_up, &i))
875        tr_sessionSetSpeedLimit_KBps (session, TR_UP, i);
876    if (tr_variantDictFindBool (settings, TR_KEY_speed_limit_up_enabled, &boolVal))
877        tr_sessionLimitSpeed (session, TR_UP, boolVal);
878
879    if (tr_variantDictFindInt (settings, TR_KEY_speed_limit_down, &i))
880        tr_sessionSetSpeedLimit_KBps (session, TR_DOWN, i);
881    if (tr_variantDictFindBool (settings, TR_KEY_speed_limit_down_enabled, &boolVal))
882        tr_sessionLimitSpeed (session, TR_DOWN, boolVal);
883
884    if (tr_variantDictFindReal (settings, TR_KEY_ratio_limit, &d))
885        tr_sessionSetRatioLimit (session, d);
886    if (tr_variantDictFindBool (settings, TR_KEY_ratio_limit_enabled, &boolVal))
887        tr_sessionSetRatioLimited (session, boolVal);
888
889    if (tr_variantDictFindInt (settings, TR_KEY_idle_seeding_limit, &i))
890        tr_sessionSetIdleLimit (session, i);
891    if (tr_variantDictFindBool (settings, TR_KEY_idle_seeding_limit_enabled, &boolVal))
892        tr_sessionSetIdleLimited (session, boolVal);
893
894    /**
895    ***  Turtle Mode
896    **/
897
898    /* update the turtle mode's fields */
899    if (tr_variantDictFindInt (settings, TR_KEY_alt_speed_up, &i))
900        turtle->speedLimit_Bps[TR_UP] = toSpeedBytes (i);
901    if (tr_variantDictFindInt (settings, TR_KEY_alt_speed_down, &i))
902        turtle->speedLimit_Bps[TR_DOWN] = toSpeedBytes (i);
903    if (tr_variantDictFindInt (settings, TR_KEY_alt_speed_time_begin, &i))
904        turtle->beginMinute = i;
905    if (tr_variantDictFindInt (settings, TR_KEY_alt_speed_time_end, &i))
906        turtle->endMinute = i;
907    if (tr_variantDictFindInt (settings, TR_KEY_alt_speed_time_day, &i))
908        turtle->days = i;
909    if (tr_variantDictFindBool (settings, TR_KEY_alt_speed_time_enabled, &boolVal))
910        turtle->isClockEnabled = boolVal;
911    if (tr_variantDictFindBool (settings, TR_KEY_alt_speed_enabled, &boolVal))
912        turtle->isEnabled = boolVal;
913    turtleBootstrap (session, turtle);
914
915    /**
916    ***  Scripts
917    **/
918
919    if (tr_variantDictFindBool (settings, TR_KEY_script_torrent_done_enabled, &boolVal))
920        tr_sessionSetTorrentDoneScriptEnabled (session, boolVal);
921    if (tr_variantDictFindStr (settings, TR_KEY_script_torrent_done_filename, &str, NULL))
922        tr_sessionSetTorrentDoneScript (session, str);
923
924
925    if (tr_variantDictFindBool (settings, TR_KEY_scrape_paused_torrents_enabled, &boolVal))
926        session->scrapePausedTorrents = boolVal;
927
928    data->done = true;
929}
930
931void
932tr_sessionSet (tr_session * session, tr_variant  * settings)
933{
934  struct init_data data;
935  data.done = false;
936  data.session = session;
937  data.clientSettings = settings;
938
939  /* run the rest in the libtransmission thread */
940  tr_runInEventThread (session, sessionSetImpl, &data);
941  while (!data.done)
942    tr_wait_msec (100);
943}
944
945/***
946****
947***/
948
949void
950tr_sessionSetDownloadDir (tr_session * session, const char * dir)
951{
952    assert (tr_isSession (session));
953
954    if (session->downloadDir != dir)
955    {
956        tr_free (session->downloadDir);
957        session->downloadDir = tr_strdup (dir);
958        memset (session->downloadDirBlkDev, 0, sizeof(session->downloadDirBlkDev));
959        memset (session->downloadDirFsType, 0, sizeof(session->downloadDirFsType));
960    }
961}
962
963const char *
964tr_sessionGetDownloadDir (const tr_session * session)
965{
966    assert (tr_isSession (session));
967
968    return session->downloadDir;
969}
970
971int64_t
972tr_sessionGetDownloadDirFreeSpace (const tr_session * session)
973{
974    assert (tr_isSession (session));
975
976    return tr_getFreeSpace (session->downloadDir, session->downloadDirBlkDev,
977    session->downloadDirFsType);
978}
979
980/***
981****
982***/
983
984void
985tr_sessionSetIncompleteFileNamingEnabled (tr_session * session, bool b)
986{
987    assert (tr_isSession (session));
988    assert (tr_isBool (b));
989
990    session->isIncompleteFileNamingEnabled = b;
991}
992
993bool
994tr_sessionIsIncompleteFileNamingEnabled (const tr_session * session)
995{
996    assert (tr_isSession (session));
997
998    return session->isIncompleteFileNamingEnabled;
999}
1000
1001/***
1002****
1003***/
1004
1005
1006void
1007tr_sessionSetIncompleteDir (tr_session * session, const char * dir)
1008{
1009    assert (tr_isSession (session));
1010
1011    if (session->incompleteDir != dir)
1012    {
1013        tr_free (session->incompleteDir);
1014
1015        session->incompleteDir = tr_strdup (dir);
1016    }
1017}
1018
1019const char*
1020tr_sessionGetIncompleteDir (const tr_session * session)
1021{
1022    assert (tr_isSession (session));
1023
1024    return session->incompleteDir;
1025}
1026
1027void
1028tr_sessionSetIncompleteDirEnabled (tr_session * session, bool b)
1029{
1030    assert (tr_isSession (session));
1031    assert (tr_isBool (b));
1032
1033    session->isIncompleteDirEnabled = b;
1034}
1035
1036bool
1037tr_sessionIsIncompleteDirEnabled (const tr_session * session)
1038{
1039    assert (tr_isSession (session));
1040
1041    return session->isIncompleteDirEnabled;
1042}
1043
1044/***
1045****
1046***/
1047
1048void
1049tr_sessionLock (tr_session * session)
1050{
1051    assert (tr_isSession (session));
1052
1053    tr_lockLock (session->lock);
1054}
1055
1056void
1057tr_sessionUnlock (tr_session * session)
1058{
1059    assert (tr_isSession (session));
1060
1061    tr_lockUnlock (session->lock);
1062}
1063
1064bool
1065tr_sessionIsLocked (const tr_session * session)
1066{
1067    return tr_isSession (session) && tr_lockHave (session->lock);
1068}
1069
1070/***********************************************************************
1071 * tr_setBindPort
1072 ***********************************************************************
1073 *
1074 **********************************************************************/
1075
1076static void
1077peerPortChanged (void * session)
1078{
1079    tr_torrent * tor = NULL;
1080
1081    assert (tr_isSession (session));
1082
1083    close_incoming_peer_port (session);
1084    open_incoming_peer_port (session);
1085    tr_sharedPortChanged (session);
1086
1087    while ((tor = tr_torrentNext (session, tor)))
1088        tr_torrentChangeMyPort (tor);
1089}
1090
1091static void
1092setPeerPort (tr_session * session, tr_port port)
1093{
1094    session->private_peer_port = port;
1095    session->public_peer_port = port;
1096
1097    tr_runInEventThread (session, peerPortChanged, session);
1098}
1099
1100void
1101tr_sessionSetPeerPort (tr_session * session, tr_port port)
1102{
1103    if (tr_isSession (session) && (session->private_peer_port != port))
1104    {
1105        setPeerPort (session, port);
1106    }
1107}
1108
1109tr_port
1110tr_sessionGetPeerPort (const tr_session * session)
1111{
1112    return tr_isSession (session) ? session->private_peer_port : 0;
1113}
1114
1115tr_port
1116tr_sessionSetPeerPortRandom (tr_session * session)
1117{
1118    assert (tr_isSession (session));
1119
1120    tr_sessionSetPeerPort (session, getRandomPort (session));
1121    return session->private_peer_port;
1122}
1123
1124void
1125tr_sessionSetPeerPortRandomOnStart (tr_session * session,
1126                                    bool random)
1127{
1128    assert (tr_isSession (session));
1129
1130    session->isPortRandom = random;
1131}
1132
1133bool
1134tr_sessionGetPeerPortRandomOnStart (tr_session * session)
1135{
1136    assert (tr_isSession (session));
1137
1138    return session->isPortRandom;
1139}
1140
1141tr_port_forwarding
1142tr_sessionGetPortForwarding (const tr_session * session)
1143{
1144    assert (tr_isSession (session));
1145
1146    return tr_sharedTraversalStatus (session->shared);
1147}
1148
1149/***
1150****
1151***/
1152
1153void
1154tr_sessionSetRatioLimited (tr_session * session, bool isLimited)
1155{
1156    assert (tr_isSession (session));
1157
1158    session->isRatioLimited = isLimited;
1159}
1160
1161void
1162tr_sessionSetRatioLimit (tr_session * session, double desiredRatio)
1163{
1164    assert (tr_isSession (session));
1165
1166    session->desiredRatio = desiredRatio;
1167}
1168
1169bool
1170tr_sessionIsRatioLimited (const tr_session  * session)
1171{
1172    assert (tr_isSession (session));
1173
1174    return session->isRatioLimited;
1175}
1176
1177double
1178tr_sessionGetRatioLimit (const tr_session * session)
1179{
1180    assert (tr_isSession (session));
1181
1182    return session->desiredRatio;
1183}
1184
1185/***
1186****
1187***/
1188
1189void
1190tr_sessionSetIdleLimited (tr_session * session, bool isLimited)
1191{
1192    assert (tr_isSession (session));
1193
1194    session->isIdleLimited = isLimited;
1195}
1196
1197void
1198tr_sessionSetIdleLimit (tr_session * session, uint16_t idleMinutes)
1199{
1200    assert (tr_isSession (session));
1201
1202    session->idleLimitMinutes = idleMinutes;
1203}
1204
1205bool
1206tr_sessionIsIdleLimited (const tr_session  * session)
1207{
1208    assert (tr_isSession (session));
1209
1210    return session->isIdleLimited;
1211}
1212
1213uint16_t
1214tr_sessionGetIdleLimit (const tr_session * session)
1215{
1216    assert (tr_isSession (session));
1217
1218    return session->idleLimitMinutes;
1219}
1220
1221/***
1222****
1223****  SPEED LIMITS
1224****
1225***/
1226
1227bool
1228tr_sessionGetActiveSpeedLimit_Bps (const tr_session * session, tr_direction dir, unsigned int * setme_Bps)
1229{
1230    int isLimited = true;
1231
1232    if (!tr_isSession (session))
1233        return false;
1234
1235    if (tr_sessionUsesAltSpeed (session))
1236        *setme_Bps = tr_sessionGetAltSpeed_Bps (session, dir);
1237    else if (tr_sessionIsSpeedLimited (session, dir))
1238        *setme_Bps = tr_sessionGetSpeedLimit_Bps (session, dir);
1239    else
1240        isLimited = false;
1241
1242    return isLimited;
1243}
1244bool
1245tr_sessionGetActiveSpeedLimit_KBps (const tr_session  * session,
1246                                    tr_direction        dir,
1247                                    double            * setme_KBps)
1248{
1249    unsigned int Bps = 0;
1250    const bool is_active = tr_sessionGetActiveSpeedLimit_Bps (session, dir, &Bps);
1251    *setme_KBps = toSpeedKBps (Bps);
1252    return is_active;
1253}
1254
1255static void
1256updateBandwidth (tr_session * session, tr_direction dir)
1257{
1258    unsigned int limit_Bps = 0;
1259    const bool isLimited = tr_sessionGetActiveSpeedLimit_Bps (session, dir, &limit_Bps);
1260    const bool zeroCase = isLimited && !limit_Bps;
1261
1262    tr_bandwidthSetLimited (&session->bandwidth, dir, isLimited && !zeroCase);
1263
1264    tr_bandwidthSetDesiredSpeed_Bps (&session->bandwidth, dir, limit_Bps);
1265}
1266
1267enum
1268{
1269    MINUTES_PER_HOUR = 60,
1270    MINUTES_PER_DAY = MINUTES_PER_HOUR * 24,
1271    MINUTES_PER_WEEK = MINUTES_PER_DAY * 7
1272};
1273
1274static void
1275turtleUpdateTable (struct tr_turtle_info * t)
1276{
1277    int day;
1278    tr_bitfield * b = &t->minutes;
1279
1280    tr_bitfieldSetHasNone (b);
1281
1282    for (day=0; day<7; ++day)
1283    {
1284        if (t->days & (1<<day))
1285        {
1286            int i;
1287            const time_t begin = t->beginMinute;
1288            time_t end = t->endMinute;
1289
1290            if (end <= begin)
1291                end += MINUTES_PER_DAY;
1292
1293            for (i=begin; i<end; ++i)
1294                tr_bitfieldAdd (b, (i+day*MINUTES_PER_DAY) % MINUTES_PER_WEEK);
1295        }
1296    }
1297}
1298
1299static void
1300altSpeedToggled (void * vsession)
1301{
1302    tr_session * session = vsession;
1303    struct tr_turtle_info * t = &session->turtle;
1304
1305    assert (tr_isSession (session));
1306
1307    updateBandwidth (session, TR_UP);
1308    updateBandwidth (session, TR_DOWN);
1309
1310    if (t->callback != NULL)
1311      (*t->callback)(session, t->isEnabled, t->changedByUser, t->callbackUserData);
1312}
1313
1314static void
1315useAltSpeed (tr_session * s, struct tr_turtle_info * t,
1316             bool enabled, bool byUser)
1317{
1318    assert (tr_isSession (s));
1319    assert (t != NULL);
1320    assert (tr_isBool (enabled));
1321    assert (tr_isBool (byUser));
1322
1323    if (t->isEnabled != enabled)
1324    {
1325        t->isEnabled = enabled;
1326        t->changedByUser = byUser;
1327        tr_runInEventThread (s, altSpeedToggled, s);
1328    }
1329}
1330
1331/**
1332 * @return whether turtle should be on/off according to the scheduler
1333 */
1334static bool
1335getInTurtleTime (const struct tr_turtle_info * t)
1336{
1337    struct tm tm;
1338    size_t minute_of_the_week;
1339    const time_t now = tr_time ();
1340
1341    tr_localtime_r (&now, &tm);
1342
1343    minute_of_the_week = tm.tm_wday * MINUTES_PER_DAY
1344                       + tm.tm_hour * MINUTES_PER_HOUR
1345                       + tm.tm_min;
1346    if (minute_of_the_week >= MINUTES_PER_WEEK) /* leap minutes? */
1347        minute_of_the_week = MINUTES_PER_WEEK - 1;
1348
1349    return tr_bitfieldHas (&t->minutes, minute_of_the_week);
1350}
1351
1352static inline tr_auto_switch_state_t
1353autoSwitchState (bool enabled)
1354{
1355    return enabled ? TR_AUTO_SWITCH_ON : TR_AUTO_SWITCH_OFF;
1356}
1357
1358static void
1359turtleCheckClock (tr_session * s, struct tr_turtle_info * t)
1360{
1361    bool enabled;
1362    bool alreadySwitched;
1363    tr_auto_switch_state_t newAutoTurtleState;
1364
1365    assert (t->isClockEnabled);
1366
1367    enabled = getInTurtleTime (t);
1368    newAutoTurtleState = autoSwitchState (enabled);
1369    alreadySwitched = (t->autoTurtleState == newAutoTurtleState);
1370
1371    if (!alreadySwitched)
1372    {
1373        tr_inf ("Time to turn %s turtle mode!", (enabled?"on":"off"));
1374        t->autoTurtleState = newAutoTurtleState;
1375        useAltSpeed (s, t, enabled, false);
1376    }
1377}
1378
1379/* Called after the turtle's fields are loaded from an outside source.
1380 * It initializes the implementation fields
1381 * and turns on turtle mode if the clock settings say to. */
1382static void
1383turtleBootstrap (tr_session * session, struct tr_turtle_info * turtle)
1384{
1385    turtle->changedByUser = false;
1386    turtle->autoTurtleState = TR_AUTO_SWITCH_UNUSED;
1387
1388    tr_bitfieldConstruct (&turtle->minutes, MINUTES_PER_WEEK);
1389
1390    turtleUpdateTable (turtle);
1391
1392    if (turtle->isClockEnabled)
1393    {
1394        turtle->isEnabled = getInTurtleTime (turtle);
1395        turtle->autoTurtleState = autoSwitchState (turtle->isEnabled);
1396    }
1397
1398    altSpeedToggled (session);
1399
1400}
1401
1402/***
1403****  Primary session speed limits
1404***/
1405
1406void
1407tr_sessionSetSpeedLimit_Bps (tr_session * s, tr_direction d, unsigned int Bps)
1408{
1409    assert (tr_isSession (s));
1410    assert (tr_isDirection (d));
1411
1412    s->speedLimit_Bps[d] = Bps;
1413
1414    updateBandwidth (s, d);
1415}
1416void
1417tr_sessionSetSpeedLimit_KBps (tr_session * s, tr_direction d, unsigned int KBps)
1418{
1419    tr_sessionSetSpeedLimit_Bps (s, d, toSpeedBytes (KBps));
1420}
1421
1422unsigned int
1423tr_sessionGetSpeedLimit_Bps (const tr_session * s, tr_direction d)
1424{
1425    assert (tr_isSession (s));
1426    assert (tr_isDirection (d));
1427
1428    return s->speedLimit_Bps[d];
1429}
1430unsigned int
1431tr_sessionGetSpeedLimit_KBps (const tr_session * s, tr_direction d)
1432{
1433    return toSpeedKBps (tr_sessionGetSpeedLimit_Bps (s, d));
1434}
1435
1436void
1437tr_sessionLimitSpeed (tr_session * s, tr_direction d, bool b)
1438{
1439    assert (tr_isSession (s));
1440    assert (tr_isDirection (d));
1441    assert (tr_isBool (b));
1442
1443    s->speedLimitEnabled[d] = b;
1444
1445    updateBandwidth (s, d);
1446}
1447
1448bool
1449tr_sessionIsSpeedLimited (const tr_session * s, tr_direction d)
1450{
1451    assert (tr_isSession (s));
1452    assert (tr_isDirection (d));
1453
1454    return s->speedLimitEnabled[d];
1455}
1456
1457/***
1458****  Alternative speed limits that are used during scheduled times
1459***/
1460
1461void
1462tr_sessionSetAltSpeed_Bps (tr_session * s, tr_direction d, unsigned int Bps)
1463{
1464    assert (tr_isSession (s));
1465    assert (tr_isDirection (d));
1466
1467    s->turtle.speedLimit_Bps[d] = Bps;
1468
1469    updateBandwidth (s, d);
1470}
1471
1472void
1473tr_sessionSetAltSpeed_KBps (tr_session * s, tr_direction d, unsigned int KBps)
1474{
1475    tr_sessionSetAltSpeed_Bps (s, d, toSpeedBytes (KBps));
1476}
1477
1478unsigned int
1479tr_sessionGetAltSpeed_Bps (const tr_session * s, tr_direction d)
1480{
1481    assert (tr_isSession (s));
1482    assert (tr_isDirection (d));
1483
1484    return s->turtle.speedLimit_Bps[d];
1485}
1486unsigned int
1487tr_sessionGetAltSpeed_KBps (const tr_session * s, tr_direction d)
1488{
1489    return toSpeedKBps (tr_sessionGetAltSpeed_Bps (s, d));
1490}
1491
1492static void
1493userPokedTheClock (tr_session * s, struct tr_turtle_info * t)
1494{
1495    tr_dbg ("Refreshing the turtle mode clock due to user changes");
1496
1497    t->autoTurtleState = TR_AUTO_SWITCH_UNUSED;
1498
1499    turtleUpdateTable (t);
1500
1501    if (t->isClockEnabled)
1502    {
1503        const bool enabled = getInTurtleTime (t);
1504        useAltSpeed (s, t, enabled, true);
1505        t->autoTurtleState = autoSwitchState (enabled);
1506    }
1507}
1508
1509void
1510tr_sessionUseAltSpeedTime (tr_session * s, bool b)
1511{
1512    struct tr_turtle_info * t = &s->turtle;
1513
1514    assert (tr_isSession (s));
1515    assert (tr_isBool (b));
1516
1517    if (t->isClockEnabled != b) {
1518        t->isClockEnabled = b;
1519        userPokedTheClock (s, t);
1520    }
1521}
1522
1523bool
1524tr_sessionUsesAltSpeedTime (const tr_session * s)
1525{
1526    assert (tr_isSession (s));
1527
1528    return s->turtle.isClockEnabled;
1529}
1530
1531void
1532tr_sessionSetAltSpeedBegin (tr_session * s, int minute)
1533{
1534    assert (tr_isSession (s));
1535    assert (0<=minute && minute< (60*24));
1536
1537    if (s->turtle.beginMinute != minute) {
1538        s->turtle.beginMinute = minute;
1539        userPokedTheClock (s, &s->turtle);
1540    }
1541}
1542
1543int
1544tr_sessionGetAltSpeedBegin (const tr_session * s)
1545{
1546    assert (tr_isSession (s));
1547
1548    return s->turtle.beginMinute;
1549}
1550
1551void
1552tr_sessionSetAltSpeedEnd (tr_session * s, int minute)
1553{
1554    assert (tr_isSession (s));
1555    assert (0<=minute && minute< (60*24));
1556
1557    if (s->turtle.endMinute != minute) {
1558        s->turtle.endMinute = minute;
1559        userPokedTheClock (s, &s->turtle);
1560    }
1561}
1562
1563int
1564tr_sessionGetAltSpeedEnd (const tr_session * s)
1565{
1566    assert (tr_isSession (s));
1567
1568    return s->turtle.endMinute;
1569}
1570
1571void
1572tr_sessionSetAltSpeedDay (tr_session * s, tr_sched_day days)
1573{
1574    assert (tr_isSession (s));
1575
1576    if (s->turtle.days != days) {
1577        s->turtle.days = days;
1578        userPokedTheClock (s, &s->turtle);
1579    }
1580}
1581
1582tr_sched_day
1583tr_sessionGetAltSpeedDay (const tr_session * s)
1584{
1585    assert (tr_isSession (s));
1586
1587    return s->turtle.days;
1588}
1589
1590void
1591tr_sessionUseAltSpeed (tr_session * session, bool enabled)
1592{
1593    useAltSpeed (session, &session->turtle, enabled, true);
1594}
1595
1596bool
1597tr_sessionUsesAltSpeed (const tr_session * s)
1598{
1599    assert (tr_isSession (s));
1600
1601    return s->turtle.isEnabled;
1602}
1603
1604void
1605tr_sessionSetAltSpeedFunc (tr_session       * session,
1606                           tr_altSpeedFunc    func,
1607                           void             * userData)
1608{
1609    assert (tr_isSession (session));
1610
1611    session->turtle.callback = func;
1612    session->turtle.callbackUserData = userData;
1613}
1614
1615void
1616tr_sessionClearAltSpeedFunc (tr_session * session)
1617{
1618    tr_sessionSetAltSpeedFunc (session, NULL, NULL);
1619}
1620
1621/***
1622****
1623***/
1624
1625void
1626tr_sessionSetPeerLimit (tr_session * session, uint16_t n)
1627{
1628    assert (tr_isSession (session));
1629
1630    session->peerLimit = n;
1631}
1632
1633uint16_t
1634tr_sessionGetPeerLimit (const tr_session * session)
1635{
1636    assert (tr_isSession (session));
1637
1638    return session->peerLimit;
1639}
1640
1641void
1642tr_sessionSetPeerLimitPerTorrent (tr_session  * session, uint16_t n)
1643{
1644    assert (tr_isSession (session));
1645
1646    session->peerLimitPerTorrent = n;
1647}
1648
1649uint16_t
1650tr_sessionGetPeerLimitPerTorrent (const tr_session * session)
1651{
1652    assert (tr_isSession (session));
1653
1654    return session->peerLimitPerTorrent;
1655}
1656
1657/***
1658****
1659***/
1660
1661void
1662tr_sessionSetPaused (tr_session * session, bool isPaused)
1663{
1664    assert (tr_isSession (session));
1665
1666    session->pauseAddedTorrent = isPaused;
1667}
1668
1669bool
1670tr_sessionGetPaused (const tr_session * session)
1671{
1672    assert (tr_isSession (session));
1673
1674    return session->pauseAddedTorrent;
1675}
1676
1677void
1678tr_sessionSetDeleteSource (tr_session * session, bool deleteSource)
1679{
1680    assert (tr_isSession (session));
1681
1682    session->deleteSourceTorrent = deleteSource;
1683}
1684
1685bool
1686tr_sessionGetDeleteSource (const tr_session * session)
1687{
1688    assert (tr_isSession (session));
1689
1690    return session->deleteSourceTorrent;
1691}
1692
1693/***
1694****
1695***/
1696
1697unsigned int
1698tr_sessionGetPieceSpeed_Bps (const tr_session * session, tr_direction dir)
1699{
1700    return tr_isSession (session) ? tr_bandwidthGetPieceSpeed_Bps (&session->bandwidth, 0, dir) : 0;
1701}
1702
1703unsigned int
1704tr_sessionGetRawSpeed_Bps (const tr_session * session, tr_direction dir)
1705{
1706    return tr_isSession (session) ? tr_bandwidthGetRawSpeed_Bps (&session->bandwidth, 0, dir) : 0;
1707}
1708double
1709tr_sessionGetRawSpeed_KBps (const tr_session * session, tr_direction dir)
1710{
1711    return toSpeedKBps (tr_sessionGetRawSpeed_Bps (session, dir));
1712}
1713
1714
1715int
1716tr_sessionCountTorrents (const tr_session * session)
1717{
1718    return tr_isSession (session) ? session->torrentCount : 0;
1719}
1720
1721static int
1722compareTorrentByCur (const void * va, const void * vb)
1723{
1724    const tr_torrent * a = * (const tr_torrent**)va;
1725    const tr_torrent * b = * (const tr_torrent**)vb;
1726    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1727    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1728
1729    if (aCur != bCur)
1730        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1731
1732    return 0;
1733}
1734
1735static void closeBlocklists (tr_session *);
1736
1737static void
1738sessionCloseImpl (void * vsession)
1739{
1740    tr_session *  session = vsession;
1741    tr_torrent *  tor;
1742    int           i, n;
1743    tr_torrent ** torrents;
1744
1745    assert (tr_isSession (session));
1746
1747    free_incoming_peer_port (session);
1748
1749    if (session->isLPDEnabled)
1750        tr_lpdUninit (session);
1751
1752    tr_utpClose (session);
1753    tr_dhtUninit (session);
1754
1755    event_free (session->saveTimer);
1756    session->saveTimer = NULL;
1757
1758    event_free (session->nowTimer);
1759    session->nowTimer = NULL;
1760
1761    tr_verifyClose (session);
1762    tr_sharedClose (session);
1763    tr_rpcClose (&session->rpcServer);
1764
1765    /* Close the torrents. Get the most active ones first so that
1766     * if we can't get them all closed in a reasonable amount of time,
1767     * at least we get the most important ones first. */
1768    tor = NULL;
1769    n = session->torrentCount;
1770    torrents = tr_new (tr_torrent *, session->torrentCount);
1771    for (i = 0; i < n; ++i)
1772        torrents[i] = tor = tr_torrentNext (session, tor);
1773    qsort (torrents, n, sizeof (tr_torrent*), compareTorrentByCur);
1774    for (i = 0; i < n; ++i)
1775        tr_torrentFree (torrents[i]);
1776    tr_free (torrents);
1777
1778    /* Close the announcer *after* closing the torrents
1779       so that all the &event=stopped messages will be
1780       queued to be sent by tr_announcerClose () */
1781    tr_announcerClose (session);
1782
1783    /* and this goes *after* announcer close so that
1784       it won't be idle until the announce events are sent... */
1785    tr_webClose (session, TR_WEB_CLOSE_WHEN_IDLE);
1786
1787    tr_cacheFree (session->cache);
1788    session->cache = NULL;
1789
1790    /* gotta keep udp running long enough to send out all
1791       the &event=stopped UDP tracker messages */
1792    while (!tr_tracker_udp_is_idle (session)) {
1793        tr_tracker_udp_upkeep (session);
1794        tr_wait_msec (100);
1795    }
1796
1797    /* we had to wait until UDP trackers were closed before closing these: */
1798    evdns_base_free (session->evdns_base, 0);
1799    session->evdns_base = NULL;
1800    tr_tracker_udp_close (session);
1801    tr_udpUninit (session);
1802
1803    tr_statsClose (session);
1804    tr_peerMgrFree (session->peerMgr);
1805
1806    closeBlocklists (session);
1807
1808    tr_fdClose (session);
1809
1810    session->isClosed = true;
1811}
1812
1813static int
1814deadlineReached (const time_t deadline)
1815{
1816    return time (NULL) >= deadline;
1817}
1818
1819#define SHUTDOWN_MAX_SECONDS 20
1820
1821void
1822tr_sessionClose (tr_session * session)
1823{
1824    const time_t deadline = time (NULL) + SHUTDOWN_MAX_SECONDS;
1825
1826    assert (tr_isSession (session));
1827
1828    dbgmsg ("shutting down transmission session %p... now is %zu, deadline is %zu", session, (size_t)time (NULL), (size_t)deadline);
1829
1830    /* close the session */
1831    tr_runInEventThread (session, sessionCloseImpl, session);
1832    while (!session->isClosed && !deadlineReached (deadline))
1833    {
1834        dbgmsg ("waiting for the libtransmission thread to finish");
1835        tr_wait_msec (100);
1836    }
1837
1838    /* "shared" and "tracker" have live sockets,
1839     * so we need to keep the transmission thread alive
1840     * for a bit while they tell the router & tracker
1841     * that we're closing now */
1842    while ((session->shared || session->web || session->announcer || session->announcer_udp)
1843           && !deadlineReached (deadline))
1844    {
1845        dbgmsg ("waiting on port unmap (%p) or announcer (%p)... now %zu deadline %zu",
1846                session->shared, session->announcer, (size_t)time (NULL), (size_t)deadline);
1847        tr_wait_msec (100);
1848    }
1849
1850    tr_webClose (session, TR_WEB_CLOSE_NOW);
1851
1852    /* close the libtransmission thread */
1853    tr_eventClose (session);
1854    while (session->events != NULL)
1855    {
1856        static bool forced = false;
1857        dbgmsg ("waiting for libtransmission thread to finish... now %zu deadline %zu", (size_t)time (NULL), (size_t)deadline);
1858        tr_wait_msec (500);
1859        if (deadlineReached (deadline) && !forced)
1860        {
1861            dbgmsg ("calling event_loopbreak ()");
1862            forced = true;
1863            event_base_loopbreak (session->event_base);
1864        }
1865        if (deadlineReached (deadline+3))
1866        {
1867            dbgmsg ("deadline+3 reached... calling break...\n");
1868            break;
1869        }
1870    }
1871
1872    /* free the session memory */
1873    tr_variantFree (&session->removedTorrents);
1874    tr_bandwidthDestruct (&session->bandwidth);
1875    tr_bitfieldDestruct (&session->turtle.minutes);
1876    tr_lockFree (session->lock);
1877    if (session->metainfoLookup) {
1878        tr_variantFree (session->metainfoLookup);
1879        tr_free (session->metainfoLookup);
1880    }
1881    tr_free (session->torrentDoneScript);
1882    tr_free (session->tag);
1883    tr_free (session->configDir);
1884    tr_free (session->resumeDir);
1885    tr_free (session->torrentDir);
1886    tr_free (session->downloadDir);
1887    tr_free (session->downloadDirBlkDev);
1888    tr_free (session->downloadDirFsType);
1889    tr_free (session->incompleteDir);
1890    tr_free (session->blocklist_url);
1891    tr_free (session->peer_congestion_algorithm);
1892    tr_free (session);
1893}
1894
1895struct sessionLoadTorrentsData
1896{
1897    tr_session * session;
1898    tr_ctor * ctor;
1899    int * setmeCount;
1900    tr_torrent ** torrents;
1901    bool done;
1902};
1903
1904static void
1905sessionLoadTorrents (void * vdata)
1906{
1907    int i;
1908    int n = 0;
1909    struct stat sb;
1910    DIR * odir = NULL;
1911    tr_list * l = NULL;
1912    tr_list * list = NULL;
1913    struct sessionLoadTorrentsData * data = vdata;
1914    const char * dirname = tr_getTorrentDir (data->session);
1915
1916    assert (tr_isSession (data->session));
1917
1918    tr_ctorSetSave (data->ctor, false); /* since we already have them */
1919
1920    if (!stat (dirname, &sb)
1921      && S_ISDIR (sb.st_mode)
1922      && ((odir = opendir (dirname))))
1923    {
1924        struct dirent *d;
1925        for (d = readdir (odir); d != NULL; d = readdir (odir))
1926        {
1927            if (tr_str_has_suffix (d->d_name, ".torrent"))
1928            {
1929                tr_torrent * tor;
1930                char * path = tr_buildPath (dirname, d->d_name, NULL);
1931                tr_ctorSetMetainfoFromFile (data->ctor, path);
1932                if ((tor = tr_torrentNew (data->ctor, NULL)))
1933                {
1934                    tr_list_prepend (&list, tor);
1935                    ++n;
1936                }
1937                tr_free (path);
1938            }
1939        }
1940        closedir (odir);
1941    }
1942
1943    data->torrents = tr_new (tr_torrent *, n);
1944    for (i = 0, l = list; l != NULL; l = l->next)
1945        data->torrents[i++] = (tr_torrent*) l->data;
1946    assert (i == n);
1947
1948    tr_list_free (&list, NULL);
1949
1950    if (n)
1951        tr_inf (_("Loaded %d torrents"), n);
1952
1953    if (data->setmeCount)
1954        *data->setmeCount = n;
1955
1956    data->done = true;
1957}
1958
1959tr_torrent **
1960tr_sessionLoadTorrents (tr_session * session,
1961                        tr_ctor    * ctor,
1962                        int        * setmeCount)
1963{
1964    struct sessionLoadTorrentsData data;
1965
1966    data.session = session;
1967    data.ctor = ctor;
1968    data.setmeCount = setmeCount;
1969    data.torrents = NULL;
1970    data.done = false;
1971
1972    tr_runInEventThread (session, sessionLoadTorrents, &data);
1973    while (!data.done)
1974        tr_wait_msec (100);
1975
1976    return data.torrents;
1977}
1978
1979/***
1980****
1981***/
1982
1983void
1984tr_sessionSetPexEnabled (tr_session * session, bool enabled)
1985{
1986    assert (tr_isSession (session));
1987
1988    session->isPexEnabled = enabled != 0;
1989}
1990
1991bool
1992tr_sessionIsPexEnabled (const tr_session * session)
1993{
1994    assert (tr_isSession (session));
1995
1996    return session->isPexEnabled;
1997}
1998
1999bool
2000tr_sessionAllowsDHT (const tr_session * session)
2001{
2002    return tr_sessionIsDHTEnabled (session);
2003}
2004
2005bool
2006tr_sessionIsDHTEnabled (const tr_session * session)
2007{
2008    assert (tr_isSession (session));
2009
2010    return session->isDHTEnabled;
2011}
2012
2013static void
2014toggleDHTImpl (void * data)
2015{
2016    tr_session * session = data;
2017    assert (tr_isSession (session));
2018
2019    tr_udpUninit (session);
2020    session->isDHTEnabled = !session->isDHTEnabled;
2021    tr_udpInit (session);
2022}
2023
2024void
2025tr_sessionSetDHTEnabled (tr_session * session, bool enabled)
2026{
2027    assert (tr_isSession (session));
2028    assert (tr_isBool (enabled));
2029
2030    if ((enabled != 0) != (session->isDHTEnabled != 0))
2031        tr_runInEventThread (session, toggleDHTImpl, session);
2032}
2033
2034/***
2035****
2036***/
2037
2038bool
2039tr_sessionIsUTPEnabled (const tr_session * session)
2040{
2041    assert (tr_isSession (session));
2042
2043#ifdef WITH_UTP
2044    return session->isUTPEnabled;
2045#else
2046    return false;
2047#endif
2048}
2049
2050static void
2051toggle_utp (void * data)
2052{
2053    tr_session * session = data;
2054    assert (tr_isSession (session));
2055
2056    session->isUTPEnabled = !session->isUTPEnabled;
2057
2058    tr_udpSetSocketBuffers (session);
2059
2060    /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
2061       explanation. */
2062}
2063
2064void
2065tr_sessionSetUTPEnabled (tr_session * session, bool enabled)
2066{
2067    assert (tr_isSession (session));
2068    assert (tr_isBool (enabled));
2069
2070    if ((enabled != 0) != (session->isUTPEnabled != 0))
2071        tr_runInEventThread (session, toggle_utp, session);
2072}
2073
2074/***
2075****
2076***/
2077
2078static void
2079toggleLPDImpl (void * data)
2080{
2081    tr_session * session = data;
2082    assert (tr_isSession (session));
2083
2084    if (session->isLPDEnabled)
2085        tr_lpdUninit (session);
2086
2087    session->isLPDEnabled = !session->isLPDEnabled;
2088
2089    if (session->isLPDEnabled)
2090        tr_lpdInit (session, &session->public_ipv4->addr);
2091}
2092
2093void
2094tr_sessionSetLPDEnabled (tr_session * session, bool enabled)
2095{
2096    assert (tr_isSession (session));
2097    assert (tr_isBool (enabled));
2098
2099    if ((enabled != 0) != (session->isLPDEnabled != 0))
2100        tr_runInEventThread (session, toggleLPDImpl, session);
2101}
2102
2103bool
2104tr_sessionIsLPDEnabled (const tr_session * session)
2105{
2106    assert (tr_isSession (session));
2107
2108    return session->isLPDEnabled;
2109}
2110
2111bool
2112tr_sessionAllowsLPD (const tr_session * session)
2113{
2114    return tr_sessionIsLPDEnabled (session);
2115}
2116
2117/***
2118****
2119***/
2120
2121void
2122tr_sessionSetCacheLimit_MB (tr_session * session, int max_bytes)
2123{
2124    assert (tr_isSession (session));
2125
2126    tr_cacheSetLimit (session->cache, toMemBytes (max_bytes));
2127}
2128
2129int
2130tr_sessionGetCacheLimit_MB (const tr_session * session)
2131{
2132    assert (tr_isSession (session));
2133
2134    return toMemMB (tr_cacheGetLimit (session->cache));
2135}
2136
2137/***
2138****
2139***/
2140
2141struct port_forwarding_data
2142{
2143    bool enabled;
2144    struct tr_shared * shared;
2145};
2146
2147static void
2148setPortForwardingEnabled (void * vdata)
2149{
2150    struct port_forwarding_data * data = vdata;
2151    tr_sharedTraversalEnable (data->shared, data->enabled);
2152    tr_free (data);
2153}
2154
2155void
2156tr_sessionSetPortForwardingEnabled (tr_session  * session, bool enabled)
2157{
2158    struct port_forwarding_data * d;
2159    d = tr_new0 (struct port_forwarding_data, 1);
2160    d->shared = session->shared;
2161    d->enabled = enabled;
2162    tr_runInEventThread (session, setPortForwardingEnabled, d);
2163}
2164
2165bool
2166tr_sessionIsPortForwardingEnabled (const tr_session * session)
2167{
2168    assert (tr_isSession (session));
2169
2170    return tr_sharedTraversalIsEnabled (session->shared);
2171}
2172
2173/***
2174****
2175***/
2176
2177static int
2178tr_stringEndsWith (const char * str, const char * end)
2179{
2180    const size_t slen = strlen (str);
2181    const size_t elen = strlen (end);
2182
2183    return slen >= elen && !memcmp (&str[slen - elen], end, elen);
2184}
2185
2186static void
2187loadBlocklists (tr_session * session)
2188{
2189    int         binCount = 0;
2190    int         newCount = 0;
2191    struct stat sb;
2192    char      * dirname;
2193    DIR *       odir = NULL;
2194    tr_list *   list = NULL;
2195    const bool  isEnabled = session->isBlocklistEnabled;
2196
2197    /* walk through the directory and find blocklists */
2198    dirname = tr_buildPath (session->configDir, "blocklists", NULL);
2199    if (!stat (dirname,
2200               &sb) && S_ISDIR (sb.st_mode)
2201      && ((odir = opendir (dirname))))
2202    {
2203        struct dirent *d;
2204        for (d = readdir (odir); d; d = readdir (odir))
2205        {
2206            char * filename;
2207
2208            if (!d->d_name || d->d_name[0] == '.') /* skip dotfiles, ., and ..
2209                                                      */
2210                continue;
2211
2212            filename = tr_buildPath (dirname, d->d_name, NULL);
2213
2214            if (tr_stringEndsWith (filename, ".bin"))
2215            {
2216                /* if we don't already have this blocklist, add it */
2217                if (!tr_list_find (list, filename,
2218                                 (TrListCompareFunc)strcmp))
2219                {
2220                    tr_list_append (&list,
2221                                   _tr_blocklistNew (filename, isEnabled));
2222                    ++binCount;
2223                }
2224            }
2225            else
2226            {
2227                /* strip out the file suffix, if there is one, and add ".bin"
2228                  instead */
2229                tr_blocklist * b;
2230                const char *   dot = strrchr (d->d_name, '.');
2231                const int      len = dot ? dot - d->d_name
2232                                         : (int)strlen (d->d_name);
2233                char         * tmp = tr_strdup_printf (
2234                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
2235                                        dirname, len, len, d->d_name);
2236                b = _tr_blocklistNew (tmp, isEnabled);
2237                _tr_blocklistSetContent (b, filename);
2238                tr_list_append (&list, b);
2239                ++newCount;
2240                tr_free (tmp);
2241            }
2242
2243            tr_free (filename);
2244        }
2245
2246        closedir (odir);
2247    }
2248
2249    session->blocklists = list;
2250
2251    if (binCount)
2252        tr_dbg ("Found %d blocklists in \"%s\"", binCount, dirname);
2253    if (newCount)
2254        tr_dbg ("Found %d new blocklists in \"%s\"", newCount, dirname);
2255
2256    tr_free (dirname);
2257}
2258
2259static void
2260closeBlocklists (tr_session * session)
2261{
2262    tr_list_free (&session->blocklists,
2263                (TrListForeachFunc)_tr_blocklistFree);
2264}
2265
2266void
2267tr_sessionReloadBlocklists (tr_session * session)
2268{
2269    closeBlocklists (session);
2270    loadBlocklists (session);
2271
2272    tr_peerMgrOnBlocklistChanged (session->peerMgr);
2273}
2274
2275int
2276tr_blocklistGetRuleCount (const tr_session * session)
2277{
2278    int       n = 0;
2279    tr_list * l;
2280
2281    assert (tr_isSession (session));
2282
2283    for (l = session->blocklists; l; l = l->next)
2284        n += _tr_blocklistGetRuleCount (l->data);
2285    return n;
2286}
2287
2288bool
2289tr_blocklistIsEnabled (const tr_session * session)
2290{
2291    assert (tr_isSession (session));
2292
2293    return session->isBlocklistEnabled;
2294}
2295
2296void
2297tr_blocklistSetEnabled (tr_session * session, bool isEnabled)
2298{
2299    tr_list * l;
2300
2301    assert (tr_isSession (session));
2302
2303    session->isBlocklistEnabled = isEnabled != 0;
2304
2305    for (l=session->blocklists; l!=NULL; l=l->next)
2306        _tr_blocklistSetEnabled (l->data, isEnabled);
2307}
2308
2309bool
2310tr_blocklistExists (const tr_session * session)
2311{
2312    assert (tr_isSession (session));
2313
2314    return session->blocklists != NULL;
2315}
2316
2317int
2318tr_blocklistSetContent (tr_session * session, const char * contentFilename)
2319{
2320    tr_list * l;
2321    int ruleCount;
2322    tr_blocklist * b;
2323    const char * defaultName = DEFAULT_BLOCKLIST_FILENAME;
2324    tr_sessionLock (session);
2325
2326    for (b = NULL, l = session->blocklists; !b && l; l = l->next)
2327        if (tr_stringEndsWith (_tr_blocklistGetFilename (l->data),
2328                               defaultName))
2329            b = l->data;
2330
2331    if (!b)
2332    {
2333        char * path = tr_buildPath (session->configDir, "blocklists", defaultName, NULL);
2334        b = _tr_blocklistNew (path, session->isBlocklistEnabled);
2335        tr_list_append (&session->blocklists, b);
2336        tr_free (path);
2337    }
2338
2339    ruleCount = _tr_blocklistSetContent (b, contentFilename);
2340    tr_sessionUnlock (session);
2341    return ruleCount;
2342}
2343
2344bool
2345tr_sessionIsAddressBlocked (const tr_session * session,
2346                            const tr_address * addr)
2347{
2348    tr_list * l;
2349
2350    assert (tr_isSession (session));
2351
2352    for (l = session->blocklists; l; l = l->next)
2353        if (_tr_blocklistHasAddress (l->data, addr))
2354            return true;
2355    return false;
2356}
2357
2358void
2359tr_blocklistSetURL (tr_session * session, const char * url)
2360{
2361    if (session->blocklist_url != url)
2362    {
2363        tr_free (session->blocklist_url);
2364        session->blocklist_url = tr_strdup (url);
2365    }
2366}
2367
2368const char *
2369tr_blocklistGetURL (const tr_session * session)
2370{
2371    return session->blocklist_url;
2372}
2373
2374
2375/***
2376****
2377***/
2378
2379static void
2380metainfoLookupInit (tr_session * session)
2381{
2382    struct stat  sb;
2383    const char * dirname = tr_getTorrentDir (session);
2384    DIR *        odir = NULL;
2385    tr_ctor *    ctor = NULL;
2386    tr_variant * lookup;
2387    int n = 0;
2388
2389    assert (tr_isSession (session));
2390
2391    /* walk through the directory and find the mappings */
2392    lookup = tr_new0 (tr_variant, 1);
2393    tr_variantInitDict (lookup, 0);
2394    ctor = tr_ctorNew (session);
2395    tr_ctorSetSave (ctor, false); /* since we already have them */
2396    if (!stat (dirname, &sb) && S_ISDIR (sb.st_mode) && ((odir = opendir (dirname))))
2397    {
2398        struct dirent *d;
2399        while ((d = readdir (odir)))
2400        {
2401            if (tr_str_has_suffix (d->d_name, ".torrent"))
2402            {
2403                tr_info inf;
2404                char * path = tr_buildPath (dirname, d->d_name, NULL);
2405                tr_ctorSetMetainfoFromFile (ctor, path);
2406                if (!tr_torrentParse (ctor, &inf))
2407                {
2408                    ++n;
2409                    tr_variantDictAddStr (lookup, tr_quark_new(inf.hashString,-1), path);
2410                }
2411                tr_free (path);
2412            }
2413        }
2414        closedir (odir);
2415    }
2416    tr_ctorFree (ctor);
2417
2418    session->metainfoLookup = lookup;
2419    tr_dbg ("Found %d torrents in \"%s\"", n, dirname);
2420}
2421
2422const char*
2423tr_sessionFindTorrentFile (const tr_session * session,
2424                           const char       * hashString)
2425{
2426    const char * filename = NULL;
2427    if (!session->metainfoLookup)
2428        metainfoLookupInit ((tr_session*)session);
2429    tr_variantDictFindStr (session->metainfoLookup, tr_quark_new(hashString,-1), &filename, NULL);
2430    return filename;
2431}
2432
2433void
2434tr_sessionSetTorrentFile (tr_session * session,
2435                          const char * hashString,
2436                          const char * filename)
2437{
2438    /* since we walk session->configDir/torrents/ to build the lookup table,
2439     * and tr_sessionSetTorrentFile () is just to tell us there's a new file
2440     * in that same directory, we don't need to do anything here if the
2441     * lookup table hasn't been built yet */
2442    if (session->metainfoLookup)
2443        tr_variantDictAddStr (session->metainfoLookup, tr_quark_new(hashString,-1), filename);
2444}
2445
2446/***
2447****
2448***/
2449
2450void
2451tr_sessionSetRPCEnabled (tr_session * session, bool isEnabled)
2452{
2453    assert (tr_isSession (session));
2454
2455    tr_rpcSetEnabled (session->rpcServer, isEnabled);
2456}
2457
2458bool
2459tr_sessionIsRPCEnabled (const tr_session * session)
2460{
2461    assert (tr_isSession (session));
2462
2463    return tr_rpcIsEnabled (session->rpcServer);
2464}
2465
2466void
2467tr_sessionSetRPCPort (tr_session * session,
2468                      tr_port      port)
2469{
2470    assert (tr_isSession (session));
2471
2472    tr_rpcSetPort (session->rpcServer, port);
2473}
2474
2475tr_port
2476tr_sessionGetRPCPort (const tr_session * session)
2477{
2478    assert (tr_isSession (session));
2479
2480    return tr_rpcGetPort (session->rpcServer);
2481}
2482
2483void
2484tr_sessionSetRPCUrl (tr_session * session,
2485                     const char * url)
2486{
2487    assert (tr_isSession (session));
2488
2489    tr_rpcSetUrl (session->rpcServer, url);
2490}
2491
2492const char*
2493tr_sessionGetRPCUrl (const tr_session * session)
2494{
2495    assert (tr_isSession (session));
2496
2497    return tr_rpcGetUrl (session->rpcServer);
2498}
2499
2500void
2501tr_sessionSetRPCCallback (tr_session * session,
2502                          tr_rpc_func  func,
2503                          void *       user_data)
2504{
2505    assert (tr_isSession (session));
2506
2507    session->rpc_func = func;
2508    session->rpc_func_user_data = user_data;
2509}
2510
2511void
2512tr_sessionSetRPCWhitelist (tr_session * session,
2513                           const char * whitelist)
2514{
2515    assert (tr_isSession (session));
2516
2517    tr_rpcSetWhitelist (session->rpcServer, whitelist);
2518}
2519
2520const char*
2521tr_sessionGetRPCWhitelist (const tr_session * session)
2522{
2523    assert (tr_isSession (session));
2524
2525    return tr_rpcGetWhitelist (session->rpcServer);
2526}
2527
2528void
2529tr_sessionSetRPCWhitelistEnabled (tr_session * session, bool isEnabled)
2530{
2531    assert (tr_isSession (session));
2532
2533    tr_rpcSetWhitelistEnabled (session->rpcServer, isEnabled);
2534}
2535
2536bool
2537tr_sessionGetRPCWhitelistEnabled (const tr_session * session)
2538{
2539    assert (tr_isSession (session));
2540
2541    return tr_rpcGetWhitelistEnabled (session->rpcServer);
2542}
2543
2544
2545void
2546tr_sessionSetRPCPassword (tr_session * session,
2547                          const char * password)
2548{
2549    assert (tr_isSession (session));
2550
2551    tr_rpcSetPassword (session->rpcServer, password);
2552}
2553
2554const char*
2555tr_sessionGetRPCPassword (const tr_session * session)
2556{
2557    assert (tr_isSession (session));
2558
2559    return tr_rpcGetPassword (session->rpcServer);
2560}
2561
2562void
2563tr_sessionSetRPCUsername (tr_session * session,
2564                          const char * username)
2565{
2566    assert (tr_isSession (session));
2567
2568    tr_rpcSetUsername (session->rpcServer, username);
2569}
2570
2571const char*
2572tr_sessionGetRPCUsername (const tr_session * session)
2573{
2574    assert (tr_isSession (session));
2575
2576    return tr_rpcGetUsername (session->rpcServer);
2577}
2578
2579void
2580tr_sessionSetRPCPasswordEnabled (tr_session * session, bool isEnabled)
2581{
2582    assert (tr_isSession (session));
2583
2584    tr_rpcSetPasswordEnabled (session->rpcServer, isEnabled);
2585}
2586
2587bool
2588tr_sessionIsRPCPasswordEnabled (const tr_session * session)
2589{
2590    assert (tr_isSession (session));
2591
2592    return tr_rpcIsPasswordEnabled (session->rpcServer);
2593}
2594
2595const char *
2596tr_sessionGetRPCBindAddress (const tr_session * session)
2597{
2598    assert (tr_isSession (session));
2599
2600    return tr_rpcGetBindAddress (session->rpcServer);
2601}
2602
2603/****
2604*****
2605****/
2606
2607bool
2608tr_sessionIsTorrentDoneScriptEnabled (const tr_session * session)
2609{
2610    assert (tr_isSession (session));
2611
2612    return session->isTorrentDoneScriptEnabled;
2613}
2614
2615void
2616tr_sessionSetTorrentDoneScriptEnabled (tr_session * session, bool isEnabled)
2617{
2618    assert (tr_isSession (session));
2619    assert (tr_isBool (isEnabled));
2620
2621    session->isTorrentDoneScriptEnabled = isEnabled;
2622}
2623
2624const char *
2625tr_sessionGetTorrentDoneScript (const tr_session * session)
2626{
2627    assert (tr_isSession (session));
2628
2629    return session->torrentDoneScript;
2630}
2631
2632void
2633tr_sessionSetTorrentDoneScript (tr_session * session, const char * scriptFilename)
2634{
2635    assert (tr_isSession (session));
2636
2637    if (session->torrentDoneScript != scriptFilename)
2638    {
2639        tr_free (session->torrentDoneScript);
2640        session->torrentDoneScript = tr_strdup (scriptFilename);
2641    }
2642}
2643
2644/***
2645****
2646***/
2647
2648void
2649tr_sessionSetQueueSize (tr_session * session, tr_direction dir, int n)
2650{
2651    assert (tr_isSession (session));
2652    assert (tr_isDirection (dir));
2653
2654    session->queueSize[dir] = n;
2655}
2656
2657int
2658tr_sessionGetQueueSize (const tr_session * session, tr_direction dir)
2659{
2660    assert (tr_isSession (session));
2661    assert (tr_isDirection (dir));
2662
2663    return session->queueSize[dir];
2664}
2665
2666void
2667tr_sessionSetQueueEnabled (tr_session * session, tr_direction dir, bool is_enabled)
2668{
2669    assert (tr_isSession (session));
2670    assert (tr_isDirection (dir));
2671    assert (tr_isBool (is_enabled));
2672
2673    session->queueEnabled[dir] = is_enabled;
2674}
2675
2676bool
2677tr_sessionGetQueueEnabled (const tr_session * session, tr_direction dir)
2678{
2679    assert (tr_isSession (session));
2680    assert (tr_isDirection (dir));
2681
2682    return session->queueEnabled[dir];
2683}
2684
2685void
2686tr_sessionSetQueueStalledMinutes (tr_session * session, int minutes)
2687{
2688    assert (tr_isSession (session));
2689    assert (minutes > 0);
2690
2691    session->queueStalledMinutes = minutes;
2692}
2693
2694void
2695tr_sessionSetQueueStalledEnabled (tr_session * session, bool is_enabled)
2696{
2697    assert (tr_isSession (session));
2698    assert (tr_isBool (is_enabled));
2699
2700    session->stalledEnabled = is_enabled;
2701}
2702
2703bool
2704tr_sessionGetQueueStalledEnabled (const tr_session * session)
2705{
2706    assert (tr_isSession (session));
2707
2708    return session->stalledEnabled;
2709}
2710
2711int
2712tr_sessionGetQueueStalledMinutes (const tr_session * session)
2713{
2714    assert (tr_isSession (session));
2715
2716    return session->queueStalledMinutes;
2717}
2718
2719tr_torrent *
2720tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction direction)
2721{
2722    tr_torrent * tor = NULL;
2723    tr_torrent * best_tor = NULL;
2724    int best_position = INT_MAX;
2725
2726    assert (tr_isSession (session));
2727    assert (tr_isDirection (direction));
2728
2729    while ((tor = tr_torrentNext (session, tor)))
2730    {
2731        int position;
2732
2733        if (!tr_torrentIsQueued (tor))
2734            continue;
2735        if (direction != tr_torrentGetQueueDirection (tor))
2736            continue;
2737
2738        position = tr_torrentGetQueuePosition (tor);
2739        if (best_position > position) {
2740            best_position = position;
2741            best_tor = tor;
2742        }
2743    }
2744
2745    return best_tor;
2746}
2747
2748int
2749tr_sessionCountQueueFreeSlots (tr_session * session, tr_direction dir)
2750{
2751    tr_torrent * tor;
2752    int active_count;
2753    const int max = tr_sessionGetQueueSize (session, dir);
2754    const tr_torrent_activity activity = dir == TR_UP ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
2755
2756    if (!tr_sessionGetQueueEnabled (session, dir))
2757        return INT_MAX;
2758
2759    tor = NULL;
2760    active_count = 0;
2761    while ((tor = tr_torrentNext (session, tor)))
2762        if (!tr_torrentIsStalled (tor))
2763            if (tr_torrentGetActivity (tor) == activity)
2764                ++active_count;
2765
2766    if (active_count >= max)
2767        return 0;
2768
2769    return max - active_count;
2770}
Note: See TracBrowser for help on using the repository browser.