source: trunk/libtransmission/transmission.c @ 5193

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

first cut at adding i18n hooks into libtransmission.

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