瀏覽代碼

Rethink the tracker client code somewhat.

btpd now uses all tiers in parallel, so a torrent with two tiers will
essentially be treated by btpd as a torrent with two trackers to send
each event to. This is not quite what the multitrackes standard says,
but it's much easier to implement reasonable behaviour this way.

btpd is going to report the number of good trackers for a torrent
instead of the number of errors, but for now just report zero errors.
master
Richard Nyberg 15 年之前
父節點
當前提交
7ba163fe5a
共有 6 個文件被更改,包括 320 次插入252 次删除
  1. +1
    -2
      btpd/cli_if.c
  2. +71
    -55
      btpd/http_tr_if.c
  3. +12
    -20
      btpd/torrent.c
  4. +1
    -1
      btpd/torrent.h
  5. +218
    -160
      btpd/tracker_req.c
  6. +17
    -14
      btpd/tracker_req.h

+ 1
- 2
btpd/cli_if.c 查看文件

@@ -148,8 +148,7 @@ write_ans(struct iobuf *iob, struct tlib *tl, enum ipc_tval val)
(tl->tp == NULL ? 0 : tl->tp->net->uploaded));
return;
case IPC_TVAL_TRERR:
iobuf_print(iob, "i%dei%ue", IPC_TYPE_NUM,
tl->tp == NULL ? 0 : tr_errors(tl->tp));
iobuf_print(iob, "i%dei%ue", IPC_TYPE_NUM, 0);
return;
case IPC_TVALCOUNT:
break;


+ 71
- 55
btpd/http_tr_if.c 查看文件

@@ -7,23 +7,26 @@

static const char *m_tr_events[] = { "started", "stopped", "completed", "" };

struct http_tr_req {
struct httptr_req {
struct torrent *tp;
struct tr_tier *tr;
struct http_req *req;
struct iobuf buf;
struct fdev ioev;
struct timeout timer;
nameconn_t nc;
int sd;
enum tr_event event;
};

static void
http_tr_free(struct http_tr_req *treq)
httptr_free(struct httptr_req *treq)
{
if (treq->sd != -1) {
btpd_ev_del(&treq->ioev);
close(treq->sd);
}
btpd_timer_del(&treq->timer);
iobuf_free(&treq->buf);
free(treq);
}
@@ -55,9 +58,9 @@ maybe_connect_to(struct torrent *tp, const char *pinfo)
free(ip);
}

static int
parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
int *interval)
static void
parse_reply(struct torrent *tp, struct tr_response *res, const char *content,
size_t size)
{
const char *buf;
size_t len;
@@ -67,25 +70,20 @@ parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
if (benc_validate(content, size) != 0)
goto bad_data;

if ((buf = benc_dget_mem(content, "failure reason", &len)) != NULL) {
btpd_log(BTPD_L_ERROR, "Tracker failure: '%.*s' for '%s'.\n",
(int)len, buf, torrent_name(tp));
return 1;
}

if (!parse) {
*interval = -1;
return 0;
if ((buf = benc_dget_any(content, "failure reason")) != NULL) {
if (!benc_isstr(buf))
goto bad_data;
res->type = TR_RES_FAIL;
res->mi_failure = buf;
return;
}

if (!benc_dct_chk(content, 2, BE_INT, 1, "interval", BE_ANY, 1, "peers"))
goto bad_data;

*interval = benc_dget_int(content, "interval");
if (*interval < 1)
goto bad_data;
buf = benc_dget_any(content, "interval");
if (buf != NULL && benc_isint(buf))
res->interval = benc_int(buf, NULL);

peers = benc_dget_any(content, "peers");
if ((peers = benc_dget_any(content, "peers")) == NULL)
goto after_peers;

if (benc_islst(peers)) {
for (peers = benc_first(peers);
@@ -101,8 +99,9 @@ parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
} else
goto bad_data;

after_peers:
if (!net_ipv6)
return 0;
goto after_peers6;
for (int k = 0; k < 2; k++) {
peers = benc_dget_any(content, v6key[k]);
if (peers != NULL && benc_isstr(peers)) {
@@ -111,42 +110,44 @@ parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
peer_create_out_compact(tp->net, AF_INET6, peers + i);
}
}
return 0;
after_peers6:
res->type = TR_RES_OK;
return;

bad_data:
btpd_log(BTPD_L_ERROR, "Bad data from tracker for '%s'.\n",
torrent_name(tp));
return 1;
res->type = TR_RES_BAD;
}

static void
http_cb(struct http_req *req, struct http_response *res, void *arg)
{
int interval;
struct http_tr_req *treq = arg;
struct httptr_req *treq = arg;
struct tr_response tres = {0, NULL, -1 };
switch (res->type) {
case HTTP_T_ERR:
btpd_log(BTPD_L_ERROR, "http request failed for '%s'.\n",
torrent_name(treq->tp));
tr_result(treq->tp, TR_RES_FAIL, -1);
http_tr_free(treq);
tres.type = TR_RES_BAD;
tr_result(treq->tr, &tres);
httptr_free(treq);
break;
case HTTP_T_DATA:
if (treq->buf.off + res->v.data.l > MAX_DOWNLOAD) {
tr_result(treq->tp, TR_RES_FAIL, -1);
http_tr_cancel(treq);
tres.type = TR_RES_BAD;
tr_result(treq->tr, &tres);
httptr_cancel(treq);
break;
}
if (!iobuf_write(&treq->buf, res->v.data.p, res->v.data.l))
btpd_err("Out of memory.\n");
break;
case HTTP_T_DONE:
if (parse_reply(treq->tp, treq->buf.buf, treq->buf.off,
treq->event != TR_EV_STOPPED, &interval) == 0)
tr_result(treq->tp, TR_RES_OK, interval);
else
tr_result(treq->tp, TR_RES_FAIL, -1);
http_tr_free(treq);
if (treq->event == TR_EV_STOPPED) {
tres.type = TR_RES_OK;
tr_result(treq->tr, &tres);
} else {
parse_reply(treq->tp, &tres, treq->buf.buf, treq->buf.off);
tr_result(treq->tr, &tres);
}
httptr_free(treq);
break;
default:
break;
@@ -154,9 +155,10 @@ http_cb(struct http_req *req, struct http_response *res, void *arg)
}

static void
sd_io_cb(int sd, short type, void *arg)
httptr_io_cb(int sd, short type, void *arg)
{
struct http_tr_req *treq = arg;
struct tr_response res;
struct httptr_req *treq = arg;
switch (type) {
case EV_READ:
if (http_read(treq->req, sd) && !http_want_read(treq->req))
@@ -166,30 +168,39 @@ sd_io_cb(int sd, short type, void *arg)
if (http_write(treq->req, sd) && !http_want_write(treq->req))
btpd_ev_disable(&treq->ioev, EV_WRITE);
break;
case EV_TIMEOUT:
res.type = TR_RES_CONN;
tr_result(treq->tr, &res);
httptr_cancel(treq);
break;
default:
abort();
}
}

static void
nc_cb(void *arg, int error, int sd)
httptr_nc_cb(void *arg, int error, int sd)
{
struct http_tr_req *treq = arg;
struct tr_response res;
struct httptr_req *treq = arg;
if (error) {
tr_result(treq->tp, TR_RES_FAIL, -1);
res.type = TR_RES_CONN;
tr_result(treq->tr, &res);
http_cancel(treq->req);
http_tr_free(treq);
httptr_free(treq);
} else {
treq->sd = sd;
uint16_t flags =
(http_want_read(treq->req) ? EV_READ : 0) |
(http_want_write(treq->req) ? EV_WRITE : 0);
btpd_ev_new(&treq->ioev, sd, flags, sd_io_cb, treq);
btpd_ev_new(&treq->ioev, sd, flags, httptr_io_cb, treq);
btpd_timer_add(&treq->timer, (& (struct timespec) { 30, 0 }));
}
}

struct http_tr_req *
http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl)
struct httptr_req *
httptr_req(struct torrent *tp, struct tr_tier *tr, const char *aurl,
enum tr_event event)
{
char e_hash[61], e_id[61], url[512], qc;
const uint8_t *peer_id = btpd_get_peer_id();
@@ -211,28 +222,33 @@ http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl)
(long long)tp->total_length - cm_content(tp),
event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]);

struct http_tr_req *treq = btpd_calloc(1, sizeof(*treq));
struct httptr_req *treq = btpd_calloc(1, sizeof(*treq));
if (!http_get(&treq->req, url, "User-Agent: " BTPD_VERSION "\r\n",
http_cb, treq)) {
free(treq);
return NULL;
}
treq->tp = tp;
treq->tr = tr;
treq->event = event;
treq->buf = iobuf_init(4096);
if (treq->buf.error)
btpd_err("Out of memory.\n");
treq->tp = tp;
treq->event = event;
treq->tr = tr;
treq->sd = -1;
http_url = http_url_get(treq->req);
treq->nc = btpd_name_connect(http_url->host, http_url->port, nc_cb, treq);
treq->nc = btpd_name_connect(http_url->host, http_url->port,
httptr_nc_cb, treq);
timer_init(&treq->timer, httptr_io_cb, treq);
btpd_timer_add(&treq->timer, (& (struct timespec) { 60, 0 }));
return treq;
}

void
http_tr_cancel(struct http_tr_req *treq)
httptr_cancel(struct httptr_req *treq)
{
if (treq->sd == -1)
btpd_name_connect_cancel(treq->nc);
http_cancel(treq->req);
http_tr_free(treq);
httptr_free(treq);
}

+ 12
- 20
btpd/torrent.c 查看文件

@@ -96,25 +96,19 @@ torrent_start(struct tlib *tl)
benc_dget_mem(benc_dget_dct(mi, "info"), "pieces", NULL) - mi;

btpd_log(BTPD_L_BTPD, "Starting torrent '%s'.\n", torrent_name(tp));
if (tr_create(tp, mi) == 0) {
tl->tp = tp;
net_create(tp);
cm_create(tp, mi);
BTPDQ_INSERT_TAIL(&m_torrents, tp, entry);
m_ntorrents++;
cm_start(tp, 0);
free(mi);
if (m_ntorrents == 1) {
m_tsave = btpd_seconds + SAVE_INTERVAL;
m_savetp = tp;
}
return IPC_OK;
} else {
mi_free_files(tp->nfiles, tp->files);
free(tp);
free(mi);
return IPC_EBADTRACKER;
tr_create(tp, mi);
tl->tp = tp;
net_create(tp);
cm_create(tp, mi);
BTPDQ_INSERT_TAIL(&m_torrents, tp, entry);
m_ntorrents++;
cm_start(tp, 0);
free(mi);
if (m_ntorrents == 1) {
m_tsave = btpd_seconds + SAVE_INTERVAL;
m_savetp = tp;
}
return IPC_OK;
}

static void
@@ -158,8 +152,6 @@ torrent_stop(struct torrent *tp, int delete)
tlib_update_info(tp->tl, 0);
break;
case T_STOPPING:
if (tr_active(tp))
tr_stop(tp);
break;
}
}


+ 1
- 1
btpd/torrent.h 查看文件

@@ -18,7 +18,7 @@ struct torrent {
int delete;

struct content *cm;
struct tracker *tr;
struct trackers *tr;
struct net *net;

off_t total_length;


+ 218
- 160
btpd/tracker_req.c 查看文件

@@ -1,251 +1,309 @@
#include "btpd.h"
#include "http_client.h"

#define REQ_DELAY 1
#define STOP_ERRORS 5
#define REQ_TIMEOUT (& (struct timespec) { 120, 0 })
#define RETRY_WAIT (& (struct timespec) { rand_between(35, 70), 0 })
#define DEFAULT_INTERVAL rand_between(25 * 60, 30 * 60)
#define RETRY1_TIMEOUT (& (struct timespec) {240 + rand_between(0, 120), 0})
#define RETRY2_TIMEOUT (& (struct timespec) {900 + rand_between(0, 300), 0})

long tr_key;

static long m_tlast_req, m_tnext_req;

enum timer_type {
TIMER_NONE,
TIMER_TIMEOUT,
TIMER_INTERVAL,
TIMER_RETRY
struct tr_entry {
BTPDQ_ENTRY(tr_entry) entry;
char *url;
enum tr_type type;
};

struct tracker {
enum timer_type ttype;
enum tr_event event;
int interval;
unsigned nerrors;
int tier, url;
struct mi_announce *ann;
void *req;
struct timeout timer;
};

typedef struct _dummy *(*request_fun_t)(struct torrent *, enum tr_event,
const char *);
typedef void (*cancel_fun_t)(struct _dummy *);
BTPDQ_HEAD(tr_entry_tq, tr_entry);

struct tr_op {
int len;
const char *scheme;
request_fun_t request;
cancel_fun_t cancel;
struct tr_tier {
struct torrent *tp;
struct tr_entry *cur;
struct tr_entry_tq trackers;
struct timeout timer;
BTPDQ_ENTRY(tr_tier) entry;
void *req;
char *failure;
int interval;
int bad_conns;
int active;
int has_responded;
enum tr_event event;
};

static struct tr_op m_http_op = {
7, "http://", (request_fun_t)http_tr_req, (cancel_fun_t)http_tr_cancel
};
BTPDQ_HEAD(tr_tier_tq, tr_tier);

static struct tr_op *m_tr_ops[] = {
&m_http_op, NULL
struct trackers {
struct tr_tier_tq trackers;
};

static char *
get_url(struct tracker *tr)
static void *
req_send(struct tr_tier *t)
{
return tr->ann->tiers[tr->tier].urls[tr->url];
switch (t->cur->type) {
case TR_HTTP:
return httptr_req(t->tp, t, t->cur->url, t->event);
default:
abort();
}
}

static void
good_url(struct tracker *tr)
req_cancel(struct tr_tier *t)
{
char *set = tr->ann->tiers[tr->tier].urls[tr->url], *hold;
for (int i = 0; i <= tr->url; i++) {
hold = tr->ann->tiers[tr->tier].urls[i];
tr->ann->tiers[tr->tier].urls[i] = set;
set = hold;
switch (t->cur->type) {
case TR_HTTP:
httptr_cancel(t->req);
break;
default:
abort();
}
tr->tier = 0;
tr->url = 0;
t->req = NULL;
}

static void
next_url(struct tracker *tr)
entry_send(struct tr_tier *t, struct tr_entry *e, enum tr_event event)
{
tr->url = (tr->url + 1) % tr->ann->tiers[tr->tier].nurls;
if (tr->url == 0)
tr->tier = (tr->tier + 1) % tr->ann->ntiers;
if (t->req != NULL)
req_cancel(t);
t->event = event;
t->cur = e;
if (m_tlast_req > btpd_seconds - REQ_DELAY) {
m_tnext_req = max(m_tnext_req, m_tlast_req) + REQ_DELAY;
btpd_timer_add(&t->timer,
(& (struct timespec) { m_tnext_req - btpd_seconds, 0 }));
return;
}
btpd_timer_del(&t->timer);
if ((t->req = req_send(t)) == NULL) {
asprintf(&t->failure, "failed to create tracker message to '%s' (%s).",
e->url, strerror(errno));
t->active = 0;
return;
}
m_tlast_req = btpd_seconds;
}

struct tr_op *
get_op(struct tracker *tr)
static int
tier_active(struct tr_tier *t)
{
struct tr_op **opp;
char *url = get_url(tr);
for (opp = m_tr_ops; *opp != NULL; opp++)
if (strncasecmp((*opp)->scheme, url, (*opp)->len) == 0)
return *opp;
return NULL;
return t->active;
}

static void
tr_cancel(struct tracker *tr)
tier_timer_cb(int fd, short type, void *arg)
{
struct tr_op *op = get_op(tr);
assert(op != NULL);
op->cancel(tr->req);
tr->req = NULL;
struct tr_tier *t = arg;
assert(tier_active(t));
entry_send(t, BTPDQ_FIRST(&t->trackers), t->event);
}

static void
tr_set_stopped(struct torrent *tp)
tier_start(struct tr_tier *t)
{
struct tracker *tr = tp->tr;
btpd_timer_del(&tr->timer);
tr->ttype = TIMER_NONE;
if (tr->req != NULL)
tr_cancel(tr);
assert(!tier_active(t) || t->event == TR_EV_STOPPED);
if (t->failure != NULL) {
free(t->failure);
t->failure = NULL;
}
t->has_responded = 0;
t->bad_conns = 0;
t->active = 1;
entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_STARTED);
}

static void
tr_send(struct torrent *tp, enum tr_event event)
tier_stop(struct tr_tier *t)
{
struct tracker *tr = tp->tr;
struct tr_op *op = get_op(tr);
if (!tier_active(t) || t->event == TR_EV_STOPPED)
return;

tr->event = event;
if (tr->req != NULL)
tr_cancel(tr);
if (!t->has_responded && t->bad_conns > 1) {
btpd_timer_del(&t->timer);
if (t->req != NULL)
req_cancel(t);
t->active = 0;
} else
entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_STOPPED);
}

if (m_tlast_req > btpd_seconds - REQ_DELAY) {
m_tnext_req = max(m_tnext_req, m_tlast_req) + REQ_DELAY;
tr->ttype = TIMER_RETRY;
btpd_timer_add(&tr->timer,
(& (struct timespec) { m_tnext_req - btpd_seconds, 0 }));
return;
}
static void
tier_complete(struct tr_tier *t)
{
if (tier_active(t) && t->event == TR_EV_EMPTY)
entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_COMPLETED);
}

if ((op == NULL ||
(tr->req = op->request(tp, event, get_url(tr))) == NULL)) {
tr->nerrors++;
if (tr->event == TR_EV_STOPPED && tr->nerrors >= STOP_ERRORS) {
tr_set_stopped(tp);
return;
}
next_url(tr);
tr->ttype = TIMER_RETRY;
btpd_timer_add(&tr->timer, (& (struct timespec) { 5, 0 }));
} else {
m_tlast_req = btpd_seconds;
tr->ttype = TIMER_TIMEOUT;
btpd_timer_add(&tr->timer, REQ_TIMEOUT);
}
static void
add_tracker(struct tr_tier *t, const char *url)
{
struct tr_entry *e;
struct http_url *hu;
if ((hu = http_url_parse(url)) != NULL) {
http_url_free(hu);
e = btpd_calloc(1, sizeof(*e));
if ((e->url = strdup(url)) == NULL)
btpd_err("Out of memory.\n");
e->type = TR_HTTP;
} else
return;
BTPDQ_INSERT_TAIL(&t->trackers, e, entry);
}

void
tr_result(struct torrent *tp, enum tr_res res, int interval)
{
struct tracker *tr = tp->tr;
tr->req = NULL;
if (tr->event == TR_EV_STOPPED &&
(res == TR_RES_OK || tr->nerrors >= STOP_ERRORS - 1))
tr_set_stopped(tp);
else if (res == TR_RES_OK) {
good_url(tr);
tr->interval = interval;
tr->nerrors = 0;
tr->ttype = TIMER_INTERVAL;
btpd_timer_add(&tr->timer, (& (struct timespec) { tr->interval, 0}));
static struct tr_tier *
tier_create(struct torrent *tp, struct mi_tier *tier)
{
struct tr_tier *t = btpd_calloc(1, sizeof(*t));
BTPDQ_INIT(&t->trackers);
for (int i = 0; i < tier->nurls; i++)
add_tracker(t, tier->urls[i]);
if (!BTPDQ_EMPTY(&t->trackers)) {
t->tp = tp;
t->interval = -1;
t->event = TR_EV_STOPPED;
timer_init(&t->timer, tier_timer_cb, t);
return t;
} else {
tr->nerrors++;
tr->ttype = TIMER_RETRY;
btpd_timer_add(&tr->timer, RETRY_WAIT);
next_url(tr);
free(t);
return NULL;
}
}

static void
timer_cb(int fd, short type, void *arg)
{
struct torrent *tp = arg;
struct tracker *tr = tp->tr;
switch (tr->ttype) {
case TIMER_TIMEOUT:
btpd_log(BTPD_L_ERROR, "Tracker request timed out for '%s'.\n",
torrent_name(tp));
tr->nerrors++;
if (tr->event == TR_EV_STOPPED && tr->nerrors >= STOP_ERRORS) {
tr_set_stopped(tp);
break;
}
tr_cancel(tr);
next_url(tr);
case TIMER_RETRY:
tr_send(tp, tr->event);
break;
case TIMER_INTERVAL:
tr_send(tp, TR_EV_EMPTY);
break;
default:
abort();
tier_kill(struct tr_tier *t)
{
struct tr_entry *e, *next;
if (t->failure != NULL)
free(t->failure);
btpd_timer_del(&t->timer);
if (t->req != NULL)
req_cancel(t);
BTPDQ_FOREACH_MUTABLE(e, &t->trackers, entry , next) {
free(e->url);
free(e);
}
free(t);
}

int
void
tr_create(struct torrent *tp, const char *mi)
{
int i;
struct tr_tier *t;
struct mi_announce *ann;
tp->tr = btpd_calloc(1, sizeof(*tp->tr));
if ((tp->tr->ann = mi_announce(mi)) == NULL)
BTPDQ_INIT(&tp->tr->trackers);
if ((ann = mi_announce(mi)) == NULL)
btpd_err("Out of memory.\n");
timer_init(&tp->tr->timer, timer_cb, tp);
return 0;
for (i = 0; i < ann->ntiers; i++)
if ((t = tier_create(tp, &ann->tiers[i])) != NULL)
BTPDQ_INSERT_TAIL(&tp->tr->trackers, t, entry);
mi_free_announce(ann);
}

void
tr_kill(struct torrent *tp)
{
struct tracker *tr = tp->tr;
struct tr_tier *t, *next;
BTPDQ_FOREACH_MUTABLE(t, &tp->tr->trackers, entry, next)
tier_kill(t);
free(tp->tr);
tp->tr = NULL;
btpd_timer_del(&tr->timer);
if (tr->req != NULL)
tr_cancel(tr);
mi_free_announce(tr->ann);
free(tr);
}

void
tr_start(struct torrent *tp)
{
tr_send(tp, TR_EV_STARTED);
struct tr_tier *t;
BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
tier_start(t);
}

void
tr_refresh(struct torrent *tp)
tr_stop(struct torrent *tp)
{
tr_send(tp, TR_EV_EMPTY);
struct tr_tier *t;
BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
tier_stop(t);
}

void
tr_complete(struct torrent *tp)
{
tr_send(tp, TR_EV_COMPLETED);
struct tr_tier *t;
BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
tier_complete(t);
}

void
tr_stop(struct torrent *tp)
int
tr_active(struct torrent *tp)
{
if (tp->tr->event == TR_EV_STOPPED)
tr_set_stopped(tp);
else
tr_send(tp, TR_EV_STOPPED);
struct tr_tier *t;
BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
if (tier_active(t))
return 1;
return 0;
}

int
tr_active(struct torrent *tp)
tr_good_count(struct torrent *tp)
{
return tp->tr->ttype != TIMER_NONE;
int count = 0;
struct tr_tier *t;
BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
if (tier_active(t) && t->bad_conns == 0)
count++;
return count;
}

unsigned
tr_errors(struct torrent *tp)
void
tr_result(struct tr_tier *t, struct tr_response *res)
{
return tp->tr->nerrors;
struct tr_entry *e;
t->req = NULL;
switch (res->type) {
case TR_RES_FAIL:
t->active = 0;
t->failure = benc_str(res->mi_failure, NULL, NULL);
btpd_log(BTPD_L_ERROR, "tracker at '%s' failed (%s).\n",
t->cur->url, t->failure);
break;
case TR_RES_CONN:
if ((e = BTPDQ_NEXT(t->cur, entry)) != NULL) {
entry_send(t, e, t->event);
break;
}
t->bad_conns++;
if (t->event == TR_EV_STOPPED && t->bad_conns > 1)
t->active = 0;
else if (t->bad_conns == 1)
entry_send(t, BTPDQ_FIRST(&t->trackers), t->event);
else if (t->bad_conns == 2)
btpd_timer_add(&t->timer, RETRY1_TIMEOUT);
else
btpd_timer_add(&t->timer, RETRY2_TIMEOUT);
break;
case TR_RES_BAD:
case TR_RES_OK:
if (t->event == TR_EV_STOPPED)
t->active = 0;
else {
t->event = TR_EV_EMPTY;
if (res->interval > 0)
t->interval = res->interval;
btpd_timer_add(&t->timer, (& (struct timespec) {
t->interval > 0 ? t->interval : DEFAULT_INTERVAL, 0 }));
}
t->bad_conns = 0;
t->has_responded = 1;
BTPDQ_REMOVE(&t->trackers, t->cur, entry);
BTPDQ_INSERT_HEAD(&t->trackers, t->cur, entry);
break;
default:
abort();
}
}

void


+ 17
- 14
btpd/tracker_req.h 查看文件

@@ -8,28 +8,31 @@ enum tr_event {
TR_EV_EMPTY
};

enum tr_res {
TR_RES_OK,
TR_RES_FAIL
extern long tr_key;

enum tr_type { TR_HTTP };

struct tr_response {
enum {
TR_RES_FAIL, TR_RES_CONN, TR_RES_BAD, TR_RES_OK
} type;
const char *mi_failure;
int interval;
};

extern long tr_key;
struct tr_tier;

int tr_create(struct torrent *tp, const char *mi);
void tr_create(struct torrent *tp, const char *mi);
void tr_kill(struct torrent *tp);
void tr_start(struct torrent *tp);
void tr_stop(struct torrent *tp);
void tr_refresh(struct torrent *tp);
void tr_complete(struct torrent *tp);
unsigned tr_errors(struct torrent *tp);
int tr_active(struct torrent *tp);
void tr_result(struct tr_tier *t, struct tr_response *res);
int tr_good_count(struct torrent *tp);

void tr_result(struct torrent *tp, enum tr_res res, int interval);

struct http_tr_req;

struct http_tr_req *http_tr_req(struct torrent *tp, enum tr_event event,
const char *aurl);
void http_tr_cancel(struct http_tr_req *treq);
struct httptr_req *httptr_req(struct torrent *tp, struct tr_tier *tr,
const char *url, enum tr_event event);
void httptr_cancel(struct httptr_req *req);

#endif

Loading…
取消
儲存