2007-08-16 20:00:06 +00:00
|
|
|
/*
|
2008-01-01 17:20:20 +00:00
|
|
|
* This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
|
2006-07-16 19:39:23 +00:00
|
|
|
*
|
2007-08-16 20:00:06 +00:00
|
|
|
* This file is licensed by the GPL version 2. Works owned by the
|
|
|
|
* Transmission project are granted a special exemption to clause 2(b)
|
|
|
|
* so that the bulk of its code can remain under the MIT license.
|
|
|
|
* This exemption does not extend to derived works not owned by
|
|
|
|
* the Transmission project.
|
2007-08-18 17:19:49 +00:00
|
|
|
*
|
|
|
|
* $Id$
|
2007-08-16 20:00:06 +00:00
|
|
|
*/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-09 20:07:52 +00:00
|
|
|
#include <assert.h>
|
2007-08-16 20:00:06 +00:00
|
|
|
#include <stdio.h> /* snprintf */
|
2007-07-29 18:11:21 +00:00
|
|
|
#include <stdlib.h>
|
2007-08-16 20:00:06 +00:00
|
|
|
#include <string.h> /* strcmp, strchr */
|
2007-07-29 18:11:21 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
#include <event.h>
|
2007-07-14 16:29:21 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#include "transmission.h"
|
2007-07-09 20:10:42 +00:00
|
|
|
#include "bencode.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "completion.h"
|
2007-07-09 20:10:42 +00:00
|
|
|
#include "net.h"
|
2008-04-11 17:01:13 +00:00
|
|
|
#include "port-forwarding.h"
|
2007-08-16 20:00:06 +00:00
|
|
|
#include "publish.h"
|
2007-12-25 05:37:32 +00:00
|
|
|
#include "torrent.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "tracker.h"
|
2008-02-21 07:29:39 +00:00
|
|
|
#include "trcompat.h" /* strlcpy */
|
2007-08-18 03:02:32 +00:00
|
|
|
#include "trevent.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "utils.h"
|
2008-04-24 01:42:53 +00:00
|
|
|
#include "web.h"
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
enum
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
HTTP_OK = 200,
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/* seconds between tracker pulses */
|
2007-11-30 23:37:44 +00:00
|
|
|
PULSE_INTERVAL_MSEC = 1000,
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
/* maximum number of concurrent tracker socket connections */
|
|
|
|
MAX_TRACKER_SOCKETS = 16,
|
|
|
|
|
2007-12-13 23:43:50 +00:00
|
|
|
/* maximum number of concurrent tracker socket connections during shutdown.
|
|
|
|
* all the peer connections should be gone by now, so we can hog more
|
|
|
|
* connections to send `stop' messages to the trackers */
|
|
|
|
MAX_TRACKER_SOCKETS_DURING_SHUTDOWN = 64,
|
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, rescrape this frequently */
|
|
|
|
DEFAULT_SCRAPE_INTERVAL_SEC = (60 * 15),
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, this is the announce interval */
|
|
|
|
DEFAULT_ANNOUNCE_INTERVAL_SEC = (60 * 4),
|
2007-10-17 01:17:30 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, this is the announce min_interval */
|
|
|
|
DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = (60 * 2),
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* this is how long we'll leave a request hanging before timeout */
|
2008-01-19 00:28:52 +00:00
|
|
|
TIMEOUT_INTERVAL_SEC = 30,
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* this is how long we'll leave a 'stop' request hanging before timeout.
|
|
|
|
we wait less time for this so it doesn't slow down shutdowns */
|
|
|
|
STOP_TIMEOUT_INTERVAL_SEC = 5,
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* the value of the 'numwant' argument passed in tracker requests. */
|
2008-04-24 01:42:53 +00:00
|
|
|
NUMWANT = 150,
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* the length of the 'key' argument passed in tracker requests */
|
|
|
|
KEYLEN = 10
|
|
|
|
};
|
2006-12-17 16:36:27 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
struct tr_tracker
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
unsigned int isRunning : 1;
|
|
|
|
|
|
|
|
uint8_t randOffset;
|
|
|
|
|
|
|
|
tr_session * session;
|
2007-08-18 03:02:32 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* these are set from the latest scrape or tracker response */
|
2007-10-17 01:17:30 +00:00
|
|
|
int announceIntervalSec;
|
2007-10-17 18:59:58 +00:00
|
|
|
int announceMinIntervalSec;
|
2007-10-17 01:17:30 +00:00
|
|
|
int scrapeIntervalSec;
|
2008-04-12 22:37:03 +00:00
|
|
|
int retryScrapeIntervalSec;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
/* index into the torrent's tr_info.trackers array */
|
|
|
|
int trackerIndex;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
|
|
|
/* sent as the "key" argument in tracker requests
|
|
|
|
to verify us if our IP address changes.
|
|
|
|
This is immutable for the life of the tracker object. */
|
2007-10-17 18:59:58 +00:00
|
|
|
char key_param[KEYLEN+1];
|
2007-08-16 20:00:06 +00:00
|
|
|
|
|
|
|
tr_publisher_t * publisher;
|
2006-12-17 16:36:27 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* torrent hash string */
|
|
|
|
uint8_t hash[SHA_DIGEST_LENGTH];
|
2008-04-24 01:42:53 +00:00
|
|
|
char escaped[SHA_DIGEST_LENGTH*3 + 1];
|
2007-10-04 19:58:30 +00:00
|
|
|
char * name;
|
2007-04-08 05:41:44 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* corresponds to the peer_id sent as a tracker request parameter.
|
2007-10-23 14:00:17 +00:00
|
|
|
one tracker admin says: "When the same torrent is opened and
|
2007-08-16 20:00:06 +00:00
|
|
|
closed and opened again without quitting Transmission ...
|
|
|
|
change the peerid. It would help sometimes if a stopped event
|
|
|
|
was missed to ensure that we didn't think someone was cheating. */
|
2008-01-07 06:19:34 +00:00
|
|
|
uint8_t * peer_id;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* these are set from the latest tracker response... -1 is 'unknown' */
|
2007-08-16 20:00:06 +00:00
|
|
|
int timesDownloaded;
|
2007-10-17 18:59:58 +00:00
|
|
|
int seederCount;
|
|
|
|
int leecherCount;
|
2007-08-16 20:00:06 +00:00
|
|
|
char * trackerID;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-10-17 01:17:30 +00:00
|
|
|
time_t manualAnnounceAllowedAt;
|
2007-11-29 00:43:58 +00:00
|
|
|
time_t reannounceAt;
|
|
|
|
time_t scrapeAt;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-02-21 07:29:39 +00:00
|
|
|
time_t lastScrapeTime;
|
2008-04-24 01:42:53 +00:00
|
|
|
long lastScrapeResponse;
|
2008-02-21 07:29:39 +00:00
|
|
|
|
|
|
|
time_t lastAnnounceTime;
|
2008-04-24 01:42:53 +00:00
|
|
|
long lastAnnounceResponse;
|
2007-10-17 18:59:58 +00:00
|
|
|
};
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-25 02:57:33 +00:00
|
|
|
#define dbgmsg(name, fmt...) tr_deepLog(__FILE__, __LINE__, name, ##fmt )
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2007-08-18 08:28:57 +00:00
|
|
|
/***
|
2007-11-29 00:43:58 +00:00
|
|
|
****
|
2007-08-18 08:28:57 +00:00
|
|
|
***/
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static const tr_tracker_info *
|
|
|
|
getCurrentAddressFromTorrent( const tr_tracker * t, const tr_torrent * tor )
|
|
|
|
{
|
|
|
|
assert( t->trackerIndex >= 0 );
|
|
|
|
assert( t->trackerIndex < tor->info.trackerCount );
|
|
|
|
return tor->info.trackers + t->trackerIndex;
|
|
|
|
}
|
|
|
|
|
2008-03-18 16:56:01 +00:00
|
|
|
static const tr_tracker_info *
|
2007-11-29 00:43:58 +00:00
|
|
|
getCurrentAddress( const tr_tracker * t )
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const tr_torrent * torrent;
|
|
|
|
if(( torrent = tr_torrentFindFromHash( t->session, t->hash )))
|
|
|
|
return getCurrentAddressFromTorrent( t, torrent );
|
|
|
|
return NULL;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2007-10-07 16:07:19 +00:00
|
|
|
static int
|
2008-04-24 01:42:53 +00:00
|
|
|
trackerSupportsScrape( const tr_tracker * t, const tr_torrent * tor )
|
2007-08-18 08:28:57 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
|
|
|
|
return info && info->scrape;
|
2007-10-07 16:07:19 +00:00
|
|
|
}
|
2007-08-18 08:28:57 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
|
|
|
tr_tracker *
|
2008-04-24 01:42:53 +00:00
|
|
|
findTracker( tr_session * session, const uint8_t * hash )
|
2007-10-07 16:07:19 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_torrent * torrent = tr_torrentFindFromHash( session, hash );
|
2007-11-30 17:10:33 +00:00
|
|
|
return torrent ? torrent->tracker : NULL;
|
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/***
|
|
|
|
**** PUBLISH
|
|
|
|
***/
|
2007-02-27 04:00:38 +00:00
|
|
|
|
2008-04-19 15:07:59 +00:00
|
|
|
static const tr_tracker_event emptyEvent = { 0, NULL, NULL, NULL, 0, 0 };
|
2007-08-16 20:00:06 +00:00
|
|
|
|
|
|
|
static void
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( tr_tracker * t, const char * msg, int type )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t )
|
2007-11-30 23:37:44 +00:00
|
|
|
{
|
|
|
|
tr_tracker_event event = emptyEvent;
|
|
|
|
event.hash = t->hash;
|
|
|
|
event.messageType = type;
|
|
|
|
event.text = msg;
|
|
|
|
tr_publisherPublish( t->publisher, t, &event );
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-09-25 18:39:58 +00:00
|
|
|
|
|
|
|
static void
|
2007-10-17 18:59:58 +00:00
|
|
|
publishErrorClear( tr_tracker * t )
|
2007-09-25 18:39:58 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, NULL, TR_TRACKER_ERROR_CLEAR );
|
2007-09-25 18:39:58 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2007-11-30 23:37:44 +00:00
|
|
|
publishErrorMessageAndStop( tr_tracker * t, const char * msg )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-11-30 23:37:44 +00:00
|
|
|
t->isRunning = 0;
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, msg, TR_TRACKER_ERROR );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2007-10-17 18:59:58 +00:00
|
|
|
publishWarning( tr_tracker * t, const char * msg )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, msg, TR_TRACKER_WARNING );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
publishNewPeers( tr_tracker * t, int allAreSeeds,
|
|
|
|
void * compact, int compactLen )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_tracker_event event = emptyEvent;
|
|
|
|
event.hash = t->hash;
|
2007-08-16 20:00:06 +00:00
|
|
|
event.messageType = TR_TRACKER_PEERS;
|
2008-04-19 15:07:59 +00:00
|
|
|
event.allAreSeeds = allAreSeeds;
|
|
|
|
event.compact = compact;
|
|
|
|
event.compactLen = compactLen;
|
|
|
|
if( compactLen )
|
2008-01-17 00:08:40 +00:00
|
|
|
tr_publisherPublish( t->publisher, t, &event );
|
2007-07-30 17:11:00 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/***
|
2007-11-29 00:43:58 +00:00
|
|
|
****
|
2007-08-16 20:00:06 +00:00
|
|
|
***/
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static void onReqDone( tr_session * session );
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2008-02-29 06:28:00 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
updateAddresses( tr_tracker * t, long response_code, int * tryAgain )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-08-16 20:00:06 +00:00
|
|
|
int moveToNextAddress = FALSE;
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !response_code ) /* tracker didn't respond */
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-03-18 16:56:01 +00:00
|
|
|
tr_ninf( t->name, _( "Tracker hasn't responded yet. Retrying..." ) );
|
2007-08-16 20:00:06 +00:00
|
|
|
moveToNextAddress = TRUE;
|
|
|
|
}
|
2008-04-24 01:42:53 +00:00
|
|
|
else if( response_code == HTTP_OK )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
#if 0
|
|
|
|
/* FIXME */
|
|
|
|
/* multitracker spec: "if a connection with a tracker is
|
|
|
|
successful, it will be moved to the front of the tier." */
|
|
|
|
const int i = t->addressIndex;
|
|
|
|
const int j = t->tierFronts[i];
|
|
|
|
const tr_tracker_info swap = t->addresses[i];
|
|
|
|
t->addresses[i] = t->addresses[j];
|
|
|
|
t->addresses[j] = swap;
|
|
|
|
#endif
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
moveToNextAddress = TRUE;
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2008-02-13 17:15:58 +00:00
|
|
|
*tryAgain = moveToNextAddress;
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
if( moveToNextAddress )
|
2008-02-13 17:15:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if ( ++t->trackerIndex >= torrent->info.trackerCount ) /* we've tried them all */
|
2008-02-13 17:15:58 +00:00
|
|
|
{
|
|
|
|
*tryAgain = FALSE;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->trackerIndex = 0;
|
2008-02-13 17:15:58 +00:00
|
|
|
}
|
2008-03-18 16:56:01 +00:00
|
|
|
else
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const tr_tracker_info * n = getCurrentAddressFromTorrent( t, torrent );
|
|
|
|
tr_ninf( t->name, _( "Trying tracker \"%s\"" ), n->announce );
|
2008-03-18 16:56:01 +00:00
|
|
|
}
|
2008-02-13 17:15:58 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/* Convert to compact form */
|
|
|
|
static uint8_t *
|
2008-04-19 15:07:59 +00:00
|
|
|
parseOldPeers( tr_benc * bePeers, size_t * byteCount )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-11-29 00:43:58 +00:00
|
|
|
int i;
|
|
|
|
uint8_t *compact, *walk;
|
|
|
|
const int peerCount = bePeers->val.l.count;
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
assert( bePeers->type == TYPE_LIST );
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
compact = tr_new( uint8_t, peerCount*6 );
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
for( i=0, walk=compact; i<peerCount; ++i )
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const char * s;
|
|
|
|
int64_t itmp;
|
2007-11-29 00:43:58 +00:00
|
|
|
struct in_addr addr;
|
|
|
|
tr_port_t port;
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc * peer = &bePeers->val.l.vals[i];
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
continue;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
memcpy( walk, &addr, 4 );
|
|
|
|
walk += 4;
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp<0 || itmp>0xffff )
|
2007-11-29 00:43:58 +00:00
|
|
|
continue;
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
port = htons( itmp );
|
2007-11-29 00:43:58 +00:00
|
|
|
memcpy( walk, &port, 2 );
|
|
|
|
walk += 2;
|
|
|
|
}
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-04-19 15:07:59 +00:00
|
|
|
*byteCount = peerCount * 6;
|
2007-11-29 00:43:58 +00:00
|
|
|
return compact;
|
2007-10-11 14:56:50 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
onStoppedResponse( tr_session * session,
|
|
|
|
long responseCode UNUSED,
|
|
|
|
const void * response UNUSED,
|
|
|
|
size_t responseLen UNUSED,
|
|
|
|
void * torrent_hash UNUSED )
|
|
|
|
{
|
|
|
|
dbgmsg( NULL, "got a response to some `stop' message" );
|
|
|
|
onReqDone( session );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
onTrackerResponse( tr_session * session,
|
|
|
|
long responseCode,
|
|
|
|
const void * response,
|
|
|
|
size_t responseLen,
|
|
|
|
void * torrent_hash )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-02-13 17:15:58 +00:00
|
|
|
int tryAgain;
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_tracker * t;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( session );
|
|
|
|
t = findTracker( session, torrent_hash );
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_free( torrent_hash );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !t ) /* tracker's been closed */
|
2007-11-29 00:43:58 +00:00
|
|
|
return;
|
|
|
|
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "tracker response: %d", responseCode );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_ndbg( t->name, "tracker response: %d", responseCode );
|
|
|
|
t->lastAnnounceResponse = responseCode;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( responseCode == HTTP_OK )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc benc;
|
2008-04-24 01:42:53 +00:00
|
|
|
const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
|
2007-11-29 00:43:58 +00:00
|
|
|
publishErrorClear( t );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( bencLoaded && tr_bencIsDict( &benc ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc * tmp;
|
2008-04-24 01:42:53 +00:00
|
|
|
int64_t i;
|
2008-04-19 15:07:59 +00:00
|
|
|
int incomplete = -1;
|
2008-04-24 01:42:53 +00:00
|
|
|
const char * str;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindStr( &benc, "failure reason", &str )))
|
|
|
|
publishErrorMessageAndStop( t, str );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindStr( &benc, "warning message", &str )))
|
|
|
|
publishWarning( t, str );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( &benc, "interval", &i ))) {
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "setting interval to %d", (int)i );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->announceIntervalSec = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( &benc, "min interval", &i ))) {
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "setting min interval to %d", (int)i );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->announceMinIntervalSec = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindStr( &benc, "tracker id", &str )))
|
|
|
|
t->trackerID = tr_strdup( str );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( &benc, "complete", &i )))
|
|
|
|
t->seederCount = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( &benc, "incomplete", &i )))
|
|
|
|
t->leecherCount = incomplete = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
if(( tmp = tr_bencDictFind( &benc, "peers" )))
|
|
|
|
{
|
2008-04-19 15:07:59 +00:00
|
|
|
const int allAreSeeds = incomplete == 0;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-19 15:07:59 +00:00
|
|
|
if( tmp->type == TYPE_STR ) /* "compact" extension */
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-19 15:07:59 +00:00
|
|
|
publishNewPeers( t, allAreSeeds, tmp->val.s.s, tmp->val.s.i );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2008-04-19 15:07:59 +00:00
|
|
|
else if( tmp->type == TYPE_LIST ) /* original protocol */
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-19 15:07:59 +00:00
|
|
|
size_t byteCount = 0;
|
|
|
|
uint8_t * compact = parseOldPeers( tmp, &byteCount );
|
|
|
|
publishNewPeers( t, allAreSeeds, compact, byteCount );
|
|
|
|
tr_free( compact );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( bencLoaded )
|
|
|
|
tr_bencFree( &benc );
|
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
updateAddresses( t, responseCode, &tryAgain );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
2008-02-13 17:15:58 +00:00
|
|
|
if( tryAgain )
|
|
|
|
responseCode = 300;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
if( 200<=responseCode && responseCode<=299 )
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const int interval = t->announceIntervalSec + t->randOffset;
|
2008-04-25 16:06:03 +00:00
|
|
|
const time_t now = time ( NULL );
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "request succeeded. reannouncing in %d seconds", interval );
|
2008-04-25 16:06:03 +00:00
|
|
|
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
|
|
|
|
t->reannounceAt = now + interval;
|
|
|
|
t->manualAnnounceAllowedAt = now + t->announceMinIntervalSec;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
else if( 300<=responseCode && responseCode<=399 )
|
|
|
|
{
|
|
|
|
/* it's a redirect... updateAddresses() has already
|
|
|
|
* parsed the redirect, all that's left is to retry */
|
2008-04-24 01:42:53 +00:00
|
|
|
const int interval = 5;
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "got a redirect. retrying in %d seconds", interval );
|
2008-03-18 19:33:08 +00:00
|
|
|
t->reannounceAt = time( NULL ) + interval;
|
2008-01-19 01:34:02 +00:00
|
|
|
t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
else if( 400<=responseCode && responseCode<=499 )
|
|
|
|
{
|
|
|
|
/* The request could not be understood by the server due to
|
|
|
|
* malformed syntax. The client SHOULD NOT repeat the
|
|
|
|
* request without modifications. */
|
2008-04-24 01:42:53 +00:00
|
|
|
publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
|
2007-11-29 00:43:58 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
|
|
|
t->reannounceAt = 0;
|
|
|
|
}
|
|
|
|
else if( 500<=responseCode && responseCode<=599 )
|
|
|
|
{
|
|
|
|
/* Response status codes beginning with the digit "5" indicate
|
|
|
|
* cases in which the server is aware that it has erred or is
|
|
|
|
* incapable of performing the request. So we pause a bit and
|
|
|
|
* try again. */
|
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-01-19 01:34:02 +00:00
|
|
|
t->reannounceAt = time( NULL ) + 60;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* WTF did we get?? */
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "Invalid response from tracker... retrying in two minutes." );
|
2007-11-29 00:43:58 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-01-19 01:34:02 +00:00
|
|
|
t->reannounceAt = time( NULL ) + t->randOffset + 120;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
onScrapeResponse( tr_session * session,
|
|
|
|
long responseCode,
|
|
|
|
const void * response,
|
|
|
|
size_t responseLen,
|
|
|
|
void * torrent_hash )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-02-13 17:15:58 +00:00
|
|
|
int tryAgain;
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_tracker * t;
|
2007-12-05 02:06:05 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( session );
|
|
|
|
t = findTracker( session, torrent_hash );
|
2007-12-05 02:06:05 +00:00
|
|
|
tr_free( torrent_hash );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !t ) /* tracker's been closed... */
|
2007-10-08 19:09:20 +00:00
|
|
|
return;
|
|
|
|
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "scrape response: %ld\n", responseCode );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_ndbg( t->name, "scrape response: %d", responseCode );
|
|
|
|
t->lastScrapeResponse = responseCode;
|
2007-10-17 18:59:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( responseCode == HTTP_OK )
|
2007-01-20 05:07:00 +00:00
|
|
|
{
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc benc, *files;
|
2008-04-24 01:42:53 +00:00
|
|
|
const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
|
|
|
|
if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
|
2007-01-20 05:07:00 +00:00
|
|
|
{
|
2007-08-16 20:00:06 +00:00
|
|
|
int i;
|
|
|
|
for( i=0; i<files->val.l.count; i+=2 )
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
int64_t itmp;
|
2007-08-16 20:00:06 +00:00
|
|
|
const uint8_t* hash =
|
2008-04-24 01:42:53 +00:00
|
|
|
(const uint8_t*) files->val.l.vals[i].val.s.s;
|
|
|
|
tr_benc * flags;
|
|
|
|
tr_benc * tordict = &files->val.l.vals[i+1];
|
2007-10-17 18:59:58 +00:00
|
|
|
if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
|
2007-08-16 20:00:06 +00:00
|
|
|
continue;
|
2007-01-20 05:07:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
publishErrorClear( t );
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( tordict, "complete", &itmp )))
|
|
|
|
t->seederCount = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( tordict, "incomplete", &itmp )))
|
|
|
|
t->leecherCount = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if(( tr_bencDictFindInt( tordict, "downloaded", &itmp )))
|
|
|
|
t->timesDownloaded = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( tr_bencDictFindDict( tordict, "flags", &flags ))
|
|
|
|
if(( tr_bencDictFindInt( flags, "min_request_interval", &itmp )))
|
|
|
|
t->scrapeIntervalSec = i;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2008-03-13 03:53:18 +00:00
|
|
|
tr_ndbg( t->name, "Scrape successful. Rescraping in %d seconds.",
|
|
|
|
t->scrapeIntervalSec );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-12 22:37:03 +00:00
|
|
|
t->retryScrapeIntervalSec = 30;
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
if( bencLoaded )
|
|
|
|
tr_bencFree( &benc );
|
2006-10-13 07:42:55 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
updateAddresses( t, responseCode, &tryAgain );
|
2006-10-13 07:42:55 +00:00
|
|
|
|
2008-04-12 22:37:03 +00:00
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
|
|
|
if( tryAgain )
|
|
|
|
responseCode = 300;
|
|
|
|
|
|
|
|
if( 200<=responseCode && responseCode<=299 )
|
|
|
|
{
|
|
|
|
const int interval = t->scrapeIntervalSec + t->randOffset;
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "request succeeded. rescraping in %d seconds", interval );
|
2008-04-19 19:37:05 +00:00
|
|
|
tr_ndbg( t->name, "request succeeded. rescraping in %d seconds", interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
|
|
|
else if( 300<=responseCode && responseCode<=399 )
|
|
|
|
{
|
|
|
|
const int interval = 5;
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "got a redirect. retrying in %d seconds", interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
2008-02-13 17:15:58 +00:00
|
|
|
else
|
2008-04-12 22:37:03 +00:00
|
|
|
{
|
|
|
|
const int interval = t->retryScrapeIntervalSec + t->randOffset;
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "Tracker responded to scrape with %d. Retrying in %d seconds.",
|
2008-04-24 01:42:53 +00:00
|
|
|
responseCode, interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->retryScrapeIntervalSec *= 2;
|
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
2007-10-17 18:59:58 +00:00
|
|
|
|
2007-11-30 17:10:33 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
TR_REQ_STARTED,
|
|
|
|
TR_REQ_COMPLETED,
|
|
|
|
TR_REQ_STOPPED,
|
|
|
|
TR_REQ_REANNOUNCE,
|
|
|
|
TR_REQ_SCRAPE,
|
|
|
|
TR_REQ_COUNT
|
|
|
|
};
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_request
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
char * url;
|
2007-11-30 17:10:33 +00:00
|
|
|
int reqtype; /* TR_REQ_* */
|
|
|
|
uint8_t torrent_hash[SHA_DIGEST_LENGTH];
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_web_done_func * done_func;
|
|
|
|
tr_session * session;
|
2007-11-29 00:43:58 +00:00
|
|
|
};
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2007-11-29 02:31:21 +00:00
|
|
|
freeRequest( struct tr_tracker_request * req )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_free( req->url );
|
2007-11-29 02:31:21 +00:00
|
|
|
tr_free( req );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2007-10-17 18:59:58 +00:00
|
|
|
buildTrackerRequestURI( const tr_tracker * t,
|
2007-10-04 19:58:30 +00:00
|
|
|
const tr_torrent * torrent,
|
2008-04-24 01:42:53 +00:00
|
|
|
const char * eventName,
|
|
|
|
struct evbuffer * buf )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-10-09 04:50:10 +00:00
|
|
|
const int isStopping = !strcmp( eventName, "stopped" );
|
|
|
|
const int numwant = isStopping ? 0 : NUMWANT;
|
2008-04-24 01:42:53 +00:00
|
|
|
const char * ann = getCurrentAddressFromTorrent(t,torrent)->announce;
|
2007-10-25 16:52:12 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
evbuffer_add_printf( buf, "%cinfo_hash=%s"
|
2007-10-17 18:59:58 +00:00
|
|
|
"&peer_id=%s"
|
|
|
|
"&port=%d"
|
|
|
|
"&uploaded=%"PRIu64
|
|
|
|
"&downloaded=%"PRIu64
|
|
|
|
"&corrupt=%"PRIu64
|
|
|
|
"&left=%"PRIu64
|
|
|
|
"&compact=1"
|
|
|
|
"&numwant=%d"
|
|
|
|
"&key=%s"
|
|
|
|
"%s%s"
|
|
|
|
"%s%s",
|
2007-11-06 16:02:50 +00:00
|
|
|
strchr(ann, '?') ? '&' : '?',
|
2007-10-17 18:59:58 +00:00
|
|
|
t->escaped,
|
|
|
|
t->peer_id,
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_sharedGetPublicPort( t->session->shared ),
|
2007-08-16 20:00:06 +00:00
|
|
|
torrent->uploadedCur,
|
|
|
|
torrent->downloadedCur,
|
2007-08-21 15:17:02 +00:00
|
|
|
torrent->corruptCur,
|
2007-08-16 20:00:06 +00:00
|
|
|
tr_cpLeftUntilComplete( torrent->completion ),
|
|
|
|
numwant,
|
2007-10-17 18:59:58 +00:00
|
|
|
t->key_param,
|
2007-08-16 20:00:06 +00:00
|
|
|
( ( eventName && *eventName ) ? "&event=" : "" ),
|
|
|
|
( ( eventName && *eventName ) ? eventName : "" ),
|
2007-10-17 18:59:58 +00:00
|
|
|
( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
|
|
|
|
( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static struct tr_tracker_request*
|
2008-04-24 01:42:53 +00:00
|
|
|
createRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
static const char* strings[] = { "started", "completed", "stopped", "", "err" };
|
|
|
|
const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
|
|
|
|
const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
|
2007-11-29 00:43:58 +00:00
|
|
|
const int isStopping = reqtype == TR_REQ_STOPPED;
|
|
|
|
struct tr_tracker_request * req;
|
2008-04-24 01:42:53 +00:00
|
|
|
struct evbuffer * url;
|
|
|
|
|
|
|
|
url = evbuffer_new( );
|
|
|
|
evbuffer_add_printf( url, "%s", address->announce );
|
|
|
|
buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
req = tr_new0( struct tr_tracker_request, 1 );
|
2008-04-24 01:42:53 +00:00
|
|
|
req->session = session;
|
2007-11-30 17:10:33 +00:00
|
|
|
req->reqtype = reqtype;
|
2008-04-24 01:42:53 +00:00
|
|
|
req->done_func = isStopping ? onStoppedResponse : onTrackerResponse;
|
|
|
|
req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
|
2007-11-30 17:10:33 +00:00
|
|
|
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
evbuffer_free( url );
|
2007-11-29 00:43:58 +00:00
|
|
|
return req;
|
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static struct tr_tracker_request*
|
2008-04-24 01:42:53 +00:00
|
|
|
createScrape( tr_session * session, const tr_tracker * tracker )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
const tr_tracker_info * a = getCurrentAddress( tracker );
|
|
|
|
struct tr_tracker_request * req;
|
2008-04-24 01:42:53 +00:00
|
|
|
struct evbuffer * url = evbuffer_new( );
|
|
|
|
|
|
|
|
evbuffer_add_printf( url, "%s%cinfo_hash=%s",
|
|
|
|
a->scrape, strchr(a->scrape,'?')?'&':'?',
|
|
|
|
tracker->escaped );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
req = tr_new0( struct tr_tracker_request, 1 );
|
2008-04-24 01:42:53 +00:00
|
|
|
req->session = session;
|
2007-11-30 17:10:33 +00:00
|
|
|
req->reqtype = TR_REQ_SCRAPE;
|
2008-04-24 01:42:53 +00:00
|
|
|
req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
|
|
|
|
req->done_func = onScrapeResponse;
|
2007-11-30 17:10:33 +00:00
|
|
|
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
evbuffer_free( url );
|
2007-11-29 00:43:58 +00:00
|
|
|
return req;
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_handle
|
|
|
|
{
|
2007-12-13 21:08:05 +00:00
|
|
|
unsigned int isShuttingDown : 1;
|
2008-04-24 01:42:53 +00:00
|
|
|
int runningCount;
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_timer * pulseTimer;
|
|
|
|
};
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static int pulse( void * vsession );
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
ensureGlobalsExist( tr_session * session )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( session->tracker == NULL )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
session->tracker = tr_new0( struct tr_tracker_handle, 1 );
|
|
|
|
session->tracker->pulseTimer = tr_timerNew( session, pulse, session, PULSE_INTERVAL_MSEC );
|
2007-11-29 00:43:58 +00:00
|
|
|
dbgmsg( NULL, "creating tracker timer" );
|
|
|
|
}
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 02:31:21 +00:00
|
|
|
void
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_trackerShuttingDown( tr_session * session )
|
2007-11-29 02:31:21 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( session->tracker )
|
|
|
|
session->tracker->isShuttingDown = 1;
|
2007-11-29 02:31:21 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static int
|
2008-04-24 01:42:53 +00:00
|
|
|
maybeFreeGlobals( tr_session * session )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
int globalsExist = session->tracker != NULL;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
if( globalsExist
|
2008-04-24 01:42:53 +00:00
|
|
|
&& ( session->tracker->runningCount < 1 )
|
|
|
|
&& ( session->torrentList== NULL ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
dbgmsg( NULL, "freeing tracker timer" );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_timerFree( &session->tracker->pulseTimer );
|
|
|
|
tr_free( session->tracker );
|
|
|
|
session->tracker = NULL;
|
2007-11-29 00:43:58 +00:00
|
|
|
globalsExist = FALSE;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
return globalsExist;
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
2007-08-20 02:29:36 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
invokeRequest( void * vreq )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
struct tr_tracker_request * req = vreq;
|
|
|
|
uint8_t * hash;
|
|
|
|
tr_tracker * t = findTracker( req->session, req->torrent_hash );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t )
|
2008-02-21 07:29:39 +00:00
|
|
|
{
|
|
|
|
if( req->reqtype == TR_REQ_SCRAPE )
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
t->lastScrapeTime = time( NULL );
|
2008-02-21 07:29:39 +00:00
|
|
|
t->scrapeAt = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
t->lastAnnounceTime = time( NULL );
|
2008-02-21 07:29:39 +00:00
|
|
|
t->reannounceAt = 0;
|
2008-04-25 16:06:03 +00:00
|
|
|
t->scrapeAt = 0;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-02-21 07:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
++req->session->tracker->runningCount;
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
hash = tr_new0( uint8_t, SHA_DIGEST_LENGTH );
|
|
|
|
memcpy( hash, req->torrent_hash, SHA_DIGEST_LENGTH );
|
|
|
|
tr_webRun( req->session, req->url, req->done_func, hash );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
freeRequest( req );
|
2007-12-27 22:38:53 +00:00
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static void ensureGlobalsExist( tr_session * );
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-30 17:10:33 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueScrape( tr_session * session, const tr_tracker * tracker )
|
2007-11-30 17:10:33 +00:00
|
|
|
{
|
|
|
|
struct tr_tracker_request * req;
|
2008-04-24 01:42:53 +00:00
|
|
|
ensureGlobalsExist( session );
|
|
|
|
req = createScrape( session, tracker );
|
|
|
|
tr_runInEventThread( session, invokeRequest, req );
|
2007-11-30 17:10:33 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
struct tr_tracker_request * req;
|
2008-04-24 01:42:53 +00:00
|
|
|
ensureGlobalsExist( session );
|
|
|
|
req = createRequest( session, tracker, reqtype );
|
|
|
|
tr_runInEventThread( session, invokeRequest, req );
|
2008-01-19 00:28:52 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static int
|
2008-04-24 01:42:53 +00:00
|
|
|
pulse( void * vsession )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_session * session = vsession;
|
|
|
|
struct tr_tracker_handle * th = session->tracker;
|
2007-11-30 17:10:33 +00:00
|
|
|
tr_torrent * tor;
|
2007-11-29 00:43:58 +00:00
|
|
|
const time_t now = time( NULL );
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !session->tracker )
|
2007-12-13 21:48:39 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( th->runningCount )
|
|
|
|
dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
/* upkeep: queue periodic rescrape / reannounce */
|
2008-04-24 01:42:53 +00:00
|
|
|
for( tor=session->torrentList; tor; tor=tor->next )
|
2007-11-30 17:10:33 +00:00
|
|
|
{
|
|
|
|
tr_tracker * t = tor->tracker;
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t->scrapeAt && trackerSupportsScrape( t, tor ) && ( now >= t->scrapeAt ) ) {
|
2007-11-30 17:10:33 +00:00
|
|
|
t->scrapeAt = 0;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueScrape( session, t );
|
2007-11-30 17:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
|
|
|
|
t->reannounceAt = 0;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( session, t, TR_REQ_REANNOUNCE );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( th->runningCount )
|
|
|
|
dbgmsg( NULL, "tracker pulse after upkeep... %d running", th->runningCount );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
return maybeFreeGlobals( session );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-12-05 02:06:05 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( tr_session * session )
|
2007-12-05 02:06:05 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( session->tracker )
|
2007-12-13 21:48:39 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
--session->tracker->runningCount;
|
|
|
|
dbgmsg( NULL, "decrementing runningCount to %d", session->tracker->runningCount );
|
|
|
|
pulse( session );
|
2007-12-13 21:48:39 +00:00
|
|
|
}
|
2007-12-05 02:06:05 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
**** LIFE CYCLE
|
|
|
|
***/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
|
|
|
generateKeyParam( char * msg, int len )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const char * pool = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
const int poolSize = strlen( pool );
|
|
|
|
for( i=0; i<len; ++i )
|
|
|
|
*msg++ = pool[tr_rand(poolSize)];
|
|
|
|
*msg = '\0';
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-01-03 17:49:45 +00:00
|
|
|
static int
|
|
|
|
is_rfc2396_alnum( char ch )
|
|
|
|
{
|
2008-01-03 18:46:33 +00:00
|
|
|
return ( (ch >= 'a' && ch <= 'z' )
|
|
|
|
|| (ch >= 'A' && ch <= 'Z' )
|
|
|
|
|| (ch >= '0' && ch <= '9' ) );
|
2008-01-03 17:49:45 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
|
|
|
escape( char * out, const uint8_t * in, int in_len ) /* rfc2396 */
|
|
|
|
{
|
|
|
|
const uint8_t *end = in + in_len;
|
|
|
|
while( in != end )
|
2008-01-03 17:49:45 +00:00
|
|
|
if( is_rfc2396_alnum(*in) )
|
2007-11-29 00:43:58 +00:00
|
|
|
*out++ = (char) *in++;
|
|
|
|
else
|
|
|
|
out += snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
|
|
|
|
*out = '\0';
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_tracker *
|
|
|
|
tr_trackerNew( const tr_torrent * torrent )
|
|
|
|
{
|
|
|
|
const tr_info * info = &torrent->info;
|
|
|
|
tr_tracker * t;
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
t = tr_new0( tr_tracker, 1 );
|
|
|
|
t->publisher = tr_publisherNew( );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->session = torrent->handle;
|
|
|
|
t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
|
|
|
|
t->retryScrapeIntervalSec = 60;
|
|
|
|
t->announceIntervalSec = DEFAULT_ANNOUNCE_INTERVAL_SEC;
|
|
|
|
t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
|
|
|
|
t->timesDownloaded = -1;
|
|
|
|
t->seederCount = -1;
|
|
|
|
t->leecherCount = -1;
|
2008-04-25 04:35:06 +00:00
|
|
|
t->lastAnnounceResponse = -1;
|
|
|
|
t->lastScrapeResponse = -1;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2007-11-29 00:43:58 +00:00
|
|
|
t->name = tr_strdup( info->name );
|
2008-04-20 21:54:44 +00:00
|
|
|
t->randOffset = tr_rand( 120 );
|
2007-11-29 00:43:58 +00:00
|
|
|
memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
|
|
|
|
escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
|
2008-04-24 01:42:53 +00:00
|
|
|
generateKeyParam( t->key_param, KEYLEN );
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
t->trackerIndex = 0;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( trackerSupportsScrape( t, torrent ) )
|
|
|
|
t->scrapeAt = time( NULL ) + t->randOffset;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
return t;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
|
|
|
onTrackerFreeNow( void * vt )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_tracker * t = vt;
|
2007-10-04 19:58:30 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_publisherFree( &t->publisher );
|
|
|
|
tr_free( t->name );
|
|
|
|
tr_free( t->trackerID );
|
2008-01-07 06:19:34 +00:00
|
|
|
tr_free( t->peer_id );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_free( t );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2008-04-15 15:51:59 +00:00
|
|
|
/***
|
|
|
|
**** PUBLIC
|
|
|
|
***/
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
void
|
|
|
|
tr_trackerFree( tr_tracker * t )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-04-15 15:51:59 +00:00
|
|
|
if( t )
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_runInEventThread( t->session, onTrackerFreeNow, t );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
tr_publisher_tag
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerSubscribe( tr_tracker * t,
|
2007-08-16 20:00:06 +00:00
|
|
|
tr_delivery_func func,
|
|
|
|
void * user_data )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
return tr_publisherSubscribe( t->publisher, func, user_data );
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerUnsubscribe( tr_tracker * t,
|
2007-08-16 20:00:06 +00:00
|
|
|
tr_publisher_tag tag )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2008-04-15 15:51:59 +00:00
|
|
|
if( t )
|
|
|
|
tr_publisherUnsubscribe( t->publisher, tag );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_tracker_info *
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerGetAddress( const tr_tracker * t )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
return getCurrentAddress( t );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2008-02-09 17:07:30 +00:00
|
|
|
time_t
|
|
|
|
tr_trackerGetManualAnnounceTime( const struct tr_tracker * t )
|
|
|
|
{
|
|
|
|
return t->isRunning ? t->manualAnnounceAllowedAt : 0;
|
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
int
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerCanManualAnnounce ( const tr_tracker * t)
|
2007-07-12 20:48:13 +00:00
|
|
|
{
|
2008-02-09 17:07:30 +00:00
|
|
|
const time_t allow = tr_trackerGetManualAnnounceTime( t );
|
|
|
|
return allow && ( allow <= time( NULL ) );
|
2007-07-12 20:48:13 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerGetCounts( const tr_tracker * t,
|
|
|
|
int * setme_completedCount,
|
|
|
|
int * setme_leecherCount,
|
|
|
|
int * setme_seederCount )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_completedCount )
|
2007-10-17 18:59:58 +00:00
|
|
|
*setme_completedCount = t->timesDownloaded;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_leecherCount )
|
2007-10-17 18:59:58 +00:00
|
|
|
*setme_leecherCount = t->leecherCount;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_seederCount )
|
2007-10-17 18:59:58 +00:00
|
|
|
*setme_seederCount = t->seederCount;
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-11-23 03:01:13 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerStart( tr_tracker * t )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t && !t->isRunning )
|
2008-04-15 15:51:59 +00:00
|
|
|
{
|
|
|
|
tr_free( t->peer_id );
|
|
|
|
t->peer_id = tr_peerIdNew( );
|
2008-01-07 06:19:34 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
t->isRunning = 1;
|
|
|
|
enqueueRequest( t->session, t, TR_REQ_STARTED );
|
2007-10-04 19:58:30 +00:00
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
2007-01-27 21:17:10 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerReannounce( tr_tracker * t )
|
2007-01-27 21:17:10 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_REANNOUNCE );
|
2007-01-27 21:17:10 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerCompleted( tr_tracker * t )
|
2007-03-30 00:12:39 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_COMPLETED );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerStop( tr_tracker * t )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-15 15:51:59 +00:00
|
|
|
if( t && t->isRunning ) {
|
2007-10-17 18:59:58 +00:00
|
|
|
t->isRunning = 0;
|
2008-02-21 07:29:39 +00:00
|
|
|
t->reannounceAt = t->manualAnnounceAllowedAt = 0;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_STOPPED );
|
2007-10-04 19:58:30 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerChangeMyPort( tr_tracker * t )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
if( t->isRunning )
|
|
|
|
tr_trackerReannounce( t );
|
2007-03-30 00:12:39 +00:00
|
|
|
}
|
2008-02-21 07:29:39 +00:00
|
|
|
|
|
|
|
void
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_trackerStat( const tr_tracker * t,
|
2008-02-21 07:29:39 +00:00
|
|
|
struct tr_tracker_stat * setme)
|
|
|
|
{
|
2008-04-25 04:26:04 +00:00
|
|
|
assert( t );
|
|
|
|
assert( setme );
|
2008-02-21 07:29:39 +00:00
|
|
|
|
|
|
|
setme->lastScrapeTime = t->lastScrapeTime;
|
|
|
|
setme->nextScrapeTime = t->scrapeAt;
|
|
|
|
setme->lastAnnounceTime = t->lastAnnounceTime;
|
|
|
|
setme->nextAnnounceTime = t->reannounceAt;
|
|
|
|
setme->nextManualAnnounceTime = t->manualAnnounceAllowedAt;
|
2008-04-25 04:35:06 +00:00
|
|
|
|
|
|
|
if( t->lastScrapeResponse == -1 ) /* never been scraped */
|
|
|
|
*setme->scrapeResponse = '\0';
|
|
|
|
else
|
|
|
|
snprintf( setme->scrapeResponse,
|
|
|
|
sizeof( setme->scrapeResponse ),
|
|
|
|
"%s (%ld)",
|
|
|
|
tr_webGetResponseStr( t->lastScrapeResponse ),
|
|
|
|
t->lastScrapeResponse );
|
|
|
|
|
|
|
|
if( t->lastAnnounceResponse == -1 ) /* never been announced */
|
|
|
|
*setme->announceResponse = '\0';
|
|
|
|
else
|
|
|
|
snprintf( setme->announceResponse,
|
|
|
|
sizeof( setme->announceResponse ),
|
|
|
|
"%s (%ld)",
|
|
|
|
tr_webGetResponseStr( t->lastAnnounceResponse ),
|
|
|
|
t->lastAnnounceResponse );
|
2008-02-21 07:29:39 +00:00
|
|
|
}
|