source: trunk/libtransmission/session.c @ 5585

Last change on this file since 5585 was 5585, checked in by charles, 14 years ago

tidy up some libtransmission filenames.

  • Property svn:keywords set to Date Rev Author Id
File size: 13.1 KB
Line 
1/******************************************************************************
2 * $Id:$
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <stdlib.h>
27#include <string.h> /* memcpy */
28
29#include <signal.h>
30#include <sys/types.h> /* stat */
31#include <sys/stat.h> /* stat */
32#include <unistd.h> /* stat */
33#include <dirent.h> /* opendir */
34
35#include "transmission.h"
36#include "blocklist.h"
37#include "fdlimit.h"
38#include "list.h"
39#include "net.h"
40#include "peer-mgr.h"
41#include "platform.h" /* tr_lock */
42#include "port-forwarding.h"
43#include "ratecontrol.h"
44#include "stats.h"
45#include "torrent.h"
46#include "tracker.h"
47#include "trevent.h"
48#include "utils.h"
49
50/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
51   characters, where x is the major version number, y is the
52   minor version number, z is the maintenance number, and b
53   designates beta (Azureus-style) */
54uint8_t*
55tr_peerIdNew( void )
56{
57    int i;
58    int val;
59    int total = 0;
60    uint8_t * buf = tr_new( uint8_t, 21 );
61    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
62    const int base = 36;
63
64    memcpy( buf, PEERID_PREFIX, 8 );
65
66    for( i=8; i<19; ++i ) {
67        val = tr_rand( base );
68        total += val;
69        buf[i] = pool[val];
70    }
71
72    val = total % base ? base - (total % base) : 0;
73    total += val;
74    buf[19] = pool[val];
75    buf[20] = '\0';
76
77    return buf;
78}
79
80const uint8_t*
81tr_getPeerId( void )
82{
83    static uint8_t * id = NULL;
84    if( id == NULL )
85        id = tr_peerIdNew( );
86    return id;
87}
88
89/***
90****
91***/
92
93tr_encryption_mode
94tr_getEncryptionMode( tr_handle * handle )
95{
96    assert( handle != NULL );
97
98    return handle->encryptionMode;
99}
100
101void
102tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
103{
104    assert( handle != NULL );
105    assert( mode==TR_ENCRYPTION_PREFERRED
106         || mode==TR_ENCRYPTION_REQUIRED
107         || mode==TR_PLAINTEXT_PREFERRED );
108
109    handle->encryptionMode = mode;
110}
111
112/***
113****
114***/
115
116tr_handle *
117tr_initFull( const char * configDir,
118             const char * tag,
119             int          isPexEnabled,
120             int          isNatEnabled,
121             int          publicPort,
122             int          encryptionMode,
123             int          isUploadLimitEnabled,
124             int          uploadLimit,
125             int          isDownloadLimitEnabled,
126             int          downloadLimit,
127             int          globalPeerLimit,
128             int          messageLevel,
129             int          isMessageQueueingEnabled,
130             int          isBlocklistEnabled )
131{
132    tr_handle * h;
133    char filename[MAX_PATH_LENGTH];
134
135#ifndef WIN32
136    /* Don't exit when writing on a broken socket */
137    signal( SIGPIPE, SIG_IGN );
138#endif
139
140    if( configDir == NULL )
141        configDir = tr_getDefaultConfigDir( );
142
143    tr_msgInit( );
144    tr_setMessageLevel( messageLevel );
145    tr_setMessageQueuing( isMessageQueueingEnabled );
146
147    h = tr_new0( tr_handle, 1 );
148    h->lock = tr_lockNew( );
149    h->isPexEnabled = isPexEnabled ? 1 : 0;
150    h->encryptionMode = encryptionMode;
151    h->configDir = tr_strdup( configDir );
152
153    tr_setConfigDir( h, configDir );
154
155    tr_netInit(); /* must go before tr_eventInit */
156
157    tr_eventInit( h );
158    while( !h->events )
159        tr_wait( 50 );
160
161    h->tag = strdup( tag );
162    if( !h->tag ) {
163        free( h );
164        return NULL;
165    }
166
167    h->peerMgr = tr_peerMgrNew( h );
168
169    /* Initialize rate and file descripts controls */
170
171    h->upload = tr_rcInit();
172    tr_rcSetLimit( h->upload, uploadLimit );
173    h->useUploadLimit = isUploadLimitEnabled;
174
175    h->download = tr_rcInit();
176    tr_rcSetLimit( h->download, downloadLimit );
177    h->useDownloadLimit = isDownloadLimitEnabled;
178
179    tr_fdInit( globalPeerLimit );
180    h->shared = tr_sharedInit( h, isNatEnabled, publicPort );
181    h->isPortSet = publicPort >= 0;
182
183    /* first %s is the application name
184       second %s is the version number */
185    tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING );
186
187    /* initialize the blocklist */
188    tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", NULL );
189    tr_mkdirp( filename, 0777 );
190    tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", "level1.bin", NULL );
191    h->blocklist = _tr_blocklistNew( filename, isBlocklistEnabled );
192
193    tr_statsInit( h );
194
195    return h;
196}
197
198tr_handle *
199tr_init( const char * configDir,
200         const char * tag )
201{
202    return tr_initFull( configDir,
203                        tag,
204                        TRUE, /* pex enabled */
205                        FALSE, /* nat enabled */
206                        -1, /* public port */
207                        TR_ENCRYPTION_PREFERRED, /* encryption mode */
208                        FALSE, /* use upload speed limit? */ 
209                        -1, /* upload speed limit */
210                        FALSE, /* use download speed limit? */
211                        -1, /* download speed limit */
212                        200, /* globalPeerLimit */
213                        TR_MSG_INF, /* message level */
214                        FALSE, /* is message queueing enabled? */
215                        FALSE ); /* is the blocklist enabled? */
216}
217
218/***
219****
220***/
221
222void
223tr_globalLock( struct tr_handle * handle )
224{
225    tr_lockLock( handle->lock );
226}
227
228void
229tr_globalUnlock( struct tr_handle * handle )
230{
231    tr_lockUnlock( handle->lock );
232}
233
234int
235tr_globalIsLocked( const struct tr_handle * handle )
236{
237    return handle && tr_lockHave( handle->lock );
238}
239
240/***********************************************************************
241 * tr_setBindPort
242 ***********************************************************************
243 *
244 **********************************************************************/
245
246struct bind_port_data
247{
248    tr_handle * handle;
249    int port;
250};
251
252static void
253tr_setBindPortImpl( void * vdata )
254{
255    struct bind_port_data * data = vdata;
256    tr_handle * handle = data->handle;
257    const int port = data->port;
258
259    handle->isPortSet = 1;
260    tr_sharedSetPort( handle->shared, port );
261
262    tr_free( data );
263}
264
265void
266tr_setBindPort( tr_handle * handle, int port )
267{
268    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
269    data->handle = handle;
270    data->port = port;
271    tr_runInEventThread( handle, tr_setBindPortImpl, data );
272}
273
274int
275tr_getPublicPort( const tr_handle * h )
276{
277    assert( h != NULL );
278    return tr_sharedGetPublicPort( h->shared );
279}
280
281void tr_natTraversalEnable( tr_handle * h, int enable )
282{
283    tr_globalLock( h );
284    tr_sharedTraversalEnable( h->shared, enable );
285    tr_globalUnlock( h );
286}
287
288const tr_handle_status *
289tr_handleStatus( tr_handle * h )
290{
291    tr_handle_status * s;
292
293    h->statCur = ( h->statCur + 1 ) % 2;
294    s = &h->stats[h->statCur];
295
296    tr_globalLock( h );
297
298    s->natTraversalStatus = tr_sharedTraversalStatus( h->shared );
299    s->publicPort = tr_sharedGetPublicPort( h->shared );
300
301    tr_globalUnlock( h );
302
303    return s;
304}
305
306/***
307****
308***/
309
310void
311tr_setUseGlobalSpeedLimit( tr_handle  * h,
312                           int          up_or_down,
313                           int          use_flag )
314{
315    if( up_or_down == TR_UP )
316        h->useUploadLimit = use_flag ? 1 : 0;
317    else
318        h->useDownloadLimit = use_flag ? 1 : 0;
319}
320
321void
322tr_setGlobalSpeedLimit( tr_handle  * h,
323                        int          up_or_down,
324                        int          KiB_sec )
325{
326    if( up_or_down == TR_DOWN )
327        tr_rcSetLimit( h->download, KiB_sec );
328    else
329        tr_rcSetLimit( h->upload, KiB_sec );
330}
331
332void
333tr_getGlobalSpeedLimit( tr_handle  * h,
334                        int          up_or_down,
335                        int        * setme_enabled,
336                        int          * setme_KiBsec )
337{
338    if( setme_enabled != NULL )
339       *setme_enabled = up_or_down==TR_UP ? h->useUploadLimit
340                                          : h->useDownloadLimit;
341    if( setme_KiBsec != NULL )
342       *setme_KiBsec = tr_rcGetLimit( up_or_down==TR_UP ? h->upload
343                                                        : h->download );
344}
345
346
347void
348tr_setGlobalPeerLimit( tr_handle * handle UNUSED,
349                       uint16_t    maxGlobalPeers )
350{
351    tr_fdSetPeerLimit( maxGlobalPeers );
352}
353
354uint16_t
355tr_getGlobalPeerLimit( const tr_handle * handle UNUSED )
356{
357    return tr_fdGetPeerLimit( );
358}
359
360void
361tr_torrentRates( tr_handle * h, float * toClient, float * toPeer )
362{
363    tr_globalLock( h );
364
365    if( toClient )
366        *toClient = tr_rcRate( h->download );
367    if( toPeer )
368        *toPeer = tr_rcRate( h->upload );
369
370    tr_globalUnlock( h );
371}
372
373int
374tr_torrentCount( const tr_handle * h )
375{
376    return h->torrentCount;
377}
378
379static void
380tr_closeImpl( void * vh )
381{
382    tr_handle * h = vh;
383    tr_torrent * t;
384
385    tr_sharedShuttingDown( h->shared );
386    tr_trackerShuttingDown( h );
387
388    _tr_blocklistFree( h->blocklist );
389    h->blocklist = NULL;
390
391    for( t=h->torrentList; t!=NULL; ) {
392        tr_torrent * tmp = t;
393        t = t->next;
394        tr_torrentClose( tmp );
395    }
396
397    tr_peerMgrFree( h->peerMgr );
398
399    tr_rcClose( h->upload );
400    tr_rcClose( h->download );
401   
402    h->isClosed = TRUE;
403}
404
405static int
406deadlineReached( const uint64_t deadline )
407{
408    return tr_date( ) >= deadline;
409}
410
411#define SHUTDOWN_MAX_SECONDS 30
412
413void
414tr_close( tr_handle * h )
415{
416    const int maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
417    const uint64_t deadline = tr_date( ) + maxwait_msec;
418
419    tr_statsClose( h );
420
421    tr_runInEventThread( h, tr_closeImpl, h );
422    while( !h->isClosed && !deadlineReached( deadline ) )
423        tr_wait( 100 );
424
425    tr_eventClose( h );
426    while( h->events && !deadlineReached( deadline ) )
427        tr_wait( 100 );
428
429    tr_fdClose( );
430    tr_lockFree( h->lock );
431    free( h->tag );
432    free( h );
433}
434
435tr_torrent **
436tr_loadTorrents ( tr_handle   * h,
437                  tr_ctor     * ctor,
438                  int         * setmeCount )
439{
440    int i, n = 0;
441    struct stat sb;
442    DIR * odir = NULL;
443    const char * dirname = tr_getTorrentDir( h );
444    tr_torrent ** torrents;
445    tr_list *l=NULL, *list=NULL;
446
447    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
448
449    if( !stat( dirname, &sb )
450        && S_ISDIR( sb.st_mode )
451        && (( odir = opendir ( dirname ) )) )
452    {
453        struct dirent *d;
454        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
455        {
456            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
457            {
458                tr_torrent * tor;
459                char filename[MAX_PATH_LENGTH];
460                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
461                tr_ctorSetMetainfoFromFile( ctor, filename );
462                tor = tr_torrentNew( h, ctor, NULL );
463                if( tor != NULL ) {
464                    tr_list_append( &list, tor );
465                    n++;
466                }
467            }
468        }
469        closedir( odir );
470    }
471
472    torrents = tr_new( tr_torrent*, n );
473    for( i=0, l=list; l!=NULL; l=l->next )
474        torrents[i++] = (tr_torrent*) l->data;
475    assert( i==n );
476
477    tr_list_free( &list, NULL );
478
479    if( n )
480        tr_inf( _( "Loaded %d torrents" ), n );
481
482    *setmeCount = n;
483    return torrents;
484}
485
486/***
487****
488***/
489
490void
491tr_setPexEnabled( tr_handle * handle, int isPexEnabled )
492{
493    handle->isPexEnabled = isPexEnabled ? 1 : 0;
494}
495
496int
497tr_isPexEnabled( const tr_handle * handle )
498{
499    return handle->isPexEnabled;
500}
501
502/***
503****
504***/
505
506int
507tr_blocklistGetRuleCount( tr_handle * handle )
508{
509    return _tr_blocklistGetRuleCount( handle->blocklist );
510}
511
512int
513tr_blocklistIsEnabled( const tr_handle * handle )
514{
515    return _tr_blocklistIsEnabled( handle->blocklist );
516}
517
518void
519tr_blocklistSetEnabled( tr_handle * handle, int isEnabled )
520{
521    _tr_blocklistSetEnabled( handle->blocklist, isEnabled );
522}
523
524int
525tr_blocklistExists( const tr_handle * handle )
526{
527    return _tr_blocklistExists( handle->blocklist );
528}
529
530int
531tr_blocklistSetContent( tr_handle  * handle, const char * filename )
532{
533    return _tr_blocklistSetContent( handle->blocklist, filename );
534}
535
536int
537tr_blocklistHasAddress( tr_handle * handle, const struct in_addr * addr )
538{
539    return _tr_blocklistHasAddress( handle->blocklist, addr );
540}
Note: See TracBrowser for help on using the repository browser.