source: trunk/libtransmission/session.c @ 8108

Last change on this file since 8108 was 8108, checked in by charles, 13 years ago

(trunk) use tr_bencDict{Find,Add}Bool() where appropriate

  • Property svn:keywords set to Date Rev Author Id
File size: 53.5 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.com>
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 8108 2009-03-29 23:05:32Z charles $
11 */
12
13#include <assert.h>
14#include <stdlib.h>
15#include <string.h> /* memcpy */
16
17#include <signal.h>
18#include <sys/types.h> /* stat */
19#include <sys/stat.h> /* stat */
20#include <unistd.h> /* stat */
21#include <dirent.h> /* opendir */
22
23#include <event.h>
24
25#include "transmission.h"
26#include "session.h"
27#include "bandwidth.h"
28#include "bencode.h"
29#include "blocklist.h"
30#include "fdlimit.h"
31#include "list.h"
32#include "metainfo.h" /* tr_metainfoFree */
33#include "net.h"
34#include "peer-mgr.h"
35#include "platform.h" /* tr_lock */
36#include "port-forwarding.h"
37#include "rpc-server.h"
38#include "stats.h"
39#include "torrent.h"
40#include "tracker.h"
41#include "trevent.h"
42#include "utils.h"
43#include "web.h"
44#include "crypto.h"
45
46#define dbgmsg( ... ) \
47    do { \
48        if( tr_deepLoggingIsActive( ) ) \
49            tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
50    } while( 0 )
51
52static tr_port
53getRandomPort( tr_session * s )
54{
55    return tr_cryptoWeakRandInt( s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow;
56}
57
58/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
59   characters, where x is the major version number, y is the
60   minor version number, z is the maintenance number, and b
61   designates beta (Azureus-style) */
62uint8_t*
63tr_peerIdNew( void )
64{
65    int          i;
66    int          val;
67    int          total = 0;
68    uint8_t *    buf = tr_new( uint8_t, 21 );
69    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
70    const int    base = 36;
71
72    memcpy( buf, PEERID_PREFIX, 8 );
73
74    for( i = 8; i < 19; ++i )
75    {
76        val = tr_cryptoRandInt( base );
77        total += val;
78        buf[i] = pool[val];
79    }
80
81    val = total % base ? base - ( total % base ) : 0;
82    buf[19] = pool[val];
83    buf[20] = '\0';
84
85    return buf;
86}
87
88const uint8_t*
89tr_getPeerId( void )
90{
91    static uint8_t * id = NULL;
92
93    if( id == NULL )
94        id = tr_peerIdNew( );
95    return id;
96}
97
98/***
99****
100***/
101
102tr_encryption_mode
103tr_sessionGetEncryption( tr_session * session )
104{
105    assert( session );
106
107    return session->encryptionMode;
108}
109
110void
111tr_sessionSetEncryption( tr_session *       session,
112                         tr_encryption_mode mode )
113{
114    assert( session );
115    assert( mode == TR_ENCRYPTION_PREFERRED
116          || mode == TR_ENCRYPTION_REQUIRED
117          || mode == TR_CLEAR_PREFERRED );
118
119    session->encryptionMode = mode;
120}
121
122/***
123****
124***/
125
126static int
127tr_stringEndsWith( const char * str,
128                   const char * end )
129{
130    const size_t slen = strlen( str );
131    const size_t elen = strlen( end );
132
133    return slen >= elen && !memcmp( &str[slen - elen], end, elen );
134}
135
136static void
137loadBlocklists( tr_session * session )
138{
139    int         binCount = 0;
140    int         newCount = 0;
141    struct stat sb;
142    char      * dirname;
143    DIR *       odir = NULL;
144    tr_list *   list = NULL;
145    const tr_bool   isEnabled = session->isBlocklistEnabled;
146
147    /* walk through the directory and find blocklists */
148    dirname = tr_buildPath( session->configDir, "blocklists", NULL );
149    if( !stat( dirname,
150               &sb ) && S_ISDIR( sb.st_mode )
151      && ( ( odir = opendir( dirname ) ) ) )
152    {
153        struct dirent *d;
154        for( d = readdir( odir ); d; d = readdir( odir ) )
155        {
156            char * filename;
157
158            if( !d->d_name || d->d_name[0] == '.' ) /* skip dotfiles, ., and ..
159                                                      */
160                continue;
161
162            filename = tr_buildPath( dirname, d->d_name, NULL );
163
164            if( tr_stringEndsWith( filename, ".bin" ) )
165            {
166                /* if we don't already have this blocklist, add it */
167                if( !tr_list_find( list, filename,
168                                   (TrListCompareFunc)strcmp ) )
169                {
170                    tr_list_append( &list,
171                                   _tr_blocklistNew( filename, isEnabled ) );
172                    ++binCount;
173                }
174            }
175            else
176            {
177                /* strip out the file suffix, if there is one, and add ".bin"
178                  instead */
179                tr_blocklist * b;
180                const char *   dot = strrchr( d->d_name, '.' );
181                const int      len = dot ? dot - d->d_name
182                                         : (int)strlen( d->d_name );
183                char         * tmp = tr_strdup_printf(
184                                        "%s" TR_PATH_DELIMITER_STR "%*.*s.bin",
185                                        dirname, len, len, d->d_name );
186                b = _tr_blocklistNew( tmp, isEnabled );
187                _tr_blocklistSetContent( b, filename );
188                tr_list_append( &list, b );
189                ++newCount;
190                tr_free( tmp );
191            }
192
193            tr_free( filename );
194        }
195
196        closedir( odir );
197    }
198
199    session->blocklists = list;
200
201    if( binCount )
202        tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
203    if( newCount )
204        tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
205
206    tr_free( dirname );
207}
208
209static tr_bool
210isAltTime( const tr_session * s )
211{
212    tr_bool is;
213    int minutes;
214    struct tm tm;
215    const time_t now = time( NULL );
216    const int begin = s->altSpeedTimeBegin;
217    const int end = s->altSpeedTimeEnd;
218
219    tr_localtime_r( &now, &tm );
220    minutes = tm.tm_hour*60 + tm.tm_min;
221
222    if( begin <= end )
223        is = ( begin <= minutes ) && ( minutes < end );
224    else /* goes past midnight */
225        is = ( begin <= minutes ) || ( minutes < end );
226
227    return is;
228}
229
230/***
231****
232***/
233
234#ifdef TR_EMBEDDED
235 #define TR_DEFAULT_ENCRYPTION   TR_CLEAR_PREFERRED
236#else
237 #define TR_DEFAULT_ENCRYPTION   TR_ENCRYPTION_PREFERRED
238#endif
239
240void
241tr_sessionGetDefaultSettings( tr_benc * d )
242{
243    assert( tr_bencIsDict( d ) );
244
245    tr_bencDictReserve( d, 35 );
246    tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        FALSE );
247    tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR,             tr_getDefaultDownloadDir( ) );
248    tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED,                   100 );
249    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           FALSE );
250    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               TR_DEFAULT_ENCRYPTION );
251    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
252    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
253    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
254    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
255    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       atoi( TR_DEFAULT_PEER_LIMIT_TORRENT_STR ) );
256    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT,                atoi( TR_DEFAULT_PEER_PORT_STR ) );
257    tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, FALSE );
258    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     1024 );
259    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    65535 );
260    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          atoi( TR_DEFAULT_PEER_SOCKET_TOS_STR ) );
261    tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED,              TRUE );
262    tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING,          TRUE );
263    tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION,            TR_PREALLOCATE_SPARSE );
264    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY,                    "" );
265    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       FALSE );
266    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_ENABLED,            FALSE );
267    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_PASSWORD,           "" );
268    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_PORT,               80 );
269    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_TYPE,               TR_PROXY_HTTP );
270    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_USERNAME,           "" );
271    tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO,                    2.0 );
272    tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED,            FALSE );
273    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        FALSE );
274    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED,              TRUE );
275    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD,             "" );
276    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME,             "" );
277    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST,            TR_DEFAULT_RPC_WHITELIST );
278    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    TRUE );
279    tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT,                 atoi( TR_DEFAULT_RPC_PORT_STR ) );
280    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED,        FALSE );
281    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP,             50 ); /* half the regular */
282    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN,           50 ); /* half the regular */
283    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN,     540 ); /* 9am */
284    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED,   FALSE );
285    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END,       1020 ); /* 5pm */
286    tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED,                   100 );
287    tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED,           FALSE );
288    tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 );
289}
290
291void
292tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
293{
294    int i, n=0;
295    char * freeme[16];
296
297    assert( tr_bencIsDict( d ) );
298
299    tr_bencDictReserve( d, 30 );
300    tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED,        tr_blocklistIsEnabled( s ) );
301    tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR,             s->downloadDir );
302    tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED,                   tr_sessionGetSpeedLimit( s, TR_DOWN ) );
303    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_DOWN ) );
304    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               s->encryptionMode );
305    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
306    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
307    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          s->openFileLimit );
308    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        tr_sessionGetPeerLimit( s ) );
309    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_TORRENT,       s->peerLimitPerTorrent );
310    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT,                tr_sessionGetPeerPort( s ) );
311    tr_bencDictAddBool( d, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, s->isPortRandom );
312    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW,     s->randomPortLow );
313    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH,    s->randomPortHigh );
314    tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_SOCKET_TOS,          s->peerSocketTOS );
315    tr_bencDictAddBool( d, TR_PREFS_KEY_PEX_ENABLED,              s->isPexEnabled );
316    tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING,          tr_sessionIsPortForwardingEnabled( s ) );
317    tr_bencDictAddInt ( d, TR_PREFS_KEY_PREALLOCATION,            s->preallocationMode );
318    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY,                    s->proxy );
319    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_AUTH_ENABLED,       s->isProxyAuthEnabled );
320    tr_bencDictAddBool( d, TR_PREFS_KEY_PROXY_ENABLED,            s->isProxyEnabled );
321    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_PASSWORD,           s->proxyPassword );
322    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_PORT,               s->proxyPort );
323    tr_bencDictAddInt ( d, TR_PREFS_KEY_PROXY_TYPE,               s->proxyType );
324    tr_bencDictAddStr ( d, TR_PREFS_KEY_PROXY_USERNAME,           s->proxyUsername );
325    tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO,                    s->desiredRatio );
326    tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED,            s->isRatioLimited );
327    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED,        tr_sessionIsRPCPasswordEnabled( s ) );
328    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED,              tr_sessionIsRPCEnabled( s ) );
329    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD,             freeme[n++] = tr_sessionGetRPCPassword( s ) );
330    tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT,                 tr_sessionGetRPCPort( s ) );
331    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME,             freeme[n++] = tr_sessionGetRPCUsername( s ) );
332    tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST,            freeme[n++] = tr_sessionGetRPCWhitelist( s ) );
333    tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,    tr_sessionGetRPCWhitelistEnabled( s ) );
334    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED,        tr_sessionUsesAltSpeed( s ) );
335    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP,             tr_sessionGetAltSpeed( s, TR_UP ) );
336    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN,           tr_sessionGetAltSpeed( s, TR_DOWN ) );
337    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN,     tr_sessionGetAltSpeedBegin( s ) );
338    tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED,   tr_sessionUsesAltSpeedTime( s ) );
339    tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_END,       tr_sessionGetAltSpeedEnd( s ) );
340    tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED,                   tr_sessionGetSpeedLimit( s, TR_UP ) );
341    tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_UP ) );
342    tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
343
344    for( i=0; i<n; ++i )
345        tr_free( freeme[i] );
346}
347
348void
349tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName )
350{
351    char * filename;
352    tr_benc fileSettings;
353    tr_benc sessionDefaults;
354    tr_benc tmp;
355
356    assert( tr_bencIsDict( d ) );
357
358    /* initializing the defaults: caller may have passed in some app-level defaults.
359     * preserve those and use the session defaults to fill in any missing gaps. */
360    tr_bencInitDict( &sessionDefaults, 0 );
361    tr_sessionGetDefaultSettings( &sessionDefaults );
362    tr_bencMergeDicts( &sessionDefaults, d );
363    tmp = *d; *d = sessionDefaults; sessionDefaults = tmp;
364
365    /* if caller didn't specify a config dir, use the default */
366    if( !configDir || !*configDir )
367        configDir = tr_getDefaultConfigDir( appName );
368
369    /* file settings override the defaults */
370    filename = tr_buildPath( configDir, "settings.json", NULL );
371    if( !tr_bencLoadJSONFile( filename, &fileSettings ) ) {
372        tr_bencMergeDicts( d, &fileSettings );
373        tr_bencFree( &fileSettings );
374    }
375
376    /* cleanup */
377    tr_bencFree( &sessionDefaults );
378    tr_free( filename );
379}
380
381void
382tr_sessionSaveSettings( tr_session    * session,
383                        const char    * configDir,
384                        const tr_benc * clientSettings )
385{
386    tr_benc settings;
387    char * filename = tr_buildPath( configDir, "settings.json", NULL );
388
389    assert( tr_bencIsDict( clientSettings ) );
390
391    tr_bencInitDict( &settings, 0 );
392
393    /* the existing file settings are the fallback values */
394    {
395        tr_benc fileSettings;
396        if( !tr_bencLoadJSONFile( filename, &fileSettings ) )
397        {
398            tr_bencMergeDicts( &settings, &fileSettings );
399            tr_bencFree( &fileSettings );
400        }
401    }
402
403    /* the client's settings override the file settings */
404    tr_bencMergeDicts( &settings, clientSettings );
405
406    /* the session's true values override the file & client settings */
407    {
408        tr_benc sessionSettings;
409        tr_bencInitDict( &sessionSettings, 0 );
410        tr_sessionGetSettings( session, &sessionSettings );
411        tr_bencMergeDicts( &settings, &sessionSettings );
412        tr_bencFree( &sessionSettings );
413    }
414
415    /* save the result */
416    tr_bencSaveJSONFile( filename, &settings );
417    tr_inf( "Saved \"%s\"", filename );
418
419    /* cleanup */
420    tr_free( filename );
421    tr_bencFree( &settings );
422}
423
424static void metainfoLookupRescan( tr_session * );
425static void tr_sessionInitImpl( void * );
426static void onAltTimer( int, short, void* );
427static void setAltTimer( tr_session * session );
428
429struct init_data
430{
431    tr_session  * session;
432    const char  * configDir;
433    tr_bool       messageQueuingEnabled;
434    tr_benc     * clientSettings;
435};
436
437tr_session *
438tr_sessionInit( const char  * tag,
439                const char  * configDir,
440                tr_bool       messageQueuingEnabled,
441                tr_benc     * clientSettings )
442{
443    tr_session * session;
444    struct init_data data;
445
446    assert( tr_bencIsDict( clientSettings ) );
447
448    /* initialize the bare skeleton of the session object */
449    session = tr_new0( tr_session, 1 );
450    session->bandwidth = tr_bandwidthNew( session, NULL );
451    session->lock = tr_lockNew( );
452    session->tag = tr_strdup( tag );
453    session->magicNumber = SESSION_MAGIC_NUMBER;
454
455    /* start the libtransmission thread */
456    tr_netInit( ); /* must go before tr_eventInit */
457    tr_eventInit( session );
458    assert( session->events != NULL );
459
460    /* run the rest in the libtransmission thread */
461    session->isWaiting = TRUE;
462    data.session = session;
463    data.configDir = configDir;
464    data.messageQueuingEnabled = messageQueuingEnabled;
465    data.clientSettings = clientSettings;
466    tr_runInEventThread( session, tr_sessionInitImpl, &data );
467    while( session->isWaiting )
468        tr_wait( 100 );
469
470    return session;
471}
472
473static void
474tr_sessionInitImpl( void * vdata )
475{
476    int64_t i;
477    int64_t j;
478    double  d;
479    tr_bool useAltSpeedTime;
480    tr_bool found;
481    tr_bool boolVal;
482    const char * str;
483    tr_benc settings;
484    char * filename;
485    struct init_data * data = vdata;
486    tr_benc * clientSettings = data->clientSettings;
487    tr_session * session = data->session;
488
489    assert( tr_amInEventThread( session ) );
490    assert( tr_bencIsDict( clientSettings ) );
491
492    dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth );
493
494    tr_bencInitDict( &settings, 0 );
495    tr_sessionGetDefaultSettings( &settings );
496    tr_bencMergeDicts( &settings, clientSettings );
497
498#ifndef WIN32
499    /* Don't exit when writing on a broken socket */
500    signal( SIGPIPE, SIG_IGN );
501#endif
502
503    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i );
504    assert( found );
505    session->peerLimitPerTorrent = i;
506
507    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i );
508    assert( found );
509    tr_setMessageLevel( i );
510    tr_setMessageQueuing( data->messageQueuingEnabled );
511
512
513    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal );
514    assert( found );
515    session->isPexEnabled = boolVal;
516
517    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i );
518    assert( found );
519    assert( tr_isEncryptionMode( i ) );
520    session->encryptionMode = i;
521
522    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i );
523    assert( found );
524    assert( tr_isPreallocationMode( i ) );
525    session->preallocationMode = i;
526
527    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i );
528    assert( found );
529    session->peerSocketTOS = i;
530
531    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str );
532    assert( found );
533    session->downloadDir = tr_strdup( str );
534
535    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_ENABLED, &boolVal );
536    assert( found );
537    session->isProxyEnabled = boolVal;
538
539    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str );
540    assert( found );
541    session->proxy = tr_strdup( str );
542
543    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i );
544    assert( found );
545    session->proxyPort = i;
546
547    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i );
548    assert( found );
549    session->proxyType = i;
550
551    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &boolVal );
552    assert( found );
553    session->isProxyAuthEnabled = boolVal;
554
555    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str );
556    assert( found );
557    session->proxyUsername = tr_strdup( str );
558
559    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str );
560    assert( found );
561    session->proxyPassword = tr_strdup( str );
562
563    session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */
564    session->so_rcvbuf = 8192;
565
566    tr_setConfigDir( session, data->configDir );
567
568    tr_trackerSessionInit( session );
569    assert( session->tracker != NULL );
570
571    session->peerMgr = tr_peerMgrNew( session );
572
573    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal );
574    assert( found );
575    session->useLazyBitfield = boolVal;
576
577    /* Initialize rate and file descripts controls */
578
579    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i );
580    assert( found );
581    session->openFileLimit = i;
582    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j );
583    assert( found );
584    tr_fdInit( session->openFileLimit, j );
585
586    /**
587    *** random port
588    **/
589
590    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &boolVal );
591    assert( found );
592    session->isPortRandom = boolVal;
593
594    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i );
595    assert( found );
596    session->randomPortLow = i;
597
598    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i );
599    assert( found );
600    session->randomPortHigh = i;
601
602    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, &boolVal )
603         && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j );
604    assert( found );
605    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
606    session->shared = tr_sharedInit( session, boolVal, session->peerPort );
607    session->isPortSet = session->isPortRandom || j>0;
608
609    /**
610    **/
611
612    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i );
613    assert( found );
614    session->uploadSlotsPerTorrent = i;
615
616    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i )
617         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_USPEED_ENABLED, &boolVal );
618    assert( found );
619    tr_sessionSetSpeedLimit( session, TR_UP, i );
620    tr_sessionLimitSpeed( session, TR_UP, boolVal );
621
622    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i )
623         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &boolVal );
624    assert( found );
625    tr_sessionSetSpeedLimit( session, TR_DOWN, i );
626    tr_sessionLimitSpeed( session, TR_DOWN, boolVal );
627
628    found = tr_bencDictFindReal( &settings, TR_PREFS_KEY_RATIO, &d )
629         && tr_bencDictFindBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, &boolVal );
630    assert( found );
631    tr_sessionSetRatioLimit( session, d );
632    tr_sessionSetRatioLimited( session, boolVal );
633
634    /**
635    ***  Alternate speed limits
636    **/
637
638    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_UP, &i );
639    assert( found );
640    session->altSpeed[TR_UP] = i;
641
642    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_DOWN, &i );
643    assert( found );
644    session->altSpeed[TR_DOWN] = i;
645
646    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN, &i );
647    assert( found );
648    session->altSpeedTimeBegin = i;
649
650    found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_END, &i );
651    assert( found );
652    session->altSpeedTimeEnd = i;
653
654    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, &boolVal );
655    assert( found );
656    useAltSpeedTime = boolVal;
657    tr_sessionUseAltSpeedTime( session, useAltSpeedTime );
658
659    if( !useAltSpeedTime )
660    {
661        found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_ALT_SPEED_ENABLED, &boolVal );
662        assert( found );
663        tr_sessionUseAltSpeed( session, boolVal );
664    }
665    else
666        tr_sessionUseAltSpeed( session, isAltTime( session ) );
667
668    /**
669    ***  Blocklist
670    **/
671
672    filename = tr_buildPath( session->configDir, "blocklists", NULL );
673    tr_mkdirp( filename, 0777 );
674    tr_free( filename );
675    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal );
676    assert( found );
677    session->isBlocklistEnabled = boolVal;
678    loadBlocklists( session );
679
680    session->rpcServer = tr_rpcInit( session, &settings );
681
682    tr_bencFree( &settings );
683
684    assert( tr_isSession( session ) );
685
686    session->altTimer = tr_new0( struct event, 1 );
687    evtimer_set( session->altTimer, onAltTimer, session );
688    setAltTimer( session );
689
690    /* first %s is the application name
691       second %s is the version number */
692    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
693
694    tr_statsInit( session );
695    session->web = tr_webInit( session );
696    metainfoLookupRescan( session );
697    session->isWaiting = FALSE;
698    dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker );
699}
700
701/***
702****
703***/
704
705void
706tr_sessionSetDownloadDir( tr_session * session, const char * dir )
707{
708    assert( tr_isSession( session ) );
709
710    if( session->downloadDir != dir )
711    {
712        tr_free( session->downloadDir );
713        session->downloadDir = tr_strdup( dir );
714    }
715}
716
717const char *
718tr_sessionGetDownloadDir( const tr_session * session )
719{
720    assert( tr_isSession( session ) );
721
722    return session->downloadDir;
723}
724
725/***
726****
727***/
728
729void
730tr_globalLock( tr_session * session )
731{
732    assert( tr_isSession( session ) );
733
734    tr_lockLock( session->lock );
735}
736
737void
738tr_globalUnlock( tr_session * session )
739{
740    assert( tr_isSession( session ) );
741
742    tr_lockUnlock( session->lock );
743}
744
745tr_bool
746tr_globalIsLocked( const tr_session * session )
747{
748    return tr_isSession( session ) && tr_lockHave( session->lock );
749}
750
751/***********************************************************************
752 * tr_setBindPort
753 ***********************************************************************
754 *
755 **********************************************************************/
756
757struct bind_port_data
758{
759    tr_session * session;
760    tr_port      port;
761};
762
763static void
764tr_setBindPortImpl( void * vdata )
765{
766    struct bind_port_data * data = vdata;
767    tr_session * session = data->session;
768    const tr_port port = data->port;
769
770    session->isPortSet = 1;
771    tr_sharedSetPort( session->shared, port );
772
773    tr_free( data );
774}
775
776static void
777setPortImpl( tr_session * session, tr_port port )
778{
779    struct bind_port_data * data;
780
781    assert( tr_isSession( session ) );
782
783    data = tr_new( struct bind_port_data, 1 );
784    data->session = session;
785    data->port = port;
786    tr_runInEventThread( session, tr_setBindPortImpl, data );
787}
788
789void
790tr_sessionSetPeerPort( tr_session * session,
791                       tr_port      port )
792{
793    assert( tr_isSession( session ) );
794
795    session->isPortRandom = FALSE;
796    session->peerPort = port;
797    setPortImpl( session, session->peerPort );
798}
799
800tr_port
801tr_sessionSetPeerPortRandom( tr_session * session )
802{
803    assert( tr_isSession( session ) );
804
805    session->isPortRandom = TRUE;
806    session->peerPort = getRandomPort( session );
807    setPortImpl( session, session->peerPort );
808    return session->peerPort;
809}
810
811tr_port
812tr_sessionGetPeerPort( const tr_session * session )
813{
814    assert( tr_isSession( session ) );
815
816    return session->peerPort;
817}
818
819tr_port_forwarding
820tr_sessionGetPortForwarding( const tr_session * session )
821{
822    assert( tr_isSession( session ) );
823
824    return tr_sharedTraversalStatus( session->shared );
825}
826
827/***
828****
829***/
830
831static void
832updateSeedRatio( tr_session * session )
833{
834    tr_torrent * tor = NULL;
835
836    while(( tor = tr_torrentNext( session, tor )))
837        tr_torrentCheckSeedRatio( tor );
838}
839
840void
841tr_sessionSetRatioLimited( tr_session * session, tr_bool isLimited )
842{
843    assert( tr_isSession( session ) );
844
845    session->isRatioLimited = isLimited;
846    updateSeedRatio( session );
847}
848
849void
850tr_sessionSetRatioLimit( tr_session * session, double desiredRatio )
851{
852    assert( tr_isSession( session ) );
853
854    session->desiredRatio = desiredRatio;
855    updateSeedRatio( session );
856}
857
858tr_bool
859tr_sessionIsRatioLimited( const tr_session  * session )
860{
861    assert( tr_isSession( session ) );
862
863    return session->isRatioLimited;
864}
865
866double
867tr_sessionGetRatioLimit( const tr_session * session )
868{
869    assert( tr_isSession( session ) );
870
871    return session->desiredRatio;
872}
873
874/***
875****  SPEED LIMITS
876***/
877
878tr_bool
879tr_sessionGetActiveSpeedLimit( const tr_session * session, tr_direction dir, int * setme )
880{
881    int isLimited = TRUE;
882
883    if( tr_sessionUsesAltSpeed( session ) )
884        *setme = tr_sessionGetAltSpeed( session, dir );
885    else if( tr_sessionIsSpeedLimited( session, dir ) )
886        *setme = tr_sessionGetSpeedLimit( session, dir );
887    else
888        isLimited = FALSE;
889
890    return isLimited;
891}
892
893static void
894updateBandwidth( tr_session * session, tr_direction dir )
895{
896    int limit;
897    const tr_bool isLimited = tr_sessionGetActiveSpeedLimit( session, dir, &limit );
898    const tr_bool zeroCase = isLimited && !limit;
899
900    tr_bandwidthSetLimited( session->bandwidth, dir, isLimited && !zeroCase );
901
902    tr_bandwidthSetDesiredSpeed( session->bandwidth, dir, limit );
903}
904
905static void
906altSpeedToggled( void * vsession )
907{
908    tr_session * session = vsession;
909
910    assert( tr_isSession( session ) );
911
912    updateBandwidth( session, TR_UP );
913    updateBandwidth( session, TR_DOWN );
914
915    if( session->altCallback != NULL )
916        (*session->altCallback)( session, session->altSpeedEnabled, session->altCallbackUserData );
917}
918
919/* tell the alt speed limit timer to fire again at the top of the minute */
920static void
921setAltTimer( tr_session * session )
922{
923    const time_t now = time( NULL );
924    struct tm tm;
925    struct timeval tv;
926
927    assert( tr_isSession( session ) );
928    assert( session->altTimer != NULL );
929
930    tr_localtime_r( &now, &tm );
931    tv.tv_sec = 60 - tm.tm_sec;
932    tv.tv_usec = 0;
933    evtimer_add( session->altTimer, &tv );
934}
935
936/* this is called once a minute to:
937 * (1) update session->isAltTime
938 * (2) alter the speed limits when the alt limits go on and off */
939static void
940onAltTimer( int foo UNUSED, short bar UNUSED, void * vsession )
941{
942    tr_session * session = vsession;
943
944    assert( tr_isSession( session ) );
945
946    if( session->altSpeedTimeEnabled )
947    {
948        const time_t now = time( NULL );
949        struct tm tm;
950        int currentMinute;
951        tr_localtime_r( &now, &tm );
952        currentMinute = tm.tm_hour*60 + tm.tm_min;
953
954        if( currentMinute == session->altSpeedTimeBegin )
955        {
956            tr_sessionUseAltSpeed( session, TRUE );
957        }
958        else if( currentMinute == session->altSpeedTimeEnd )
959        {
960            tr_sessionUseAltSpeed( session, FALSE );
961        }
962    }
963
964    setAltTimer( session );
965}
966
967/***
968****  Primary session speed limits
969***/
970
971void
972tr_sessionSetSpeedLimit( tr_session * s, tr_direction d, int KB_s )
973{
974    assert( tr_isSession( s ) );
975    assert( tr_isDirection( d ) );
976    assert( KB_s >= 0 );
977
978    s->speedLimit[d] = KB_s;
979
980    updateBandwidth( s, d );
981}
982
983int
984tr_sessionGetSpeedLimit( const tr_session * s, tr_direction d )
985{
986    assert( tr_isSession( s ) );
987    assert( tr_isDirection( d ) );
988
989    return s->speedLimit[d];
990}
991
992void
993tr_sessionLimitSpeed( tr_session * s, tr_direction d, tr_bool b )
994{
995    assert( tr_isSession( s ) );
996    assert( tr_isDirection( d ) );
997    assert( tr_isBool( b ) );
998
999    s->speedLimitEnabled[d] = b;
1000
1001    updateBandwidth( s, d );
1002}
1003
1004tr_bool
1005tr_sessionIsSpeedLimited( const tr_session * s, tr_direction d )
1006{
1007    assert( tr_isSession( s ) );
1008    assert( tr_isDirection( d ) );
1009
1010    return s->speedLimitEnabled[d];
1011}
1012
1013/***
1014****  Alternative speed limits that are used during scheduled times
1015***/
1016
1017void
1018tr_sessionSetAltSpeed( tr_session * s, tr_direction d, int KB_s )
1019{
1020    assert( tr_isSession( s ) );
1021    assert( tr_isDirection( d ) );
1022    assert( KB_s >= 0 );
1023
1024    s->altSpeed[d] = KB_s;
1025
1026    updateBandwidth( s, d );
1027}
1028
1029int
1030tr_sessionGetAltSpeed( const tr_session * s, tr_direction d )
1031{
1032    assert( tr_isSession( s ) );
1033    assert( tr_isDirection( d ) );
1034
1035    return s->altSpeed[d]; 
1036}
1037
1038void
1039tr_sessionUseAltSpeedTime( tr_session * s, tr_bool b )
1040{
1041    assert( tr_isSession( s ) );
1042    assert( tr_isBool( b ) );
1043
1044    if( s->altSpeedTimeEnabled != b )
1045    {
1046        const tr_bool isAlt = isAltTime( s );
1047
1048        s->altSpeedTimeEnabled = b;
1049
1050        if( b && s->altSpeedEnabled != isAlt )
1051            tr_sessionUseAltSpeed( s, isAlt );
1052    }
1053}
1054
1055tr_bool
1056tr_sessionUsesAltSpeedTime( const tr_session * s )
1057{
1058    assert( tr_isSession( s ) );
1059
1060    return s->altSpeedTimeEnabled;
1061}
1062
1063void
1064tr_sessionSetAltSpeedBegin( tr_session * s, int minutes )
1065{
1066    assert( tr_isSession( s ) );
1067    assert( 0<=minutes && minutes<(60*24) );
1068
1069    if( s->altSpeedTimeBegin != minutes )
1070    {
1071        s->altSpeedTimeBegin = minutes;
1072
1073        if( tr_sessionUsesAltSpeedTime( s ) )
1074            tr_sessionUseAltSpeed( s, isAltTime( s ) );
1075    }
1076}
1077
1078int
1079tr_sessionGetAltSpeedBegin( const tr_session * s )
1080{
1081    assert( tr_isSession( s ) );
1082
1083    return s->altSpeedTimeBegin;
1084}
1085
1086void
1087tr_sessionSetAltSpeedEnd( tr_session * s, int minutes )
1088{
1089    assert( tr_isSession( s ) );
1090    assert( 0<=minutes && minutes<(60*24) );
1091
1092    if( s->altSpeedTimeEnd != minutes )
1093    {
1094        s->altSpeedTimeEnd = minutes;
1095
1096        if( tr_sessionUsesAltSpeedTime( s ) )
1097            tr_sessionUseAltSpeed( s, isAltTime( s ) );
1098    }
1099}
1100
1101int
1102tr_sessionGetAltSpeedEnd( const tr_session * s )
1103{
1104    assert( tr_isSession( s ) );
1105
1106    return s->altSpeedTimeEnd;
1107}
1108
1109void
1110tr_sessionUseAltSpeed( tr_session * s, tr_bool b )
1111{
1112    assert( tr_isSession( s ) );
1113    assert( tr_isBool( b ) );
1114
1115    if( s->altSpeedEnabled != b)
1116    {
1117        s->altSpeedEnabled = b;
1118   
1119        tr_runInEventThread( s, altSpeedToggled, s );
1120    }
1121}
1122
1123tr_bool
1124tr_sessionUsesAltSpeed( const tr_session * s )
1125{
1126    assert( tr_isSession( s ) );
1127
1128    return s->altSpeedEnabled;
1129}
1130
1131void
1132tr_sessionSetAltSpeedFunc( tr_session       * session,
1133                           tr_altSpeedFunc    func,
1134                           void             * userData )
1135{
1136    assert( tr_isSession( session ) );
1137
1138    session->altCallback = func;
1139    session->altCallbackUserData = userData;
1140}
1141
1142void
1143tr_sessionClearAltSpeedFunc( tr_session * session )
1144{
1145    tr_sessionSetAltSpeedFunc( session, NULL, NULL );
1146}
1147
1148/***
1149****
1150***/
1151
1152void
1153tr_sessionSetPeerLimit( tr_session * session, uint16_t maxGlobalPeers )
1154{
1155    assert( tr_isSession( session ) );
1156
1157    tr_fdSetPeerLimit( maxGlobalPeers );
1158}
1159
1160uint16_t
1161tr_sessionGetPeerLimit( const tr_session * session )
1162{
1163    assert( tr_isSession( session ) );
1164
1165    return tr_fdGetPeerLimit( );
1166}
1167
1168void
1169tr_sessionSetPeerLimitPerTorrent( tr_session  * session, uint16_t n )
1170{
1171    assert( tr_isSession( session ) );
1172
1173    session->peerLimitPerTorrent = n;
1174}
1175
1176uint16_t
1177tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
1178{
1179    assert( tr_isSession( session ) );
1180
1181    return session->peerLimitPerTorrent;
1182}
1183
1184/***
1185****
1186***/
1187
1188double
1189tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
1190{
1191    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1192}
1193
1194double
1195tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
1196{
1197    return tr_isSession( session ) ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
1198}
1199
1200int
1201tr_sessionCountTorrents( const tr_session * session )
1202{
1203    return tr_isSession( session ) ? session->torrentCount : 0;
1204}
1205
1206static int
1207compareTorrentByCur( const void * va, const void * vb )
1208{
1209    const tr_torrent * a = *(const tr_torrent**)va;
1210    const tr_torrent * b = *(const tr_torrent**)vb;
1211    const uint64_t     aCur = a->downloadedCur + a->uploadedCur;
1212    const uint64_t     bCur = b->downloadedCur + b->uploadedCur;
1213
1214    if( aCur != bCur )
1215        return aCur > bCur ? -1 : 1; /* close the biggest torrents first */
1216
1217    return 0;
1218}
1219
1220static void
1221tr_closeAllConnections( void * vsession )
1222{
1223    tr_session *  session = vsession;
1224    tr_torrent *  tor;
1225    int           i, n;
1226    tr_torrent ** torrents;
1227
1228    assert( tr_isSession( session ) );
1229
1230    evtimer_del( session->altTimer );
1231    tr_free( session->altTimer );
1232    session->altTimer = NULL;
1233
1234    tr_statsClose( session );
1235    tr_sharedShuttingDown( session->shared );
1236    tr_rpcClose( &session->rpcServer );
1237
1238    /* close the torrents.  get the most active ones first so that
1239     * if we can't get them all closed in a reasonable amount of time,
1240     * at least we get the most important ones first. */
1241    tor = NULL;
1242    n = session->torrentCount;
1243    torrents = tr_new( tr_torrent *, session->torrentCount );
1244    for( i = 0; i < n; ++i )
1245        torrents[i] = tor = tr_torrentNext( session, tor );
1246    qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur );
1247    for( i = 0; i < n; ++i )
1248        tr_torrentFree( torrents[i] );
1249    tr_free( torrents );
1250
1251    tr_peerMgrFree( session->peerMgr );
1252
1253    tr_trackerSessionClose( session );
1254    tr_list_free( &session->blocklists,
1255                  (TrListForeachFunc)_tr_blocklistFree );
1256    tr_webClose( &session->web );
1257
1258    session->isClosed = TRUE;
1259}
1260
1261static int
1262deadlineReached( const uint64_t deadline )
1263{
1264    return tr_date( ) >= deadline;
1265}
1266
1267#define SHUTDOWN_MAX_SECONDS 30
1268
1269void
1270tr_sessionClose( tr_session * session )
1271{
1272    int            i;
1273    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
1274    const uint64_t deadline = tr_date( ) + maxwait_msec;
1275
1276    assert( tr_isSession( session ) );
1277
1278    dbgmsg( "shutting down transmission session %p", session );
1279
1280    /* close the session */
1281    tr_runInEventThread( session, tr_closeAllConnections, session );
1282    while( !session->isClosed && !deadlineReached( deadline ) )
1283    {
1284        dbgmsg(
1285            "waiting for the shutdown commands to run in the main thread" );
1286        tr_wait( 100 );
1287    }
1288
1289    /* "shared" and "tracker" have live sockets,
1290     * so we need to keep the transmission thread alive
1291     * for a bit while they tell the router & tracker
1292     * that we're closing now */
1293    while( ( session->shared
1294           || session->tracker ) && !deadlineReached( deadline ) )
1295    {
1296        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
1297                session->shared, session->tracker );
1298        tr_wait( 100 );
1299    }
1300
1301    tr_fdClose( );
1302
1303    /* close the libtransmission thread */
1304    tr_eventClose( session );
1305    while( session->events && !deadlineReached( deadline ) )
1306    {
1307        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
1308        tr_wait( 100 );
1309    }
1310
1311    /* free the session memory */
1312    tr_bandwidthFree( session->bandwidth );
1313    tr_lockFree( session->lock );
1314    for( i = 0; i < session->metainfoLookupCount; ++i )
1315        tr_free( session->metainfoLookup[i].filename );
1316    tr_free( session->metainfoLookup );
1317    tr_free( session->tag );
1318    tr_free( session->configDir );
1319    tr_free( session->resumeDir );
1320    tr_free( session->torrentDir );
1321    tr_free( session->downloadDir );
1322    tr_free( session->proxy );
1323    tr_free( session->proxyUsername );
1324    tr_free( session->proxyPassword );
1325    tr_free( session );
1326}
1327
1328tr_torrent **
1329tr_sessionLoadTorrents( tr_session * session,
1330                        tr_ctor    * ctor,
1331                        int        * setmeCount )
1332{
1333    int           i, n = 0;
1334    struct stat   sb;
1335    DIR *         odir = NULL;
1336    const char *  dirname = tr_getTorrentDir( session );
1337    tr_torrent ** torrents;
1338    tr_list *     l = NULL, *list = NULL;
1339
1340    assert( tr_isSession( session ) );
1341
1342    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1343
1344    if( !stat( dirname, &sb )
1345      && S_ISDIR( sb.st_mode )
1346      && ( ( odir = opendir ( dirname ) ) ) )
1347    {
1348        struct dirent *d;
1349        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1350        {
1351            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1352                                                     */
1353            {
1354                tr_torrent * tor;
1355                char * path = tr_buildPath( dirname, d->d_name, NULL );
1356                tr_ctorSetMetainfoFromFile( ctor, path );
1357                if(( tor = tr_torrentNew( session, ctor, NULL )))
1358                {
1359                    tr_list_append( &list, tor );
1360                    ++n;
1361                }
1362                tr_free( path );
1363            }
1364        }
1365        closedir( odir );
1366    }
1367
1368    torrents = tr_new( tr_torrent *, n );
1369    for( i = 0, l = list; l != NULL; l = l->next )
1370        torrents[i++] = (tr_torrent*) l->data;
1371    assert( i == n );
1372
1373    tr_list_free( &list, NULL );
1374
1375    if( n )
1376        tr_inf( _( "Loaded %d torrents" ), n );
1377
1378    if( setmeCount )
1379        *setmeCount = n;
1380    return torrents;
1381}
1382
1383/***
1384****
1385***/
1386
1387void
1388tr_sessionSetPexEnabled( tr_session * session,
1389                         tr_bool      enabled )
1390{
1391    assert( tr_isSession( session ) );
1392
1393    session->isPexEnabled = enabled != 0;
1394}
1395
1396tr_bool
1397tr_sessionIsPexEnabled( const tr_session * session )
1398{
1399    assert( tr_isSession( session ) );
1400
1401    return session->isPexEnabled;
1402}
1403
1404/***
1405****
1406***/
1407
1408void
1409tr_sessionSetLazyBitfieldEnabled( tr_session * session,
1410                                  tr_bool      enabled )
1411{
1412    assert( tr_isSession( session ) );
1413
1414    session->useLazyBitfield = enabled != 0;
1415}
1416
1417tr_bool
1418tr_sessionIsLazyBitfieldEnabled( const tr_session * session )
1419{
1420    assert( tr_isSession( session ) );
1421
1422    return session->useLazyBitfield;
1423}
1424
1425/***
1426****
1427***/
1428
1429void
1430tr_sessionSetPortForwardingEnabled( tr_session  * session,
1431                                    tr_bool       enabled )
1432{
1433    assert( tr_isSession( session ) );
1434
1435    tr_globalLock( session );
1436    tr_sharedTraversalEnable( session->shared, enabled );
1437    tr_globalUnlock( session );
1438}
1439
1440tr_bool
1441tr_sessionIsPortForwardingEnabled( const tr_session * session )
1442{
1443    assert( tr_isSession( session ) );
1444
1445    return tr_sharedTraversalIsEnabled( session->shared );
1446}
1447
1448/***
1449****
1450***/
1451
1452int
1453tr_blocklistGetRuleCount( const tr_session * session )
1454{
1455    int       n = 0;
1456    tr_list * l;
1457
1458    assert( tr_isSession( session ) );
1459
1460    for( l = session->blocklists; l; l = l->next )
1461        n += _tr_blocklistGetRuleCount( l->data );
1462    return n;
1463}
1464
1465tr_bool
1466tr_blocklistIsEnabled( const tr_session * session )
1467{
1468    assert( tr_isSession( session ) );
1469
1470    return session->isBlocklistEnabled;
1471}
1472
1473void
1474tr_blocklistSetEnabled( tr_session * session,
1475                        tr_bool      isEnabled )
1476{
1477    tr_list * l;
1478
1479    assert( tr_isSession( session ) );
1480
1481    session->isBlocklistEnabled = isEnabled != 0;
1482
1483    for( l=session->blocklists; l!=NULL; l=l->next )
1484        _tr_blocklistSetEnabled( l->data, isEnabled );
1485}
1486
1487tr_bool
1488tr_blocklistExists( const tr_session * session )
1489{
1490    assert( tr_isSession( session ) );
1491
1492    return session->blocklists != NULL;
1493}
1494
1495int
1496tr_blocklistSetContent( tr_session * session,
1497                        const char * contentFilename )
1498{
1499    tr_list *      l;
1500    tr_blocklist * b;
1501    const char *   defaultName = "level1.bin";
1502
1503    assert( tr_isSession( session ) );
1504
1505    for( b = NULL, l = session->blocklists; !b && l; l = l->next )
1506        if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ),
1507                               defaultName ) )
1508            b = l->data;
1509
1510    if( !b )
1511    {
1512        char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL );
1513        b = _tr_blocklistNew( path, session->isBlocklistEnabled );
1514        tr_list_append( &session->blocklists, b );
1515        tr_free( path );
1516    }
1517
1518    return _tr_blocklistSetContent( b, contentFilename );
1519}
1520
1521tr_bool
1522tr_sessionIsAddressBlocked( const tr_session * session,
1523                            const tr_address * addr )
1524{
1525    tr_list * l;
1526
1527    assert( tr_isSession( session ) );
1528
1529    for( l = session->blocklists; l; l = l->next )
1530        if( _tr_blocklistHasAddress( l->data, addr ) )
1531            return TRUE;
1532    return FALSE;
1533}
1534
1535/***
1536****
1537***/
1538
1539static int
1540compareLookupEntries( const void * va, const void * vb )
1541{
1542    const struct tr_metainfo_lookup * a = va;
1543    const struct tr_metainfo_lookup * b = vb;
1544
1545    return strcmp( a->hashString, b->hashString );
1546}
1547
1548static void
1549metainfoLookupResort( tr_session * session )
1550{
1551    assert( tr_isSession( session ) );
1552
1553    qsort( session->metainfoLookup,
1554           session->metainfoLookupCount,
1555           sizeof( struct tr_metainfo_lookup ),
1556           compareLookupEntries );
1557}
1558
1559static int
1560compareHashStringToLookupEntry( const void * va, const void * vb )
1561{
1562    const char *                      a = va;
1563    const struct tr_metainfo_lookup * b = vb;
1564
1565    return strcmp( a, b->hashString );
1566}
1567
1568const char*
1569tr_sessionFindTorrentFile( const tr_session * session,
1570                           const char       * hashStr )
1571{
1572    struct tr_metainfo_lookup * l = bsearch( hashStr,
1573                                             session->metainfoLookup,
1574                                             session->metainfoLookupCount,
1575                                             sizeof( struct tr_metainfo_lookup ),
1576                                             compareHashStringToLookupEntry );
1577
1578    return l ? l->filename : NULL;
1579}
1580
1581static void
1582metainfoLookupRescan( tr_session * session )
1583{
1584    int          i;
1585    int          n;
1586    struct stat  sb;
1587    const char * dirname = tr_getTorrentDir( session );
1588    DIR *        odir = NULL;
1589    tr_ctor *    ctor = NULL;
1590    tr_list *    list = NULL;
1591
1592    assert( tr_isSession( session ) );
1593
1594    /* walk through the directory and find the mappings */
1595    ctor = tr_ctorNew( session );
1596    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
1597    if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) )
1598    {
1599        struct dirent *d;
1600        for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
1601        {
1602            if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and ..
1603                                                     */
1604            {
1605                tr_info inf;
1606                char * path = tr_buildPath( dirname, d->d_name, NULL );
1607                tr_ctorSetMetainfoFromFile( ctor, path );
1608                if( !tr_torrentParse( session, ctor, &inf ) )
1609                {
1610                    tr_list_append( &list, tr_strdup( inf.hashString ) );
1611                    tr_list_append( &list, tr_strdup( path ) );
1612                    tr_metainfoFree( &inf );
1613                }
1614                tr_free( path );
1615            }
1616        }
1617        closedir( odir );
1618    }
1619    tr_ctorFree( ctor );
1620
1621    n = tr_list_size( list ) / 2;
1622    session->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n );
1623    session->metainfoLookupCount = n;
1624    for( i = 0; i < n; ++i )
1625    {
1626        char * hashString = tr_list_pop_front( &list );
1627        char * filename = tr_list_pop_front( &list );
1628
1629        memcpy( session->metainfoLookup[i].hashString, hashString,
1630                2 * SHA_DIGEST_LENGTH + 1 );
1631        tr_free( hashString );
1632        session->metainfoLookup[i].filename = filename;
1633    }
1634
1635    metainfoLookupResort( session );
1636    tr_dbg( "Found %d torrents in \"%s\"", n, dirname );
1637}
1638
1639void
1640tr_sessionSetTorrentFile( tr_session * session,
1641                          const char * hashString,
1642                          const char * filename )
1643{
1644    struct tr_metainfo_lookup * l = bsearch( hashString,
1645                                             session->metainfoLookup,
1646                                             session->metainfoLookupCount,
1647                                             sizeof( struct tr_metainfo_lookup ),
1648                                             compareHashStringToLookupEntry );
1649
1650    if( l )
1651    {
1652        if( l->filename != filename )
1653        {
1654            tr_free( l->filename );
1655            l->filename = tr_strdup( filename );
1656        }
1657    }
1658    else
1659    {
1660        const int n = session->metainfoLookupCount++;
1661        struct tr_metainfo_lookup * node;
1662        session->metainfoLookup = tr_renew( struct tr_metainfo_lookup,
1663                                            session->metainfoLookup,
1664                                            session->metainfoLookupCount );
1665        node = session->metainfoLookup + n;
1666        memcpy( node->hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 );
1667        node->filename = tr_strdup( filename );
1668        metainfoLookupResort( session );
1669    }
1670}
1671
1672tr_torrent*
1673tr_torrentNext( tr_session * session,
1674                tr_torrent * tor )
1675{
1676    assert( tr_isSession( session ) );
1677
1678    return tor ? tor->next : session->torrentList;
1679}
1680
1681/***
1682****
1683***/
1684
1685void
1686tr_sessionSetRPCEnabled( tr_session * session,
1687                         tr_bool      isEnabled )
1688{
1689    assert( tr_isSession( session ) );
1690
1691    tr_rpcSetEnabled( session->rpcServer, isEnabled );
1692}
1693
1694tr_bool
1695tr_sessionIsRPCEnabled( const tr_session * session )
1696{
1697    assert( tr_isSession( session ) );
1698
1699    return tr_rpcIsEnabled( session->rpcServer );
1700}
1701
1702void
1703tr_sessionSetRPCPort( tr_session * session,
1704                      tr_port      port )
1705{
1706    assert( tr_isSession( session ) );
1707
1708    tr_rpcSetPort( session->rpcServer, port );
1709}
1710
1711tr_port
1712tr_sessionGetRPCPort( const tr_session * session )
1713{
1714    assert( tr_isSession( session ) );
1715
1716    return tr_rpcGetPort( session->rpcServer );
1717}
1718
1719void
1720tr_sessionSetRPCCallback( tr_session * session,
1721                          tr_rpc_func  func,
1722                          void *       user_data )
1723{
1724    assert( tr_isSession( session ) );
1725
1726    session->rpc_func = func;
1727    session->rpc_func_user_data = user_data;
1728}
1729
1730void
1731tr_sessionSetRPCWhitelist( tr_session * session,
1732                           const char * whitelist )
1733{
1734    assert( tr_isSession( session ) );
1735
1736    tr_rpcSetWhitelist( session->rpcServer, whitelist );
1737}
1738
1739char*
1740tr_sessionGetRPCWhitelist( const tr_session * session )
1741{
1742    assert( tr_isSession( session ) );
1743
1744    return tr_rpcGetWhitelist( session->rpcServer );
1745}
1746
1747void
1748tr_sessionSetRPCWhitelistEnabled( tr_session * session,
1749                                  tr_bool      isEnabled )
1750{
1751    assert( tr_isSession( session ) );
1752
1753    tr_rpcSetWhitelistEnabled( session->rpcServer, isEnabled );
1754}
1755
1756tr_bool
1757tr_sessionGetRPCWhitelistEnabled( const tr_session * session )
1758{
1759    assert( tr_isSession( session ) );
1760
1761    return tr_rpcGetWhitelistEnabled( session->rpcServer );
1762}
1763
1764
1765void
1766tr_sessionSetRPCPassword( tr_session * session,
1767                          const char * password )
1768{
1769    assert( tr_isSession( session ) );
1770
1771    tr_rpcSetPassword( session->rpcServer, password );
1772}
1773
1774char*
1775tr_sessionGetRPCPassword( const tr_session * session )
1776{
1777    assert( tr_isSession( session ) );
1778
1779    return tr_rpcGetPassword( session->rpcServer );
1780}
1781
1782void
1783tr_sessionSetRPCUsername( tr_session * session,
1784                          const char * username )
1785{
1786    assert( tr_isSession( session ) );
1787
1788    tr_rpcSetUsername( session->rpcServer, username );
1789}
1790
1791char*
1792tr_sessionGetRPCUsername( const tr_session * session )
1793{
1794    assert( tr_isSession( session ) );
1795
1796    return tr_rpcGetUsername( session->rpcServer );
1797}
1798
1799void
1800tr_sessionSetRPCPasswordEnabled( tr_session * session,
1801                                 tr_bool      isEnabled )
1802{
1803    assert( tr_isSession( session ) );
1804
1805    tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled );
1806}
1807
1808tr_bool
1809tr_sessionIsRPCPasswordEnabled( const tr_session * session )
1810{
1811    assert( tr_isSession( session ) );
1812
1813    return tr_rpcIsPasswordEnabled( session->rpcServer );
1814}
1815
1816/***
1817****
1818***/
1819
1820tr_bool
1821tr_sessionIsProxyEnabled( const tr_session * session )
1822{
1823    assert( tr_isSession( session ) );
1824
1825    return session->isProxyEnabled;
1826}
1827
1828void
1829tr_sessionSetProxyEnabled( tr_session * session,
1830                           tr_bool      isEnabled )
1831{
1832    assert( tr_isSession( session ) );
1833
1834    session->isProxyEnabled = isEnabled != 0;
1835}
1836
1837tr_proxy_type
1838tr_sessionGetProxyType( const tr_session * session )
1839{
1840    assert( tr_isSession( session ) );
1841
1842    return session->proxyType;
1843}
1844
1845void
1846tr_sessionSetProxyType( tr_session *  session,
1847                        tr_proxy_type type )
1848{
1849    assert( tr_isSession( session ) );
1850
1851    session->proxyType = type;
1852}
1853
1854const char*
1855tr_sessionGetProxy( const tr_session * session )
1856{
1857    assert( tr_isSession( session ) );
1858
1859    return session->proxy;
1860}
1861
1862tr_port
1863tr_sessionGetProxyPort( const tr_session * session )
1864{
1865    assert( tr_isSession( session ) );
1866
1867    return session->proxyPort;
1868}
1869
1870void
1871tr_sessionSetProxy( tr_session * session,
1872                    const char * proxy )
1873{
1874    assert( tr_isSession( session ) );
1875
1876    if( proxy != session->proxy )
1877    {
1878        tr_free( session->proxy );
1879        session->proxy = tr_strdup( proxy );
1880    }
1881}
1882
1883void
1884tr_sessionSetProxyPort( tr_session * session,
1885                        tr_port      port )
1886{
1887    assert( tr_isSession( session ) );
1888
1889    session->proxyPort = port;
1890}
1891
1892tr_bool
1893tr_sessionIsProxyAuthEnabled( const tr_session * session )
1894{
1895    assert( tr_isSession( session ) );
1896
1897    return session->isProxyAuthEnabled;
1898}
1899
1900void
1901tr_sessionSetProxyAuthEnabled( tr_session * session,
1902                               tr_bool      isEnabled )
1903{
1904    assert( tr_isSession( session ) );
1905
1906    session->isProxyAuthEnabled = isEnabled != 0;
1907}
1908
1909const char*
1910tr_sessionGetProxyUsername( const tr_session * session )
1911{
1912    assert( tr_isSession( session ) );
1913
1914    return session->proxyUsername;
1915}
1916
1917void
1918tr_sessionSetProxyUsername( tr_session * session,
1919                            const char * username )
1920{
1921    assert( tr_isSession( session ) );
1922
1923    if( username != session->proxyUsername )
1924    {
1925        tr_free( session->proxyUsername );
1926        session->proxyUsername = tr_strdup( username );
1927    }
1928}
1929
1930const char*
1931tr_sessionGetProxyPassword( const tr_session * session )
1932{
1933    assert( tr_isSession( session ) );
1934
1935    return session->proxyPassword;
1936}
1937
1938void
1939tr_sessionSetProxyPassword( tr_session * session,
1940                            const char * password )
1941{
1942    assert( tr_isSession( session ) );
1943
1944    if( password != session->proxyPassword )
1945    {
1946        tr_free( session->proxyPassword );
1947        session->proxyPassword = tr_strdup( password );
1948    }
1949}
1950
1951int
1952tr_sessionGetActiveTorrentCount( tr_session * session )
1953{
1954    int ret = 0;
1955    tr_torrent * tor = NULL;
1956
1957    assert( tr_isSession( session ) );
1958
1959    while(( tor = tr_torrentNext( session, tor )))
1960        if( tr_torrentGetActivity( tor ) != TR_STATUS_STOPPED )
1961            ++ret;
1962
1963    return ret;
1964}
Note: See TracBrowser for help on using the repository browser.