source: trunk/libtransmission/session.c @ 13631

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

(trunk, libT) #5165: fix r13625 oops

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