source: trunk/libtransmission/transmission.c @ 4324

Last change on this file since 4324 was 4324, checked in by charles, 15 years ago

a little housekeeping: move tr_torrent stuff into its own header

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