source: trunk/libtransmission/transmission.c @ 5209

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

more i18n work.

  • Property svn:keywords set to Date Rev Author Id
File size: 11.6 KB
Line 
1/******************************************************************************
2 * $Id: transmission.c 5209 2008-03-07 03:26:59Z charles $
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 "fdlimit.h"
37#include "list.h"
38#include "net.h"
39#include "peer-mgr.h"
40#include "platform.h" /* tr_lock */
41#include "ratecontrol.h"
42#include "shared.h"
43#include "stats.h"
44#include "torrent.h"
45#include "tracker.h"
46#include "trevent.h"
47#include "utils.h"
48
49/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
50   characters, where x is the major version number, y is the
51   minor version number, z is the maintenance number, and b
52   designates beta (Azureus-style) */
53uint8_t*
54tr_peerIdNew( void )
55{
56    int i;
57    int val;
58    int total = 0;
59    uint8_t * buf = tr_new( uint8_t, 21 );
60    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz";
61    const int base = 36;
62
63    memcpy( buf, PEERID_PREFIX, 8 );
64
65    for( i=8; i<19; ++i ) {
66        val = tr_rand( base );
67        total += val;
68        buf[i] = pool[val];
69    }
70
71    val = total % base ? base - (total % base) : 0;
72    total += val;
73    buf[19] = pool[val];
74    buf[20] = '\0';
75
76    return buf;
77}
78
79const uint8_t*
80tr_getPeerId( void )
81{
82    static uint8_t * id = NULL;
83    if( id == NULL )
84        id = tr_peerIdNew( );
85    return id;
86}
87
88/***
89****
90***/
91
92tr_encryption_mode
93tr_getEncryptionMode( tr_handle * handle )
94{
95    assert( handle != NULL );
96
97    return handle->encryptionMode;
98}
99
100void
101tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
102{
103    assert( handle != NULL );
104    assert( mode==TR_ENCRYPTION_PREFERRED
105         || mode==TR_ENCRYPTION_REQUIRED
106         || mode==TR_PLAINTEXT_PREFERRED );
107
108    handle->encryptionMode = mode;
109}
110
111/***
112****
113***/
114
115tr_handle *
116tr_initFull( const char * tag,
117             int          isPexEnabled,
118             int          isNatEnabled,
119             int          publicPort,
120             int          encryptionMode,
121             int          isUploadLimitEnabled,
122             int          uploadLimit,
123             int          isDownloadLimitEnabled,
124             int          downloadLimit,
125             int          globalPeerLimit,
126             int          messageLevel,
127             int          isMessageQueueingEnabled )
128{
129    tr_handle * h;
130    char buf[128];
131
132#ifndef WIN32
133    /* Don't exit when writing on a broken socket */
134    signal( SIGPIPE, SIG_IGN );
135#endif
136
137    tr_msgInit( );
138    tr_setMessageLevel( messageLevel );
139    tr_setMessageQueuing( isMessageQueueingEnabled );
140
141    h = tr_new0( tr_handle, 1 );
142    h->lock = tr_lockNew( );
143    h->isPexEnabled = isPexEnabled ? 1 : 0;
144    h->encryptionMode = encryptionMode;
145
146    tr_netInit(); /* must go before tr_eventInit */
147
148    tr_eventInit( h );
149    while( !h->events )
150        tr_wait( 50 );
151
152    h->tag = strdup( tag );
153    if( !h->tag ) {
154        free( h );
155        return NULL;
156    }
157
158    h->peerMgr = tr_peerMgrNew( h );
159
160    /* Initialize rate and file descripts controls */
161
162    h->upload = tr_rcInit();
163    tr_rcSetLimit( h->upload, uploadLimit );
164    h->useUploadLimit = isUploadLimitEnabled;
165
166    h->download = tr_rcInit();
167    tr_rcSetLimit( h->download, downloadLimit );
168    h->useDownloadLimit = isDownloadLimitEnabled;
169
170    tr_fdInit( globalPeerLimit );
171    h->shared = tr_sharedInit( h, isNatEnabled, publicPort );
172    h->isPortSet = publicPort >= 0;
173
174    snprintf( buf, sizeof( buf ), _( "%s %s started" ),
175              TR_NAME, LONG_VERSION_STRING );
176    tr_inf( "%s", buf );
177
178    tr_statsInit( h );
179
180    return h;
181}
182
183tr_handle * tr_init( const char * tag )
184{
185    return tr_initFull( tag,
186                        TRUE, /* pex enabled */
187                        FALSE, /* nat enabled */
188                        -1, /* public port */
189                        TR_ENCRYPTION_PREFERRED, /* encryption mode */
190                        FALSE, /* use upload speed limit? */ 
191                        -1, /* upload speed limit */
192                        FALSE, /* use download speed limit? */
193                        -1, /* download speed limit */
194                        200, /* globalPeerLimit */
195                        TR_MSG_INF, /* message level */
196                        FALSE ); /* is message queueing enabled? */
197}
198
199/***
200****
201***/
202
203void
204tr_globalLock( struct tr_handle * handle )
205{
206    tr_lockLock( handle->lock );
207}
208
209void
210tr_globalUnlock( struct tr_handle * handle )
211{
212    tr_lockUnlock( handle->lock );
213}
214
215int
216tr_globalIsLocked( const struct tr_handle * handle )
217{
218    return handle && tr_lockHave( handle->lock );
219}
220
221/***********************************************************************
222 * tr_setBindPort
223 ***********************************************************************
224 *
225 **********************************************************************/
226
227struct bind_port_data
228{
229    tr_handle * handle;
230    int port;
231};
232
233static void
234tr_setBindPortImpl( void * vdata )
235{
236    struct bind_port_data * data = vdata;
237    tr_handle * handle = data->handle;
238    const int port = data->port;
239
240    handle->isPortSet = 1;
241    tr_sharedSetPort( handle->shared, port );
242
243    tr_free( data );
244}
245
246void
247tr_setBindPort( tr_handle * handle, int port )
248{
249    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
250    data->handle = handle;
251    data->port = port;
252    tr_runInEventThread( handle, tr_setBindPortImpl, data );
253}
254
255int
256tr_getPublicPort( const tr_handle * h )
257{
258    assert( h != NULL );
259    return tr_sharedGetPublicPort( h->shared );
260}
261
262void tr_natTraversalEnable( tr_handle * h, int enable )
263{
264    tr_globalLock( h );
265    tr_sharedTraversalEnable( h->shared, enable );
266    tr_globalUnlock( h );
267}
268
269const tr_handle_status *
270tr_handleStatus( tr_handle * h )
271{
272    tr_handle_status * s;
273
274    h->statCur = ( h->statCur + 1 ) % 2;
275    s = &h->stats[h->statCur];
276
277    tr_globalLock( h );
278
279    s->natTraversalStatus = tr_sharedTraversalStatus( h->shared );
280    s->publicPort = tr_sharedGetPublicPort( h->shared );
281
282    tr_globalUnlock( h );
283
284    return s;
285}
286
287/***
288****
289***/
290
291void
292tr_setUseGlobalSpeedLimit( tr_handle  * h,
293                           int          up_or_down,
294                           int          use_flag )
295{
296    char * ch = up_or_down==TR_UP ? &h->useUploadLimit
297                                  : &h->useDownloadLimit;
298    *ch = use_flag;
299}
300
301void
302tr_setGlobalSpeedLimit( tr_handle  * h,
303                        int          up_or_down,
304                        int          KiB_sec )
305{
306    if( up_or_down == TR_DOWN )
307        tr_rcSetLimit( h->download, KiB_sec );
308    else
309        tr_rcSetLimit( h->upload, KiB_sec );
310}
311
312void
313tr_getGlobalSpeedLimit( tr_handle  * h,
314                        int          up_or_down,
315                        int        * setme_enabled,
316                        int          * setme_KiBsec )
317{
318    if( setme_enabled != NULL )
319       *setme_enabled = up_or_down==TR_UP ? h->useUploadLimit
320                                          : h->useDownloadLimit;
321    if( setme_KiBsec != NULL )
322       *setme_KiBsec = tr_rcGetLimit( up_or_down==TR_UP ? h->upload
323                                                        : h->download );
324}
325
326
327void
328tr_setGlobalPeerLimit( tr_handle * handle UNUSED,
329                       uint16_t    maxGlobalPeers )
330{
331    tr_fdSetPeerLimit( maxGlobalPeers );
332}
333
334uint16_t
335tr_getGlobalPeerLimit( const tr_handle * handle UNUSED )
336{
337    return tr_fdGetPeerLimit( );
338}
339
340void
341tr_torrentRates( tr_handle * h, float * toClient, float * toPeer )
342{
343    const tr_torrent * tor;
344    tr_globalLock( h );
345
346    *toClient = *toPeer = 0.0;
347    for( tor = h->torrentList; tor; tor = tor->next )
348    {
349        float c, p;
350        tr_torrentGetRates( tor, &c, &p );
351        *toClient += c;
352        *toPeer += p;
353    }
354
355    tr_globalUnlock( h );
356}
357
358int
359tr_torrentCount( const tr_handle * h )
360{
361    return h->torrentCount;
362}
363
364static void
365tr_closeImpl( void * vh )
366{
367    tr_handle * h = vh;
368    tr_torrent * t;
369
370    tr_sharedShuttingDown( h->shared );
371    tr_trackerShuttingDown( h );
372
373    for( t=h->torrentList; t!=NULL; ) {
374        tr_torrent * tmp = t;
375        t = t->next;
376        tr_torrentClose( tmp );
377    }
378
379    tr_peerMgrFree( h->peerMgr );
380
381    tr_rcClose( h->upload );
382    tr_rcClose( h->download );
383   
384    h->isClosed = TRUE;
385}
386
387static int
388deadlineReached( const uint64_t deadline )
389{
390    return tr_date( ) >= deadline;
391}
392
393#define SHUTDOWN_MAX_SECONDS 30
394
395void
396tr_close( tr_handle * h )
397{
398    const int maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
399    const uint64_t deadline = tr_date( ) + maxwait_msec;
400
401    tr_statsClose( h );
402
403    tr_runInEventThread( h, tr_closeImpl, h );
404    while( !h->isClosed && !deadlineReached( deadline ) )
405        tr_wait( 100 );
406
407    tr_eventClose( h );
408    while( h->events && !deadlineReached( deadline ) )
409        tr_wait( 100 );
410
411    tr_fdClose( );
412    tr_lockFree( h->lock );
413    free( h->tag );
414    free( h );
415}
416
417tr_torrent **
418tr_loadTorrents ( tr_handle   * h,
419                  tr_ctor     * ctor,
420                  int         * setmeCount )
421{
422    int i, n = 0;
423    struct stat sb;
424    DIR * odir = NULL;
425    const char * dirname = tr_getTorrentsDirectory( );
426    tr_torrent ** torrents;
427    tr_list *l=NULL, *list=NULL;
428
429    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
430
431    if( !stat( dirname, &sb )
432        && S_ISDIR( sb.st_mode )
433        && (( odir = opendir ( dirname ) )) )
434    {
435        struct dirent *d;
436        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
437        {
438            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
439            {
440                tr_torrent * tor;
441                char filename[MAX_PATH_LENGTH];
442                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
443                tr_ctorSetMetainfoFromFile( ctor, filename );
444                tor = tr_torrentNew( h, ctor, NULL );
445                if( tor != NULL ) {
446                    tr_list_append( &list, tor );
447                    n++;
448                }
449            }
450        }
451        closedir( odir );
452    }
453
454    torrents = tr_new( tr_torrent*, n );
455    for( i=0, l=list; l!=NULL; l=l->next )
456        torrents[i++] = (tr_torrent*) l->data;
457    assert( i==n );
458
459    tr_list_free( &list, NULL );
460
461    *setmeCount = n;
462    tr_inf( _( "Loaded %d torrents" ), *setmeCount );
463    return torrents;
464}
465
466/***
467****
468***/
469
470void
471tr_setPexEnabled( tr_handle * handle, int isPexEnabled )
472{
473    handle->isPexEnabled = isPexEnabled ? 1 : 0;
474}
475
476int
477tr_isPexEnabled( const tr_handle * handle )
478{
479    return handle->isPexEnabled;
480}
Note: See TracBrowser for help on using the repository browser.