source: trunk/libtransmission/transmission.c @ 5222

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

more i18n improvements. thanks to Gnome translator andre for feedback.

  • Property svn:keywords set to Date Rev Author Id
File size: 11.7 KB
Line 
1/******************************************************************************
2 * $Id: transmission.c 5222 2008-03-07 21:20:45Z 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    /* Translators: first %s is the application name, second %s is the version number */
175    snprintf( buf, sizeof( buf ), _( "%s %s started" ),
176              TR_NAME, LONG_VERSION_STRING );
177    tr_inf( "%s", buf );
178
179    tr_statsInit( h );
180
181    return h;
182}
183
184tr_handle * tr_init( const char * tag )
185{
186    return tr_initFull( tag,
187                        TRUE, /* pex enabled */
188                        FALSE, /* nat enabled */
189                        -1, /* public port */
190                        TR_ENCRYPTION_PREFERRED, /* encryption mode */
191                        FALSE, /* use upload speed limit? */ 
192                        -1, /* upload speed limit */
193                        FALSE, /* use download speed limit? */
194                        -1, /* download speed limit */
195                        200, /* globalPeerLimit */
196                        TR_MSG_INF, /* message level */
197                        FALSE ); /* is message queueing enabled? */
198}
199
200/***
201****
202***/
203
204void
205tr_globalLock( struct tr_handle * handle )
206{
207    tr_lockLock( handle->lock );
208}
209
210void
211tr_globalUnlock( struct tr_handle * handle )
212{
213    tr_lockUnlock( handle->lock );
214}
215
216int
217tr_globalIsLocked( const struct tr_handle * handle )
218{
219    return handle && tr_lockHave( handle->lock );
220}
221
222/***********************************************************************
223 * tr_setBindPort
224 ***********************************************************************
225 *
226 **********************************************************************/
227
228struct bind_port_data
229{
230    tr_handle * handle;
231    int port;
232};
233
234static void
235tr_setBindPortImpl( void * vdata )
236{
237    struct bind_port_data * data = vdata;
238    tr_handle * handle = data->handle;
239    const int port = data->port;
240
241    handle->isPortSet = 1;
242    tr_sharedSetPort( handle->shared, port );
243
244    tr_free( data );
245}
246
247void
248tr_setBindPort( tr_handle * handle, int port )
249{
250    struct bind_port_data * data = tr_new( struct bind_port_data, 1 );
251    data->handle = handle;
252    data->port = port;
253    tr_runInEventThread( handle, tr_setBindPortImpl, data );
254}
255
256int
257tr_getPublicPort( const tr_handle * h )
258{
259    assert( h != NULL );
260    return tr_sharedGetPublicPort( h->shared );
261}
262
263void tr_natTraversalEnable( tr_handle * h, int enable )
264{
265    tr_globalLock( h );
266    tr_sharedTraversalEnable( h->shared, enable );
267    tr_globalUnlock( h );
268}
269
270const tr_handle_status *
271tr_handleStatus( tr_handle * h )
272{
273    tr_handle_status * s;
274
275    h->statCur = ( h->statCur + 1 ) % 2;
276    s = &h->stats[h->statCur];
277
278    tr_globalLock( h );
279
280    s->natTraversalStatus = tr_sharedTraversalStatus( h->shared );
281    s->publicPort = tr_sharedGetPublicPort( h->shared );
282
283    tr_globalUnlock( h );
284
285    return s;
286}
287
288/***
289****
290***/
291
292void
293tr_setUseGlobalSpeedLimit( tr_handle  * h,
294                           int          up_or_down,
295                           int          use_flag )
296{
297    char * ch = up_or_down==TR_UP ? &h->useUploadLimit
298                                  : &h->useDownloadLimit;
299    *ch = use_flag;
300}
301
302void
303tr_setGlobalSpeedLimit( tr_handle  * h,
304                        int          up_or_down,
305                        int          KiB_sec )
306{
307    if( up_or_down == TR_DOWN )
308        tr_rcSetLimit( h->download, KiB_sec );
309    else
310        tr_rcSetLimit( h->upload, KiB_sec );
311}
312
313void
314tr_getGlobalSpeedLimit( tr_handle  * h,
315                        int          up_or_down,
316                        int        * setme_enabled,
317                        int          * setme_KiBsec )
318{
319    if( setme_enabled != NULL )
320       *setme_enabled = up_or_down==TR_UP ? h->useUploadLimit
321                                          : h->useDownloadLimit;
322    if( setme_KiBsec != NULL )
323       *setme_KiBsec = tr_rcGetLimit( up_or_down==TR_UP ? h->upload
324                                                        : h->download );
325}
326
327
328void
329tr_setGlobalPeerLimit( tr_handle * handle UNUSED,
330                       uint16_t    maxGlobalPeers )
331{
332    tr_fdSetPeerLimit( maxGlobalPeers );
333}
334
335uint16_t
336tr_getGlobalPeerLimit( const tr_handle * handle UNUSED )
337{
338    return tr_fdGetPeerLimit( );
339}
340
341void
342tr_torrentRates( tr_handle * h, float * toClient, float * toPeer )
343{
344    const tr_torrent * tor;
345    tr_globalLock( h );
346
347    *toClient = *toPeer = 0.0;
348    for( tor = h->torrentList; tor; tor = tor->next )
349    {
350        float c, p;
351        tr_torrentGetRates( tor, &c, &p );
352        *toClient += c;
353        *toPeer += p;
354    }
355
356    tr_globalUnlock( h );
357}
358
359int
360tr_torrentCount( const tr_handle * h )
361{
362    return h->torrentCount;
363}
364
365static void
366tr_closeImpl( void * vh )
367{
368    tr_handle * h = vh;
369    tr_torrent * t;
370
371    tr_sharedShuttingDown( h->shared );
372    tr_trackerShuttingDown( h );
373
374    for( t=h->torrentList; t!=NULL; ) {
375        tr_torrent * tmp = t;
376        t = t->next;
377        tr_torrentClose( tmp );
378    }
379
380    tr_peerMgrFree( h->peerMgr );
381
382    tr_rcClose( h->upload );
383    tr_rcClose( h->download );
384   
385    h->isClosed = TRUE;
386}
387
388static int
389deadlineReached( const uint64_t deadline )
390{
391    return tr_date( ) >= deadline;
392}
393
394#define SHUTDOWN_MAX_SECONDS 30
395
396void
397tr_close( tr_handle * h )
398{
399    const int maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
400    const uint64_t deadline = tr_date( ) + maxwait_msec;
401
402    tr_statsClose( h );
403
404    tr_runInEventThread( h, tr_closeImpl, h );
405    while( !h->isClosed && !deadlineReached( deadline ) )
406        tr_wait( 100 );
407
408    tr_eventClose( h );
409    while( h->events && !deadlineReached( deadline ) )
410        tr_wait( 100 );
411
412    tr_fdClose( );
413    tr_lockFree( h->lock );
414    free( h->tag );
415    free( h );
416}
417
418tr_torrent **
419tr_loadTorrents ( tr_handle   * h,
420                  tr_ctor     * ctor,
421                  int         * setmeCount )
422{
423    int i, n = 0;
424    struct stat sb;
425    DIR * odir = NULL;
426    const char * dirname = tr_getTorrentsDirectory( );
427    tr_torrent ** torrents;
428    tr_list *l=NULL, *list=NULL;
429
430    tr_ctorSetSave( ctor, FALSE ); /* since we already have them */
431
432    if( !stat( dirname, &sb )
433        && S_ISDIR( sb.st_mode )
434        && (( odir = opendir ( dirname ) )) )
435    {
436        struct dirent *d;
437        for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
438        {
439            if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
440            {
441                tr_torrent * tor;
442                char filename[MAX_PATH_LENGTH];
443                tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
444                tr_ctorSetMetainfoFromFile( ctor, filename );
445                tor = tr_torrentNew( h, ctor, NULL );
446                if( tor != NULL ) {
447                    tr_list_append( &list, tor );
448                    n++;
449                }
450            }
451        }
452        closedir( odir );
453    }
454
455    torrents = tr_new( tr_torrent*, n );
456    for( i=0, l=list; l!=NULL; l=l->next )
457        torrents[i++] = (tr_torrent*) l->data;
458    assert( i==n );
459
460    tr_list_free( &list, NULL );
461
462    *setmeCount = n;
463    tr_inf( _( "Loaded %d torrents" ), *setmeCount );
464    return torrents;
465}
466
467/***
468****
469***/
470
471void
472tr_setPexEnabled( tr_handle * handle, int isPexEnabled )
473{
474    handle->isPexEnabled = isPexEnabled ? 1 : 0;
475}
476
477int
478tr_isPexEnabled( const tr_handle * handle )
479{
480    return handle->isPexEnabled;
481}
Note: See TracBrowser for help on using the repository browser.