~ubuntu-branches/ubuntu/precise/transmission/precise

« back to all changes in this revision

Viewing changes to libtransmission/tracker.c

  • Committer: Bazaar Package Importer
  • Author(s): Leo Costela
  • Date: 2009-05-17 19:39:51 UTC
  • mto: (1.3.4 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: james.westby@ubuntu.com-20090517193951-k8x15sqoxzf7cuyx
ImportĀ upstreamĀ versionĀ 1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
 
2
 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
3
3
 *
4
4
 * This file is licensed by the GPL version 2.  Works owned by the
5
5
 * Transmission project are granted a special exemption to clause 2(b)
6
 
 * so that the bulk of its code can remain under the MIT license. 
 
6
 * so that the bulk of its code can remain under the MIT license.
7
7
 * This exemption does not extend to derived works not owned by
8
8
 * the Transmission project.
9
9
 *
10
 
 * $Id: tracker.c 5881 2008-05-21 17:25:56Z charles $
 
10
 * $Id: tracker.c 8268 2009-04-21 16:52:28Z charles $
11
11
 */
12
12
 
13
13
#include <assert.h>
14
 
#include <stdio.h> /* snprintf */
15
14
#include <stdlib.h>
16
15
#include <string.h> /* strcmp, strchr */
17
16
 
18
17
#include <event.h>
19
18
 
20
19
#include "transmission.h"
 
20
#include "session.h"
21
21
#include "bencode.h"
 
22
#include "crypto.h"
22
23
#include "completion.h"
23
24
#include "net.h"
24
 
#include "port-forwarding.h"
25
25
#include "publish.h"
 
26
#include "resume.h"
26
27
#include "torrent.h"
27
28
#include "tracker.h"
28
 
#include "trcompat.h" /* strlcpy */
29
29
#include "trevent.h"
30
30
#include "utils.h"
31
31
#include "web.h"
32
32
 
33
33
enum
34
34
{
 
35
    /* the announceAt fields are set to this when the action is disabled */
 
36
    TR_TRACKER_STOPPED = 0,
 
37
 
 
38
    /* the announceAt fields are set to this when the action is in progress */
 
39
    TR_TRACKER_BUSY = 1,
 
40
 
35
41
    HTTP_OK = 200,
36
42
 
37
43
    /* seconds between tracker pulses */
38
44
    PULSE_INTERVAL_MSEC = 1000,
39
45
 
40
 
    /* maximum number of concurrent tracker socket connections */
41
 
    MAX_TRACKER_SOCKETS = 16,
42
 
 
43
 
    /* maximum number of concurrent tracker socket connections during shutdown.
44
 
     * all the peer connections should be gone by now, so we can hog more 
45
 
     * connections to send `stop' messages to the trackers */
46
 
    MAX_TRACKER_SOCKETS_DURING_SHUTDOWN = 64,
47
 
 
48
46
    /* unless the tracker says otherwise, rescrape this frequently */
49
 
    DEFAULT_SCRAPE_INTERVAL_SEC = (60 * 15),
 
47
    DEFAULT_SCRAPE_INTERVAL_SEC = ( 60 * 15 ),
50
48
 
51
49
    /* unless the tracker says otherwise, this is the announce interval */
52
 
    DEFAULT_ANNOUNCE_INTERVAL_SEC = (60 * 4),
 
50
    DEFAULT_ANNOUNCE_INTERVAL_SEC = ( 60 * 4 ),
53
51
 
54
52
    /* unless the tracker says otherwise, this is the announce min_interval */
55
 
    DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = (60 * 2),
 
53
    DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = ( 60 * 2 ),
 
54
 
 
55
    /* how long to wait before a rescrape the first time we get an error */
 
56
    FIRST_SCRAPE_RETRY_INTERVAL_SEC = 30,
 
57
 
 
58
    /* how long to wait before a reannounce the first time we get an error */
 
59
    FIRST_ANNOUNCE_RETRY_INTERVAL_SEC = 30,
56
60
 
57
61
    /* the value of the 'numwant' argument passed in tracker requests. */
58
 
    NUMWANT = 80,
 
62
    NUMWANT = 200,
59
63
 
60
64
    /* the length of the 'key' argument passed in tracker requests */
61
65
    KEYLEN = 10
67
71
 
68
72
struct tr_tracker
69
73
{
70
 
    unsigned int isRunning     : 1;
71
 
 
72
 
    uint8_t randOffset;
73
 
 
74
 
    tr_session * session;
75
 
 
76
 
    /* these are set from the latest scrape or tracker response */
77
 
    int announceIntervalSec;
78
 
    int announceMinIntervalSec;
79
 
    int scrapeIntervalSec;
80
 
    int retryScrapeIntervalSec;
81
 
 
82
 
    /* index into the torrent's tr_info.trackers array */
83
 
    int trackerIndex;
 
74
    tr_bool         isRunning;
 
75
 
 
76
    uint8_t         randOffset;
84
77
 
85
78
    /* sent as the "key" argument in tracker requests
86
79
       to verify us if our IP address changes.
87
80
       This is immutable for the life of the tracker object. */
88
 
    char key_param[KEYLEN+1];
89
 
 
90
 
    tr_publisher_t * publisher;
 
81
    char    key_param[KEYLEN + 1];
 
82
 
 
83
    /* these are set from the latest scrape or tracker response */
 
84
    int    announceIntervalSec;
 
85
    int    announceMinIntervalSec;
 
86
    int    scrapeIntervalSec;
 
87
    int    retryScrapeIntervalSec;
 
88
    int    retryAnnounceIntervalSec;
 
89
 
 
90
    /* index into the torrent's tr_info.trackers array */
 
91
    int               trackerIndex;
 
92
 
 
93
    tr_session *      session;
 
94
 
 
95
    tr_publisher      publisher;
91
96
 
92
97
    /* torrent hash string */
93
 
    uint8_t hash[SHA_DIGEST_LENGTH];
94
 
    char escaped[SHA_DIGEST_LENGTH*3 + 1];
95
 
    char * name;
 
98
    uint8_t    hash[SHA_DIGEST_LENGTH];
 
99
    char       escaped[SHA_DIGEST_LENGTH * 3 + 1];
 
100
    char *     name;
 
101
    int        torrentId;
96
102
 
97
103
    /* corresponds to the peer_id sent as a tracker request parameter.
98
104
       one tracker admin says: "When the same torrent is opened and
99
105
       closed and opened again without quitting Transmission ...
100
106
       change the peerid. It would help sometimes if a stopped event
101
107
       was missed to ensure that we didn't think someone was cheating. */
102
 
    uint8_t * peer_id;
 
108
    uint8_t *  peer_id;
103
109
 
104
110
    /* these are set from the latest tracker response... -1 is 'unknown' */
105
 
    int timesDownloaded;
106
 
    int seederCount;
107
 
    int leecherCount;
108
 
    char * trackerID;
109
 
 
110
 
    time_t manualAnnounceAllowedAt;
111
 
    time_t reannounceAt;
112
 
    time_t scrapeAt;
113
 
 
114
 
    time_t lastScrapeTime;
115
 
    long lastScrapeResponse;
116
 
 
117
 
    time_t lastAnnounceTime;
118
 
    long lastAnnounceResponse;
 
111
    int       timesDownloaded;
 
112
    int       seederCount;
 
113
    int       downloaderCount;
 
114
    int       leecherCount;
 
115
    char *    trackerID;
 
116
 
 
117
    time_t    manualAnnounceAllowedAt;
 
118
    time_t    reannounceAt;
 
119
 
 
120
    /* 0==never, 1==in progress, other values==when to scrape */
 
121
    time_t    scrapeAt;
 
122
 
 
123
    time_t    lastScrapeTime;
 
124
    long      lastScrapeResponse;
 
125
 
 
126
    time_t    lastAnnounceTime;
 
127
    long      lastAnnounceResponse;
119
128
};
120
129
 
121
 
#define dbgmsg(name, fmt...) tr_deepLog(__FILE__, __LINE__, name, ##fmt )
 
130
#define dbgmsg( name, ... ) \
 
131
    do { \
 
132
        if( tr_deepLoggingIsActive( ) ) \
 
133
            tr_deepLog( __FILE__, __LINE__, name, __VA_ARGS__ ); \
 
134
    } while( 0 )
122
135
 
123
136
/***
124
137
****
125
138
***/
126
139
 
127
140
static const tr_tracker_info *
128
 
getCurrentAddressFromTorrent( const tr_tracker * t, const tr_torrent * tor )
 
141
getCurrentAddressFromTorrent( tr_tracker *       t,
 
142
                              const tr_torrent * tor )
129
143
{
 
144
    /* user might have removed trackers,
 
145
     * so check to make sure our current index is in-bounds */
 
146
    if( t->trackerIndex >= tor->info.trackerCount )
 
147
        t->trackerIndex = 0;
 
148
 
130
149
    assert( t->trackerIndex >= 0 );
131
150
    assert( t->trackerIndex < tor->info.trackerCount );
132
151
    return tor->info.trackers + t->trackerIndex;
133
152
}
134
 
    
 
153
 
135
154
static const tr_tracker_info *
136
 
getCurrentAddress( const tr_tracker * t )
 
155
getCurrentAddress( tr_tracker * t )
137
156
{
138
157
    const tr_torrent * torrent;
139
 
    if(( torrent = tr_torrentFindFromHash( t->session, t->hash )))
 
158
 
 
159
    if( ( torrent = tr_torrentFindFromId( t->session, t->torrentId ) ) )
140
160
        return getCurrentAddressFromTorrent( t, torrent );
141
161
    return NULL;
142
162
}
143
163
 
144
164
static int
145
 
trackerSupportsScrape( const tr_tracker * t, const tr_torrent * tor )
 
165
trackerSupportsScrape( tr_tracker *       t,
 
166
                       const tr_torrent * tor )
146
167
{
147
168
    const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
 
169
 
148
170
    return info && info->scrape;
149
171
}
150
172
 
152
174
****
153
175
***/
154
176
 
155
 
tr_tracker *
156
 
findTracker( tr_session * session, const uint8_t * hash )
 
177
static tr_tracker *
 
178
findTracker( tr_session * session, int torrentId )
157
179
{
158
 
    tr_torrent * torrent = tr_torrentFindFromHash( session, hash );
 
180
    tr_torrent * torrent = tr_torrentFindFromId( session, torrentId );
 
181
 
159
182
    return torrent ? torrent->tracker : NULL;
160
183
}
161
184
 
163
186
****  PUBLISH
164
187
***/
165
188
 
166
 
static const tr_tracker_event emptyEvent = { 0, NULL, NULL, NULL, 0, 0 };
 
189
static const tr_tracker_event emptyEvent = { 0, NULL, NULL, 0, 0 };
167
190
 
168
191
static void
169
 
publishMessage( tr_tracker * t, const char * msg, int type )
 
192
publishMessage( tr_tracker * t,
 
193
                const char * msg,
 
194
                int          type )
170
195
{
171
196
    if( t )
172
197
    {
173
198
        tr_tracker_event event = emptyEvent;
174
 
        event.hash = t->hash;
175
199
        event.messageType = type;
176
200
        event.text = msg;
177
 
        tr_publisherPublish( t->publisher, t, &event );
 
201
        tr_publisherPublish( &t->publisher, t, &event );
178
202
    }
179
203
}
180
204
 
185
209
}
186
210
 
187
211
static void
188
 
publishErrorMessageAndStop( tr_tracker * t, const char * msg )
 
212
publishErrorMessageAndStop( tr_tracker * t,
 
213
                            const char * msg )
189
214
{
190
215
    t->isRunning = 0;
191
216
    publishMessage( t, msg, TR_TRACKER_ERROR );
192
217
}
193
218
 
194
219
static void
195
 
publishWarning( tr_tracker * t, const char * msg )
 
220
publishWarning( tr_tracker * t,
 
221
                const char * msg )
196
222
{
197
223
    publishMessage( t, msg, TR_TRACKER_WARNING );
198
224
}
199
225
 
200
226
static void
201
 
publishNewPeers( tr_tracker * t, int allAreSeeds,
202
 
                 void * compact, int compactLen )
 
227
publishNewPeers( tr_tracker * t,
 
228
                 int          allAreSeeds,
 
229
                 void *       compact,
 
230
                 int          compactLen )
203
231
{
204
232
    tr_tracker_event event = emptyEvent;
205
 
    event.hash = t->hash;
 
233
 
206
234
    event.messageType = TR_TRACKER_PEERS;
207
235
    event.allAreSeeds = allAreSeeds;
208
236
    event.compact = compact;
209
237
    event.compactLen = compactLen;
210
238
    if( compactLen )
211
 
        tr_publisherPublish( t->publisher, t, &event );
 
239
        tr_publisherPublish( &t->publisher, t, &event );
 
240
}
 
241
 
 
242
static void
 
243
publishNewPeersCompact( tr_tracker * t,
 
244
                        int          allAreSeeds,
 
245
                        void       * compact,
 
246
                        int          compactLen )
 
247
{
 
248
    int i;
 
249
    uint8_t *array, *walk, *compactWalk;
 
250
    const int peerCount = compactLen / 6;
 
251
    const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
 
252
    tr_address addr;
 
253
    tr_port port;
 
254
    
 
255
    addr.type = TR_AF_INET;
 
256
    memset( &addr.addr, 0x00, sizeof( addr.addr ) );
 
257
    array = tr_new( uint8_t, arrayLen );
 
258
    for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
 
259
    {
 
260
        memcpy( &addr.addr.addr4, compactWalk, 4 );
 
261
        memcpy( &port, compactWalk + 4, 2 );
 
262
        
 
263
        memcpy( walk, &addr, sizeof( addr ) );
 
264
        memcpy( walk + sizeof( addr ), &port, 2 );
 
265
        
 
266
        walk += sizeof( tr_address ) + 2;
 
267
        compactWalk += 6;
 
268
    }
 
269
    publishNewPeers( t, allAreSeeds, array, arrayLen );
 
270
    tr_free( array );
 
271
}
 
272
 
 
273
static void
 
274
publishNewPeersCompact6( tr_tracker * t,
 
275
                         int          allAreSeeds,
 
276
                         void       * compact,
 
277
                         int          compactLen )
 
278
{
 
279
    int i;
 
280
    uint8_t *array, *walk, *compactWalk;
 
281
    const int peerCount = compactLen / 18;
 
282
    const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
 
283
    tr_address addr;
 
284
    tr_port port;
 
285
    
 
286
    addr.type = TR_AF_INET6;
 
287
    memset( &addr.addr, 0x00, sizeof( addr.addr ) );
 
288
    array = tr_new( uint8_t, arrayLen );
 
289
    for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
 
290
    {
 
291
        memcpy( &addr.addr.addr6, compactWalk, 16 );
 
292
        memcpy( &port, compactWalk + 16, 2 );
 
293
        compactWalk += 18;
 
294
        
 
295
        memcpy( walk, &addr, sizeof( addr ) );
 
296
        memcpy( walk + sizeof( addr ), &port, 2 );
 
297
        walk += sizeof( tr_address ) + 2;
 
298
    }
 
299
    publishNewPeers( t, allAreSeeds, array, arrayLen );
 
300
    tr_free( array );
212
301
}
213
302
 
214
303
/***
218
307
static void onReqDone( tr_session * session );
219
308
 
220
309
static int
221
 
updateAddresses( tr_tracker  * t, int success )
 
310
updateAddresses( tr_tracker * t,
 
311
                 int          success )
222
312
{
223
 
    int retry;
 
313
    int          retry;
224
314
 
225
315
    tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );
226
316
 
231
321
        t->trackerIndex = tr_torrentPromoteTracker( torrent, t->trackerIndex );
232
322
        retry = FALSE; /* we succeeded; no need to retry */
233
323
    }
234
 
    else if ( ++t->trackerIndex >= torrent->info.trackerCount )
 
324
    else if( ++t->trackerIndex >= torrent->info.trackerCount )
235
325
    {
236
326
        t->trackerIndex = 0;
237
327
        retry = FALSE; /* we've tried them all */
246
336
    return retry;
247
337
}
248
338
 
249
 
/* Convert to compact form */
250
339
static uint8_t *
251
 
parseOldPeers( tr_benc * bePeers, size_t * byteCount )
 
340
parseOldPeers( tr_benc * bePeers,
 
341
               size_t *  byteCount )
252
342
{
253
 
    int i;
254
 
    uint8_t *compact, *walk;
 
343
    int       i;
 
344
    uint8_t * array, *walk;
255
345
    const int peerCount = bePeers->val.l.count;
256
346
 
257
 
    assert( bePeers->type == TYPE_LIST );
258
 
 
259
 
    compact = tr_new( uint8_t, peerCount*6 );
260
 
 
261
 
    for( i=0, walk=compact; i<peerCount; ++i )
 
347
    assert( tr_bencIsList( bePeers ) );
 
348
 
 
349
    array = tr_new( uint8_t, peerCount * ( sizeof( tr_address ) + 2 ) );
 
350
 
 
351
    for( i = 0, walk = array; i < peerCount; ++i )
262
352
    {
263
353
        const char * s;
264
 
        int64_t itmp;
265
 
        struct in_addr addr;
266
 
        tr_port_t port;
267
 
        tr_benc * peer = &bePeers->val.l.vals[i];
268
 
 
269
 
        if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) )
270
 
            continue;
271
 
 
272
 
        memcpy( walk, &addr, 4 );
273
 
        walk += 4;
274
 
 
275
 
        if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp<0 || itmp>0xffff )
276
 
            continue;
277
 
 
 
354
        int64_t      itmp;
 
355
        tr_address   addr;
 
356
        tr_port      port;
 
357
        tr_benc    * peer = &bePeers->val.l.vals[i];
 
358
 
 
359
        if( tr_bencDictFindStr( peer, "ip", &s ) )
 
360
        {
 
361
            if( tr_pton( s, &addr ) == NULL )
 
362
                continue;
 
363
        }
 
364
        if( !tr_bencDictFindInt( peer, "port",
 
365
                                 &itmp ) || itmp < 0 || itmp > 0xffff )
 
366
            continue;
 
367
 
 
368
        memcpy( walk, &addr, sizeof( tr_address ) );
278
369
        port = htons( itmp );
279
 
        memcpy( walk, &port, 2 );
280
 
        walk += 2;
 
370
        memcpy( walk + sizeof( tr_address ), &port, 2 );
 
371
        walk += sizeof( tr_address ) + 2;
281
372
    }
282
373
 
283
 
    *byteCount = peerCount * 6;
284
 
    return compact;
 
374
    *byteCount = peerCount * sizeof( tr_address ) + 2;
 
375
    return array;
285
376
}
286
377
 
287
378
static void
288
379
onStoppedResponse( tr_session    * session,
289
 
                   long            responseCode  UNUSED,
290
 
                   const void    * response      UNUSED,
291
 
                   size_t          responseLen   UNUSED,
292
 
                   void          * torrent_hash )
 
380
                   long            responseCode UNUSED,
 
381
                   const void    * response     UNUSED,
 
382
                   size_t          responseLen  UNUSED,
 
383
                   void          * torrentId )
293
384
{
 
385
    tr_tracker * t = findTracker( session, tr_ptr2int( torrentId ) );
 
386
    if( t )
 
387
    {
 
388
        const time_t now = time( NULL );
 
389
 
 
390
        t->reannounceAt = TR_TRACKER_STOPPED;
 
391
        t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
 
392
 
 
393
        if( t->scrapeAt <= now )
 
394
            t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
 
395
    }
 
396
 
294
397
    dbgmsg( NULL, "got a response to some `stop' message" );
295
 
    tr_free( torrent_hash );
296
398
    onReqDone( session );
297
399
}
298
400
 
299
401
static void
300
 
onTrackerResponse( tr_session    * session,
301
 
                   long            responseCode,
302
 
                   const void    * response,
303
 
                   size_t          responseLen,
304
 
                   void          * torrent_hash )
 
402
onTrackerResponse( tr_session * session,
 
403
                   long         responseCode,
 
404
                   const void * response,
 
405
                   size_t       responseLen,
 
406
                   void       * torrentId )
305
407
{
306
408
    int retry;
307
409
    int success = FALSE;
 
410
    int scrapeFields = 0;
308
411
    tr_tracker * t;
309
412
 
310
413
    onReqDone( session );
311
 
    t = findTracker( session, torrent_hash );
312
 
    tr_free( torrent_hash );
 
414
    t = findTracker( session, tr_ptr2int( torrentId ) );
313
415
    if( !t ) /* tracker's been closed */
314
416
        return;
315
417
 
316
 
    dbgmsg( t->name, "tracker response: %d", responseCode );
317
 
    tr_ndbg( t->name, "tracker response: %d", responseCode );
 
418
    dbgmsg( t->name, "tracker response: %ld", responseCode );
 
419
    tr_ndbg( t->name, "tracker response: %ld", responseCode );
318
420
    t->lastAnnounceResponse = responseCode;
319
421
 
320
422
    if( responseCode == HTTP_OK )
321
423
    {
322
 
        tr_benc benc;
323
 
        const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
 
424
        tr_benc   benc;
 
425
        const int bencLoaded = !tr_bencLoad( response, responseLen,
 
426
                                             &benc, NULL );
324
427
        publishErrorClear( t );
325
428
        if( bencLoaded && tr_bencIsDict( &benc ) )
326
429
        {
327
 
            tr_benc * tmp;
328
 
            int64_t i;
329
 
            int incomplete = -1;
 
430
            tr_benc *    tmp;
 
431
            int64_t      i;
 
432
            int          incomplete = -1;
330
433
            const char * str;
331
434
 
332
435
            success = TRUE;
 
436
            t->retryAnnounceIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
333
437
 
334
 
            if(( tr_bencDictFindStr( &benc, "failure reason", &str ))) {
335
 
               // publishErrorMessageAndStop( t, str );
 
438
            if( ( tr_bencDictFindStr( &benc, "failure reason", &str ) ) )
 
439
            {
336
440
                publishMessage( t, str, TR_TRACKER_ERROR );
337
441
                success = FALSE;
338
442
            }
339
443
 
340
 
            if(( tr_bencDictFindStr( &benc, "warning message", &str )))
 
444
            if( ( tr_bencDictFindStr( &benc, "warning message", &str ) ) )
341
445
                publishWarning( t, str );
342
446
 
343
 
            if(( tr_bencDictFindInt( &benc, "interval", &i ))) {
 
447
            if( ( tr_bencDictFindInt( &benc, "interval", &i ) ) )
 
448
            {
344
449
                dbgmsg( t->name, "setting interval to %d", (int)i );
345
450
                t->announceIntervalSec = i;
346
451
            }
347
452
 
348
 
            if(( tr_bencDictFindInt( &benc, "min interval", &i ))) {
 
453
            if( ( tr_bencDictFindInt( &benc, "min interval", &i ) ) )
 
454
            {
349
455
                dbgmsg( t->name, "setting min interval to %d", (int)i );
350
456
                t->announceMinIntervalSec = i;
351
457
            }
352
458
 
353
 
            if(( tr_bencDictFindStr( &benc, "tracker id", &str )))
 
459
            if( ( tr_bencDictFindStr( &benc, "tracker id", &str ) ) )
354
460
                t->trackerID = tr_strdup( str );
355
461
 
356
 
            if(( tr_bencDictFindInt( &benc, "complete", &i )))
 
462
            if( ( tr_bencDictFindInt( &benc, "complete", &i ) ) )
 
463
            {
 
464
                ++scrapeFields;
357
465
                t->seederCount = i;
 
466
            }
358
467
 
359
 
            if(( tr_bencDictFindInt( &benc, "incomplete", &i )))
 
468
            if( ( tr_bencDictFindInt( &benc, "incomplete", &i ) ) )
 
469
            {
 
470
                ++scrapeFields;
360
471
                t->leecherCount = incomplete = i;
361
 
 
362
 
            if(( tmp = tr_bencDictFind( &benc, "peers" )))
363
 
            {
364
 
                const int allAreSeeds = incomplete == 0;
365
 
 
366
 
                if( tmp->type == TYPE_STR ) /* "compact" extension */
367
 
                {
368
 
                    publishNewPeers( t, allAreSeeds, tmp->val.s.s, tmp->val.s.i );
369
 
                }
370
 
                else if( tmp->type == TYPE_LIST ) /* original protocol */
371
 
                {
372
 
                    size_t byteCount = 0;
373
 
                    uint8_t * compact = parseOldPeers( tmp, &byteCount );
374
 
                    publishNewPeers( t, allAreSeeds, compact, byteCount );
375
 
                    tr_free( compact );
 
472
            }
 
473
 
 
474
            if( ( tr_bencDictFindInt( &benc, "downloaded", &i ) ) )
 
475
            {
 
476
                ++scrapeFields;
 
477
                t->timesDownloaded = i;
 
478
            }
 
479
 
 
480
            if( ( tmp = tr_bencDictFind( &benc, "peers" ) ) )
 
481
            {
 
482
                const int allAreSeeds = incomplete == 0;
 
483
 
 
484
                if( tr_bencIsString( tmp ) ) /* "compact" extension */
 
485
                {
 
486
                    publishNewPeersCompact( t, allAreSeeds, tmp->val.s.s,
 
487
                                            tmp->val.s.i );
 
488
                }
 
489
                else if( tr_bencIsList( tmp ) ) /* original protocol */
 
490
                {
 
491
                    size_t    byteCount = 0;
 
492
                    uint8_t * array = parseOldPeers( tmp, &byteCount );
 
493
                    publishNewPeers( t, allAreSeeds, array, byteCount );
 
494
                    tr_free( array );
 
495
                }
 
496
            }
 
497
            
 
498
            if( ( tmp = tr_bencDictFind( &benc, "peers6" ) ) )
 
499
            {
 
500
                const int allAreSeeds = incomplete == 0;
 
501
                
 
502
                if( tr_bencIsString( tmp ) ) /* "compact" extension */
 
503
                {
 
504
                    publishNewPeersCompact6( t, allAreSeeds, tmp->val.s.s,
 
505
                                             tmp->val.s.i );
376
506
                }
377
507
            }
378
508
        }
380
510
        if( bencLoaded )
381
511
            tr_bencFree( &benc );
382
512
    }
 
513
    else if( responseCode )
 
514
    {
 
515
        /* %1$ld - http status code, such as 404
 
516
         * %2$s - human-readable explanation of the http status code */
 
517
        char * buf = tr_strdup_printf( _( "Tracker request failed.  Got HTTP Status Code %1$ld (%2$s)" ),
 
518
                                      responseCode,
 
519
                                      tr_webGetResponseStr( responseCode ) );
 
520
        publishWarning( t, buf );
 
521
        tr_free( buf );
 
522
    }
383
523
 
384
524
    retry = updateAddresses( t, success );
385
525
 
386
 
    /**
387
 
    ***
388
 
    **/
389
 
 
390
 
    if( retry )
 
526
    if( responseCode && retry )
391
527
        responseCode = 300;
392
528
 
393
 
    if( 200<=responseCode && responseCode<=299 )
394
 
    {
395
 
        const int interval = t->announceIntervalSec + t->randOffset;
 
529
    if( responseCode == 0 )
 
530
    {
 
531
        dbgmsg( t->name, "No response from tracker... retrying in two minutes." );
 
532
        t->manualAnnounceAllowedAt = ~(time_t)0;
 
533
        t->reannounceAt = time( NULL ) + t->randOffset + 120;
 
534
    }
 
535
    else if( 200 <= responseCode && responseCode <= 299 )
 
536
    {
 
537
        const int    interval = t->announceIntervalSec + t->randOffset;
396
538
        const time_t now = time ( NULL );
397
539
        dbgmsg( t->name, "request succeeded. reannouncing in %d seconds", interval );
398
 
        t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
 
540
 
 
541
        /* if the announce response was a superset of the scrape response,
 
542
           treat this as both a successful announce AND scrape. */
 
543
        if( scrapeFields >= 3 ) {
 
544
            t->lastScrapeResponse = responseCode;
 
545
            t->lastScrapeTime = now;
 
546
            t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
 
547
        }
 
548
 
 
549
        /* most trackers don't provide all the scrape responses, but do
 
550
           provide most of them, so don't scrape too soon anyway */
 
551
        if( ( scrapeFields == 2 ) && ( t->scrapeAt <= ( now + 120 ) ) ) {
 
552
            t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
 
553
        }
 
554
 
399
555
        t->reannounceAt = now + interval;
400
556
        t->manualAnnounceAllowedAt = now + t->announceMinIntervalSec;
 
557
 
 
558
        /* #319: save the .resume file after an announce so that, in case
 
559
         * of a crash, our stats still match up with the tracker's stats */
 
560
        tr_torrentSaveResume( tr_torrentFindFromHash( t->session, t->hash ) );
401
561
    }
402
 
    else if( 300<=responseCode && responseCode<=399 )
 
562
    else if( 300 <= responseCode && responseCode <= 399 )
403
563
    {
404
564
        /* it's a redirect... updateAddresses() has already
405
565
         * parsed the redirect, all that's left is to retry */
408
568
        t->reannounceAt = time( NULL ) + interval;
409
569
        t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
410
570
    }
411
 
    else if( 400<=responseCode && responseCode<=499 )
 
571
    else if( 400 <= responseCode && responseCode <= 499 )
412
572
    {
413
573
        /* The request could not be understood by the server due to
414
574
         * malformed syntax. The client SHOULD NOT repeat the
415
575
         * request without modifications. */
416
576
        publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
417
577
        t->manualAnnounceAllowedAt = ~(time_t)0;
418
 
        t->reannounceAt = 0;
 
578
        t->reannounceAt = TR_TRACKER_STOPPED;
419
579
    }
420
 
    else if( 500<=responseCode && responseCode<=599 )
 
580
    else if( 500 <= responseCode && responseCode <= 599 )
421
581
    {
422
582
        /* Response status codes beginning with the digit "5" indicate
423
583
         * cases in which the server is aware that it has erred or is
424
584
         * incapable of performing the request.  So we pause a bit and
425
585
         * try again. */
426
586
        t->manualAnnounceAllowedAt = ~(time_t)0;
427
 
        t->reannounceAt = time( NULL ) + 60;
 
587
        t->reannounceAt = time( NULL ) + t->retryAnnounceIntervalSec;
 
588
        t->retryAnnounceIntervalSec *= 2;
428
589
    }
429
590
    else
430
591
    {
436
597
}
437
598
 
438
599
static void
439
 
onScrapeResponse( tr_session   * session,
440
 
                  long           responseCode,
441
 
                  const void   * response,
442
 
                  size_t         responseLen,
443
 
                  void         * torrent_hash )
 
600
onScrapeResponse( tr_session * session,
 
601
                  long         responseCode,
 
602
                  const void * response,
 
603
                  size_t       responseLen,
 
604
                  void       * torrentId )
444
605
{
445
 
    int success = FALSE;
446
 
    int retry;
 
606
    int          success = FALSE;
 
607
    int          retry;
447
608
    tr_tracker * t;
448
609
 
449
610
    onReqDone( session );
450
 
    t = findTracker( session, torrent_hash );
451
 
    tr_free( torrent_hash );
 
611
    t = findTracker( session, tr_ptr2int( torrentId ) );
452
612
    if( !t ) /* tracker's been closed... */
453
613
        return;
454
614
 
455
615
    dbgmsg( t->name, "scrape response: %ld\n", responseCode );
456
 
    tr_ndbg( t->name, "scrape response: %d", responseCode );
 
616
    tr_ndbg( t->name, "scrape response: %ld", responseCode );
457
617
    t->lastScrapeResponse = responseCode;
458
618
 
459
619
    if( responseCode == HTTP_OK )
460
620
    {
461
 
        tr_benc benc, *files;
462
 
        const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
 
621
        tr_benc   benc, *files;
 
622
        const int bencLoaded = !tr_bencLoad( response, responseLen,
 
623
                                             &benc, NULL );
463
624
        if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
464
625
        {
465
 
            int i;
466
 
            for( i=0; i<files->val.l.count; i+=2 )
 
626
            size_t i;
 
627
            for( i = 0; i < files->val.l.count; i += 2 )
467
628
            {
468
 
                int64_t itmp;
 
629
                int64_t        itmp;
469
630
                const uint8_t* hash =
470
631
                    (const uint8_t*) files->val.l.vals[i].val.s.s;
471
 
                tr_benc * flags;
472
 
                tr_benc * tordict = &files->val.l.vals[i+1];
 
632
                tr_benc *      flags;
 
633
                tr_benc *      tordict = &files->val.l.vals[i + 1];
473
634
                if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
474
635
                    continue;
475
636
 
476
637
                publishErrorClear( t );
477
638
 
478
 
                if(( tr_bencDictFindInt( tordict, "complete", &itmp )))
 
639
                if( ( tr_bencDictFindInt( tordict, "complete", &itmp ) ) )
479
640
                    t->seederCount = itmp;
480
641
 
481
 
                if(( tr_bencDictFindInt( tordict, "incomplete", &itmp )))
 
642
                if( ( tr_bencDictFindInt( tordict, "incomplete", &itmp ) ) )
482
643
                    t->leecherCount = itmp;
483
644
 
484
 
                if(( tr_bencDictFindInt( tordict, "downloaded", &itmp )))
 
645
                if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) )
485
646
                    t->timesDownloaded = itmp;
486
647
 
487
 
                if( tr_bencDictFindDict( tordict, "flags", &flags ))
488
 
                    if(( tr_bencDictFindInt( flags, "min_request_interval", &itmp )))
 
648
                if( ( tr_bencDictFindInt( tordict, "downloaders", &itmp ) ) )
 
649
                    t->downloaderCount = itmp;
 
650
 
 
651
                if( tr_bencDictFindDict( tordict, "flags", &flags ) )
 
652
                    if( ( tr_bencDictFindInt( flags, "min_request_interval", &itmp ) ) )
489
653
                        t->scrapeIntervalSec = i;
490
654
 
 
655
                /* as per ticket #1045, safeguard against trackers returning
 
656
                 * a very low min_request_interval... */
 
657
                if( t->scrapeIntervalSec < DEFAULT_SCRAPE_INTERVAL_SEC )
 
658
                    t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
 
659
 
 
660
                tr_ndbg( t->name,
 
661
                         "Scrape successful. Rescraping in %d seconds.",
 
662
                         t->scrapeIntervalSec );
 
663
 
491
664
                success = TRUE;
492
 
 
493
 
                tr_ndbg( t->name, "Scrape successful.  Rescraping in %d seconds.",
494
 
                         t->scrapeIntervalSec );
495
 
 
496
 
                t->retryScrapeIntervalSec = 30;
 
665
                t->retryScrapeIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
497
666
            }
498
667
        }
499
668
 
510
679
    if( retry )
511
680
        responseCode = 300;
512
681
 
513
 
    if( 200<=responseCode && responseCode<=299 )
 
682
    if( 200 <= responseCode && responseCode <= 299 )
514
683
    {
515
684
        const int interval = t->scrapeIntervalSec + t->randOffset;
516
 
        dbgmsg( t->name, "request succeeded. rescraping in %d seconds", interval );
517
 
        tr_ndbg( t->name, "request succeeded. rescraping in %d seconds", interval );
 
685
        dbgmsg( t->name, "Request succeeded. Rescraping in %d seconds",
 
686
                interval );
 
687
        tr_ndbg( t->name, "Request succeeded. Rescraping in %d seconds",
 
688
                 interval );
518
689
        t->scrapeAt = time( NULL ) + interval;
519
690
    }
520
 
    else if( 300<=responseCode && responseCode<=399 )
 
691
    else if( 300 <= responseCode && responseCode <= 399 )
521
692
    {
522
693
        const int interval = 5;
523
 
        dbgmsg( t->name, "got a redirect. retrying in %d seconds", interval );
 
694
        dbgmsg( t->name, "Got a redirect. Retrying in %d seconds", interval );
524
695
        t->scrapeAt = time( NULL ) + interval;
525
696
    }
526
697
    else
527
698
    {
528
699
        const int interval = t->retryScrapeIntervalSec + t->randOffset;
529
 
        dbgmsg( t->name, "Tracker responded to scrape with %d.  Retrying in %d seconds.",
530
 
                   responseCode,  interval );
 
700
        dbgmsg(
 
701
            t->name,
 
702
            "Tracker responded to scrape with %ld. Retrying in %d seconds.",
 
703
            responseCode,  interval );
531
704
        t->retryScrapeIntervalSec *= 2;
532
705
        t->scrapeAt = time( NULL ) + interval;
533
706
    }
542
715
    TR_REQ_STARTED,
543
716
    TR_REQ_COMPLETED,
544
717
    TR_REQ_STOPPED,
 
718
    TR_REQ_PAUSED,     /* BEP 21 */
545
719
    TR_REQ_REANNOUNCE,
546
720
    TR_REQ_SCRAPE,
547
 
    TR_REQ_COUNT
 
721
    TR_NUM_REQ_TYPES
548
722
};
549
723
 
550
724
struct tr_tracker_request
551
725
{
552
 
    char * url;
553
 
    int reqtype; /* TR_REQ_* */
554
 
    uint8_t torrent_hash[SHA_DIGEST_LENGTH];
555
 
    tr_web_done_func * done_func;
556
 
    tr_session * session;
 
726
    int                 reqtype; /* TR_REQ_* */
 
727
    int                 torrentId;
 
728
    struct evbuffer   * url;
 
729
    tr_web_done_func  * done_func;
 
730
    tr_session *        session;
557
731
};
558
732
 
559
733
static void
560
734
freeRequest( struct tr_tracker_request * req )
561
735
{
562
 
    tr_free( req->url );
 
736
    evbuffer_free( req->url );
563
737
    tr_free( req );
564
738
}
565
739
 
566
740
static void
567
 
buildTrackerRequestURI( const tr_tracker  * t,
568
 
                        const tr_torrent  * torrent,
569
 
                        const char        * eventName,
570
 
                        struct evbuffer   * buf )
 
741
buildTrackerRequestURI( tr_tracker *       t,
 
742
                        const tr_torrent * torrent,
 
743
                        const char *       eventName,
 
744
                        struct evbuffer *  buf )
571
745
{
572
 
    const int isStopping = !strcmp( eventName, "stopped" );
573
 
    const int numwant = isStopping ? 0 : NUMWANT;
574
 
    const char * ann = getCurrentAddressFromTorrent(t,torrent)->announce;
575
 
    
 
746
    const int    isStopping = !strcmp( eventName, "stopped" );
 
747
    const int    numwant = isStopping ? 0 : NUMWANT;
 
748
    const char * ann = getCurrentAddressFromTorrent( t, torrent )->announce;
 
749
 
576
750
    evbuffer_add_printf( buf, "%cinfo_hash=%s"
577
751
                              "&peer_id=%s"
578
752
                              "&port=%d"
579
 
                              "&uploaded=%"PRIu64
580
 
                              "&downloaded=%"PRIu64
581
 
                              "&corrupt=%"PRIu64
582
 
                              "&left=%"PRIu64
 
753
                              "&uploaded=%" PRIu64
 
754
                              "&downloaded=%" PRIu64
 
755
                              "&corrupt=%" PRIu64
 
756
                              "&left=%" PRIu64
583
757
                              "&compact=1"
584
758
                              "&numwant=%d"
585
 
                              "&key=%s"
586
 
                              "%s%s"
587
 
                              "%s%s",
588
 
        strchr(ann, '?') ? '&' : '?',
589
 
        t->escaped,
590
 
        t->peer_id,
591
 
        tr_sharedGetPublicPort( t->session->shared ),
592
 
        torrent->uploadedCur,
593
 
        torrent->downloadedCur,
594
 
        torrent->corruptCur,
595
 
        tr_cpLeftUntilComplete( torrent->completion ),
596
 
        numwant,
597
 
        t->key_param,
598
 
        ( ( eventName && *eventName ) ? "&event=" : "" ),
599
 
        ( ( eventName && *eventName ) ? eventName : "" ),
600
 
        ( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
601
 
        ( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
 
759
                              "&key=%s",
 
760
                              strchr( ann, '?' ) ? '&' : '?',
 
761
                              t->escaped,
 
762
                              t->peer_id,
 
763
                              tr_sessionGetPeerPort( t->session ),
 
764
                              torrent->uploadedCur,
 
765
                              torrent->downloadedCur,
 
766
                              torrent->corruptCur,
 
767
                              tr_cpLeftUntilComplete( &torrent->completion ),
 
768
                              numwant,
 
769
                              t->key_param );
 
770
 
 
771
    if( eventName && *eventName )
 
772
        evbuffer_add_printf( buf, "&event=%s", eventName );
 
773
 
 
774
    if( t->trackerID && *t->trackerID )
 
775
        evbuffer_add_printf( buf, "&trackerid=%s", t->trackerID );
 
776
 
602
777
}
603
778
 
604
779
static struct tr_tracker_request*
605
 
createRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
 
780
createRequest( tr_session * session,
 
781
               tr_tracker * tracker,
 
782
               int          reqtype )
606
783
{
607
 
    static const char* strings[] = { "started", "completed", "stopped", "", "err" };
 
784
    static const char* strings[] = { "started", "completed", "stopped", "paused", "", "err" };
608
785
    const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
609
786
    const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
610
 
    const int isStopping = reqtype == TR_REQ_STOPPED;
 
787
    int isStopping;
611
788
    struct tr_tracker_request * req;
612
789
    struct evbuffer * url;
613
790
 
 
791
    /* BEP 21: In order to tell the tracker that a peer is a partial seed, it MUST send
 
792
     * an event=paused parameter in every announce while it is a partial seed. */
 
793
    if( tr_cpGetStatus( &torrent->completion ) == TR_PARTIAL_SEED )
 
794
        reqtype = TR_REQ_PAUSED;
 
795
 
 
796
    isStopping = reqtype == TR_REQ_STOPPED;
 
797
 
614
798
    url = evbuffer_new( );
615
799
    evbuffer_add_printf( url, "%s", address->announce );
616
800
    buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
619
803
    req->session = session;
620
804
    req->reqtype = reqtype;
621
805
    req->done_func =  isStopping ? onStoppedResponse : onTrackerResponse;
622
 
    req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
623
 
    memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
 
806
    req->url = url;
 
807
    req->torrentId = tracker->torrentId;
624
808
 
625
 
    evbuffer_free( url );
626
809
    return req;
627
810
}
628
811
 
629
812
static struct tr_tracker_request*
630
 
createScrape( tr_session * session, const tr_tracker * tracker )
 
813
createScrape( tr_session * session,
 
814
              tr_tracker * tracker )
631
815
{
632
 
    const tr_tracker_info * a = getCurrentAddress( tracker );
 
816
    const tr_tracker_info *     a = getCurrentAddress( tracker );
633
817
    struct tr_tracker_request * req;
634
 
    struct evbuffer * url = evbuffer_new( );
 
818
    struct evbuffer *           url = evbuffer_new( );
635
819
 
636
820
    evbuffer_add_printf( url, "%s%cinfo_hash=%s",
637
 
                         a->scrape, strchr(a->scrape,'?')?'&':'?',
638
 
                         tracker->escaped ); 
 
821
                         a->scrape, strchr( a->scrape, '?' ) ? '&' : '?',
 
822
                         tracker->escaped );
639
823
 
640
824
    req = tr_new0( struct tr_tracker_request, 1 );
641
825
    req->session = session;
642
826
    req->reqtype = TR_REQ_SCRAPE;
643
 
    req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
 
827
    req->url = url;
644
828
    req->done_func = onScrapeResponse;
645
 
    memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
 
829
    req->torrentId = tracker->torrentId;
646
830
 
647
 
    evbuffer_free( url );
648
831
    return req;
649
832
}
650
833
 
651
834
struct tr_tracker_handle
652
835
{
653
 
    unsigned int isShuttingDown : 1;
654
 
    int runningCount;
655
 
    tr_timer * pulseTimer;
 
836
    tr_bool     shutdownHint;
 
837
    int         runningCount;
 
838
    tr_timer *  pulseTimer;
656
839
};
657
840
 
658
 
static int pulse( void * vsession );
 
841
static int trackerPulse( void * vsession );
 
842
 
 
843
void
 
844
tr_trackerSessionInit( tr_session * session )
 
845
{
 
846
    assert( tr_isSession( session ) );
 
847
 
 
848
    session->tracker = tr_new0( struct tr_tracker_handle, 1 );
 
849
    session->tracker->pulseTimer = tr_timerNew( session, trackerPulse, session, PULSE_INTERVAL_MSEC );
 
850
    dbgmsg( NULL, "creating tracker timer" );
 
851
}
 
852
 
 
853
void
 
854
tr_trackerSessionClose( tr_session * session )
 
855
{
 
856
    assert( tr_isSession( session ) );
 
857
 
 
858
    session->tracker->shutdownHint = TRUE;
 
859
}
659
860
 
660
861
static void
661
 
ensureGlobalsExist( tr_session * session )
662
 
{
663
 
    if( session->tracker == NULL )
664
 
    {
665
 
        session->tracker = tr_new0( struct tr_tracker_handle, 1 );
666
 
        session->tracker->pulseTimer = tr_timerNew( session, pulse, session, PULSE_INTERVAL_MSEC );
667
 
        dbgmsg( NULL, "creating tracker timer" );
668
 
    }
669
 
}
670
 
 
671
 
void
672
 
tr_trackerShuttingDown( tr_session * session )
673
 
{
674
 
    if( session->tracker )
675
 
        session->tracker->isShuttingDown = 1;
676
 
}
677
 
 
678
 
static int
679
 
maybeFreeGlobals( tr_session * session )
680
 
{
681
 
    int globalsExist = session->tracker != NULL;
682
 
 
683
 
    if( globalsExist
684
 
        && ( session->tracker->runningCount < 1 )
685
 
        && ( session->torrentList== NULL ) )
 
862
tr_trackerSessionDestroy( tr_session * session )
 
863
{
 
864
    if( session && session->tracker )
686
865
    {
687
866
        dbgmsg( NULL, "freeing tracker timer" );
688
867
        tr_timerFree( &session->tracker->pulseTimer );
689
868
        tr_free( session->tracker );
690
869
        session->tracker = NULL;
691
 
        globalsExist = FALSE;
692
870
    }
693
 
 
694
 
    return globalsExist;
695
871
}
696
872
 
697
873
/***
702
878
invokeRequest( void * vreq )
703
879
{
704
880
    struct tr_tracker_request * req = vreq;
705
 
    uint8_t * hash;
706
 
    tr_tracker * t = findTracker( req->session, req->torrent_hash );
707
 
 
708
 
    if( t )
 
881
    tr_tracker * t;
 
882
 
 
883
    assert( req != NULL );
 
884
    assert( tr_isSession( req->session ) );
 
885
    assert( req->torrentId >= 0 );
 
886
    assert( req->reqtype >= 0 );
 
887
    assert( req->reqtype < TR_NUM_REQ_TYPES );
 
888
 
 
889
    dbgmsg( NULL, "invokeRequest got session %p, tracker %p", req->session, req->session->tracker );
 
890
 
 
891
    t = findTracker( req->session, req->torrentId );
 
892
 
 
893
    if( t != NULL )
709
894
    {
710
895
        const time_t now = time( NULL );
711
896
 
712
897
        if( req->reqtype == TR_REQ_SCRAPE )
713
898
        {
714
899
            t->lastScrapeTime = now;
715
 
            t->scrapeAt = 0;
 
900
            t->scrapeAt = TR_TRACKER_BUSY;
716
901
        }
717
902
        else
718
903
        {
719
904
            t->lastAnnounceTime = now;
720
 
            t->reannounceAt = 0;
721
 
            t->scrapeAt = req->reqtype == TR_REQ_STOPPED
722
 
                        ? now + t->scrapeIntervalSec + t->randOffset
723
 
                        : 0;
 
905
            t->reannounceAt = TR_TRACKER_BUSY;
 
906
            t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
724
907
        }
725
908
    }
726
909
 
 
910
    assert( req->session->tracker != NULL );
727
911
    ++req->session->tracker->runningCount;
728
912
 
729
 
    hash = tr_new0( uint8_t, SHA_DIGEST_LENGTH );
730
 
    memcpy( hash, req->torrent_hash, SHA_DIGEST_LENGTH );
731
 
    tr_webRun( req->session, req->url, req->done_func, hash );
 
913
    tr_webRun( req->session,
 
914
               (char*)EVBUFFER_DATA(req->url),
 
915
               NULL,
 
916
               req->done_func, tr_int2ptr( req->torrentId ) );
732
917
 
733
918
    freeRequest( req );
734
919
}
735
920
 
736
 
static void ensureGlobalsExist( tr_session * );
737
 
 
738
921
static void
739
 
enqueueScrape( tr_session * session, const tr_tracker * tracker )
 
922
enqueueScrape( tr_session * session,
 
923
               tr_tracker * tracker )
740
924
{
741
925
    struct tr_tracker_request * req;
742
 
    ensureGlobalsExist( session );
 
926
    assert( tr_isSession( session ) );
 
927
 
743
928
    req = createScrape( session, tracker );
744
929
    tr_runInEventThread( session, invokeRequest, req );
745
930
}
746
931
 
747
932
static void
748
 
enqueueRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
 
933
enqueueRequest( tr_session * session,
 
934
                tr_tracker * tracker,
 
935
                int          reqtype )
749
936
{
750
937
    struct tr_tracker_request * req;
751
 
    ensureGlobalsExist( session );
 
938
    assert( tr_isSession( session ) );
 
939
 
752
940
    req = createRequest( session, tracker, reqtype );
753
941
    tr_runInEventThread( session, invokeRequest, req );
754
942
}
755
943
 
756
944
static int
757
 
pulse( void * vsession )
 
945
trackerPulse( void * vsession )
758
946
{
759
 
    tr_session * session = vsession;
 
947
    tr_session *               session = vsession;
760
948
    struct tr_tracker_handle * th = session->tracker;
761
 
    tr_torrent * tor;
762
 
    const time_t now = time( NULL );
 
949
    tr_torrent *               tor;
 
950
    const time_t               now = time( NULL );
763
951
 
764
 
    if( !session->tracker )
 
952
    if( !th )
765
953
        return FALSE;
766
954
 
767
955
    if( th->runningCount )
768
956
        dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
769
957
 
770
958
    /* upkeep: queue periodic rescrape / reannounce */
771
 
    for( tor=session->torrentList; tor; tor=tor->next )
 
959
    tor = NULL;
 
960
    while(( tor = tr_torrentNext( session, tor )))
772
961
    {
773
962
        tr_tracker * t = tor->tracker;
774
963
 
775
 
        if( t->scrapeAt && trackerSupportsScrape( t, tor ) && ( now >= t->scrapeAt ) ) {
776
 
            t->scrapeAt = 0;
 
964
        if( ( t->scrapeAt > 1 )
 
965
          && ( t->scrapeAt <= now )
 
966
          && ( trackerSupportsScrape( t, tor ) ) )
 
967
        {
 
968
            t->scrapeAt = TR_TRACKER_BUSY;
777
969
            enqueueScrape( session, t );
778
970
        }
779
971
 
780
 
        if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
781
 
            t->reannounceAt = 0;
 
972
        if( ( t->reannounceAt > 1 )
 
973
          && ( t->reannounceAt <= now )
 
974
          && ( t->isRunning ) )
 
975
        {
 
976
            t->reannounceAt = TR_TRACKER_BUSY;
 
977
            t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
782
978
            enqueueRequest( session, t, TR_REQ_REANNOUNCE );
783
979
        }
784
980
    }
785
981
 
786
982
    if( th->runningCount )
787
 
        dbgmsg( NULL, "tracker pulse after upkeep... %d running", th->runningCount );
788
 
 
789
 
    return maybeFreeGlobals( session );
 
983
        dbgmsg( NULL, "tracker pulse after upkeep... %d running",
 
984
                th->runningCount );
 
985
 
 
986
    /* free the tracker manager if no torrents are left */
 
987
    if(    ( th != NULL )
 
988
        && ( th->shutdownHint != FALSE )
 
989
        && ( th->runningCount < 1 )
 
990
        && ( tr_sessionCountTorrents( session ) == 0 ) )
 
991
    {
 
992
        tr_trackerSessionDestroy( session );
 
993
        return FALSE;
 
994
    }
 
995
 
 
996
    return TRUE;
790
997
}
791
998
 
792
999
static void
795
1002
    if( session->tracker )
796
1003
    {
797
1004
        --session->tracker->runningCount;
798
 
        dbgmsg( NULL, "decrementing runningCount to %d", session->tracker->runningCount );
799
 
        pulse( session );
 
1005
        dbgmsg( NULL, "decrementing runningCount to %d",
 
1006
                session->tracker->runningCount );
 
1007
        trackerPulse( session );
800
1008
    }
801
1009
}
802
1010
 
805
1013
***/
806
1014
 
807
1015
static void
808
 
generateKeyParam( char * msg, int len )
 
1016
generateKeyParam( char * msg,
 
1017
                  int    len )
809
1018
{
810
 
    int i;
 
1019
    int          i;
811
1020
    const char * pool = "abcdefghijklmnopqrstuvwxyz0123456789";
812
 
    const int poolSize = strlen( pool );
813
 
    for( i=0; i<len; ++i )
814
 
        *msg++ = pool[tr_rand(poolSize)];
 
1021
    const int    poolSize = strlen( pool );
 
1022
 
 
1023
    for( i = 0; i < len; ++i )
 
1024
        *msg++ = pool[tr_cryptoRandInt( poolSize )];
815
1025
    *msg = '\0';
816
1026
}
817
1027
 
818
1028
static int
819
1029
is_rfc2396_alnum( char ch )
820
1030
{
821
 
    return     ( '0' <= ch && ch <= '9' )
822
 
            || ( 'A' <= ch && ch <= 'Z' )
823
 
            || ( 'a' <= ch && ch <= 'z' );
 
1031
    return ( '0' <= ch && ch <= '9' )
 
1032
           || ( 'A' <= ch && ch <= 'Z' )
 
1033
           || ( 'a' <= ch && ch <= 'z' );
824
1034
}
825
1035
 
826
1036
static void
827
 
escape( char * out, const uint8_t * in, int in_len ) /* rfc2396 */
 
1037
escape( char *          out,
 
1038
        const uint8_t * in,
 
1039
        int             in_len )                     /* rfc2396 */
828
1040
{
829
1041
    const uint8_t *end = in + in_len;
 
1042
 
830
1043
    while( in != end )
831
 
        if( is_rfc2396_alnum(*in) )
 
1044
        if( is_rfc2396_alnum( *in ) )
832
1045
            *out++ = (char) *in++;
833
 
        else 
834
 
            out += snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
 
1046
        else
 
1047
            out += tr_snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
 
1048
 
835
1049
    *out = '\0';
836
1050
}
837
1051
 
839
1053
tr_trackerNew( const tr_torrent * torrent )
840
1054
{
841
1055
    const tr_info * info = &torrent->info;
842
 
    tr_tracker * t;
 
1056
    tr_tracker *    t;
843
1057
 
844
1058
    t = tr_new0( tr_tracker, 1 );
845
 
    t->publisher = tr_publisherNew( );
846
 
    t->session                  = torrent->handle;
 
1059
    t->publisher                = TR_PUBLISHER_INIT;
 
1060
    t->session                  = torrent->session;
847
1061
    t->scrapeIntervalSec        = DEFAULT_SCRAPE_INTERVAL_SEC;
848
 
    t->retryScrapeIntervalSec   = 60;
 
1062
    t->retryScrapeIntervalSec   = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
 
1063
    t->retryAnnounceIntervalSec = FIRST_ANNOUNCE_RETRY_INTERVAL_SEC;
849
1064
    t->announceIntervalSec      = DEFAULT_ANNOUNCE_INTERVAL_SEC;
850
1065
    t->announceMinIntervalSec   = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
851
1066
    t->timesDownloaded          = -1;
852
1067
    t->seederCount              = -1;
 
1068
    t->downloaderCount          = -1;
853
1069
    t->leecherCount             = -1;
854
1070
    t->lastAnnounceResponse     = -1;
855
1071
    t->lastScrapeResponse       = -1;
856
1072
    t->manualAnnounceAllowedAt  = ~(time_t)0;
857
 
    t->name = tr_strdup( info->name );
858
 
    t->randOffset = tr_rand( 30 );
 
1073
    t->name                     = tr_strdup( info->name );
 
1074
    t->torrentId                = torrent->uniqueId;
 
1075
    t->randOffset               = tr_cryptoRandInt( 30 );
859
1076
    memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
860
1077
    escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
861
1078
    generateKeyParam( t->key_param, KEYLEN );
873
1090
{
874
1091
    tr_tracker * t = vt;
875
1092
 
876
 
    tr_publisherFree( &t->publisher );
 
1093
    tr_publisherDestruct( &t->publisher );
877
1094
    tr_free( t->name );
878
1095
    tr_free( t->trackerID );
879
1096
    tr_free( t->peer_id );
893
1110
}
894
1111
 
895
1112
tr_publisher_tag
896
 
tr_trackerSubscribe( tr_tracker          * t,
897
 
                     tr_delivery_func      func,
898
 
                     void                * user_data )
 
1113
tr_trackerSubscribe( tr_tracker *     t,
 
1114
                     tr_delivery_func func,
 
1115
                     void *           user_data )
899
1116
{
900
 
    return tr_publisherSubscribe( t->publisher, func, user_data );
 
1117
    return tr_publisherSubscribe( &t->publisher, func, user_data );
901
1118
}
902
1119
 
903
1120
void
904
 
tr_trackerUnsubscribe( tr_tracker        * t,
905
 
                       tr_publisher_tag    tag )
 
1121
tr_trackerUnsubscribe( tr_tracker *     t,
 
1122
                       tr_publisher_tag tag )
906
1123
{
907
1124
    if( t )
908
 
        tr_publisherUnsubscribe( t->publisher, tag );
 
1125
        tr_publisherUnsubscribe( &t->publisher, tag );
909
1126
}
910
1127
 
911
1128
const tr_tracker_info *
912
 
tr_trackerGetAddress( const tr_tracker   * t )
 
1129
tr_trackerGetAddress( tr_tracker * t, const tr_torrent * torrent )
913
1130
{
914
 
    return getCurrentAddress( t );
 
1131
    return getCurrentAddressFromTorrent( t, torrent );
915
1132
}
916
1133
 
917
1134
time_t
921
1138
}
922
1139
 
923
1140
int
924
 
tr_trackerCanManualAnnounce ( const tr_tracker * t)
 
1141
tr_trackerCanManualAnnounce( const tr_tracker * t )
925
1142
{
926
1143
    const time_t allow = tr_trackerGetManualAnnounceTime( t );
 
1144
 
927
1145
    return allow && ( allow <= time( NULL ) );
928
1146
}
929
1147
 
930
1148
void
931
 
tr_trackerGetCounts( const tr_tracker  * t,
932
 
                     int               * setme_completedCount,
933
 
                     int               * setme_leecherCount,
934
 
                     int               * setme_seederCount )
 
1149
tr_trackerGetCounts( const tr_tracker * t,
 
1150
                     int              * setme_completedCount,
 
1151
                     int              * setme_leecherCount,
 
1152
                     int              * setme_seederCount,
 
1153
                     int              * setme_downloaderCount )
935
1154
{
936
1155
    if( setme_completedCount )
937
 
       *setme_completedCount = t->timesDownloaded;
 
1156
        *setme_completedCount = t->timesDownloaded;
938
1157
 
939
1158
    if( setme_leecherCount )
940
 
       *setme_leecherCount = t->leecherCount;
 
1159
        *setme_leecherCount = t->leecherCount;
941
1160
 
942
1161
    if( setme_seederCount )
943
 
       *setme_seederCount = t->seederCount;
 
1162
        *setme_seederCount = t->seederCount;
 
1163
 
 
1164
    if( setme_downloaderCount )
 
1165
        *setme_downloaderCount = t->downloaderCount;
944
1166
}
945
1167
 
946
 
 
947
1168
void
948
1169
tr_trackerStart( tr_tracker * t )
949
1170
{
950
1171
    if( t && !t->isRunning )
951
1172
    {
 
1173
        tr_torrent * tor;
 
1174
 
 
1175
        /* change the peer-id */
952
1176
        tr_free( t->peer_id );
953
1177
        t->peer_id = tr_peerIdNew( );
 
1178
        if(( tor = tr_torrentFindFromHash( t->session, t->hash ))) {
 
1179
            tr_free( tor->peer_id );
 
1180
            tor->peer_id = (uint8_t*) tr_strdup( t->peer_id );
 
1181
        }
954
1182
 
955
1183
        t->isRunning = 1;
956
1184
        enqueueRequest( t->session, t, TR_REQ_STARTED );
972
1200
void
973
1201
tr_trackerStop( tr_tracker * t )
974
1202
{
975
 
    if( t && t->isRunning ) {
 
1203
    if( t && t->isRunning )
 
1204
    {
976
1205
        t->isRunning = 0;
977
 
        t->reannounceAt = t->manualAnnounceAllowedAt = 0;
 
1206
        t->reannounceAt = TR_TRACKER_STOPPED;
 
1207
        t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
978
1208
        enqueueRequest( t->session, t, TR_REQ_STOPPED );
979
1209
    }
980
1210
}
987
1217
}
988
1218
 
989
1219
void
990
 
tr_trackerStat( const tr_tracker       * t,
991
 
                struct tr_tracker_stat * setme)
 
1220
tr_trackerStat( const tr_tracker * t,
 
1221
                struct tr_stat *   setme )
992
1222
{
993
1223
    assert( t );
994
1224
    assert( setme );
997
1227
    setme->nextScrapeTime = t->scrapeAt;
998
1228
    setme->lastAnnounceTime = t->lastAnnounceTime;
999
1229
    setme->nextAnnounceTime = t->reannounceAt;
1000
 
    setme->nextManualAnnounceTime = t->manualAnnounceAllowedAt;
 
1230
    setme->manualAnnounceTime = t->manualAnnounceAllowedAt;
1001
1231
 
1002
1232
    if( t->lastScrapeResponse == -1 ) /* never been scraped */
1003
1233
        *setme->scrapeResponse = '\0';
1004
1234
    else
1005
 
        snprintf( setme->scrapeResponse,
1006
 
                  sizeof( setme->scrapeResponse ),
1007
 
                  "%s (%ld)",
1008
 
                  tr_webGetResponseStr( t->lastScrapeResponse ),
1009
 
                  t->lastScrapeResponse );
 
1235
        tr_snprintf( setme->scrapeResponse,
 
1236
                     sizeof( setme->scrapeResponse ),
 
1237
                     "%s (%ld)",
 
1238
                     tr_webGetResponseStr( t->lastScrapeResponse ),
 
1239
                     t->lastScrapeResponse );
1010
1240
 
1011
1241
    if( t->lastAnnounceResponse == -1 ) /* never been announced */
1012
1242
        *setme->announceResponse = '\0';
1013
1243
    else
1014
 
        snprintf( setme->announceResponse,
1015
 
                  sizeof( setme->announceResponse ),
1016
 
                  "%s (%ld)",
1017
 
                  tr_webGetResponseStr( t->lastAnnounceResponse ),
1018
 
                  t->lastAnnounceResponse );
 
1244
        tr_snprintf( setme->announceResponse,
 
1245
                     sizeof( setme->announceResponse ),
 
1246
                     "%s (%ld)",
 
1247
                     tr_webGetResponseStr( t->lastAnnounceResponse ),
 
1248
                     t->lastAnnounceResponse );
1019
1249
}
 
1250