From be9d0e58a691b4c59b847f1504eaea6b8a4e213b Mon Sep 17 00:00:00 2001 From: Richard Nyberg Date: Fri, 30 Jan 2009 11:18:50 +0100 Subject: Set failures on individual trackers, not on tiers. Unfortunately many don't understand the tracker tiers and put unrelated trackers in the same tier. Thus btpd can't assume that a failure from one tracker in a tier is valid for all trackers in that tier. --- btpd/tracker_req.c | 66 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c index a792e7f..9debcf5 100644 --- a/btpd/tracker_req.c +++ b/btpd/tracker_req.c @@ -12,6 +12,7 @@ static long m_tlast_req, m_tnext_req; struct tr_entry { BTPDQ_ENTRY(tr_entry) entry; + char *failure; char *url; enum tr_type type; }; @@ -25,7 +26,6 @@ struct tr_tier { struct timeout timer; BTPDQ_ENTRY(tr_tier) entry; void *req; - char *failure; int interval; int bad_conns; int active; @@ -39,6 +39,26 @@ struct trackers { struct tr_tier_tq trackers; }; +static struct tr_entry * +first_nonfailed(struct tr_tier *t) +{ + struct tr_entry *e; + BTPDQ_FOREACH(e, &t->trackers, entry) + if (e->failure == NULL) + return e; + abort(); +} + +static int +all_failed(struct tr_tier *t) +{ + struct tr_entry *e; + BTPDQ_FOREACH(e, &t->trackers, entry) + if (e->failure == NULL) + return 0; + return 1; +} + static void * req_send(struct tr_tier *t) { @@ -77,12 +97,9 @@ entry_send(struct tr_tier *t, struct tr_entry *e, enum tr_event event) return; } btpd_timer_del(&t->timer); - if ((t->req = req_send(t)) == NULL) { - asprintf(&t->failure, "failed to create tracker message to '%s' (%s).", + if ((t->req = req_send(t)) == NULL) + btpd_err("failed to create tracker message to '%s' (%s).", e->url, strerror(errno)); - t->active = 0; - return; - } m_tlast_req = btpd_seconds; } @@ -96,18 +113,20 @@ static void tier_timer_cb(int fd, short type, void *arg) { struct tr_tier *t = arg; - assert(tier_active(t)); - entry_send(t, BTPDQ_FIRST(&t->trackers), t->event); + assert(tier_active(t) && !all_failed(t)); + entry_send(t, first_nonfailed(t), t->event); } static void tier_start(struct tr_tier *t) { + struct tr_entry *e; assert(!tier_active(t) || t->event == TR_EV_STOPPED); - if (t->failure != NULL) { - free(t->failure); - t->failure = NULL; - } + BTPDQ_FOREACH(e, &t->trackers, entry) + if (e->failure != NULL) { + free(e->failure); + e->failure = NULL; + } t->has_responded = 0; t->bad_conns = 0; t->active = 1; @@ -126,7 +145,7 @@ tier_stop(struct tr_tier *t) req_cancel(t); t->active = 0; } else - entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_STOPPED); + entry_send(t, first_nonfailed(t), TR_EV_STOPPED); } static void @@ -175,12 +194,12 @@ static void 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) { + if (e->failure != NULL) + free(e->failure); free(e->url); free(e); } @@ -265,13 +284,18 @@ tr_result(struct tr_tier *t, struct tr_response *res) t->req = NULL; switch (res->type) { case TR_RES_FAIL: - t->active = 0; - t->failure = benc_str(res->mi_failure, NULL, NULL); + t->cur->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; + t->cur->url, t->cur->failure); + if (all_failed(t)) { + t->active = 0; + break; + } case TR_RES_CONN: - if ((e = BTPDQ_NEXT(t->cur, entry)) != NULL) { + e = t->cur; + while ((e = BTPDQ_NEXT(e, entry)) != NULL && e->failure != NULL) + ; + if (e != NULL) { entry_send(t, e, t->event); break; } @@ -286,6 +310,8 @@ tr_result(struct tr_tier *t, struct tr_response *res) btpd_timer_add(&t->timer, RETRY2_TIMEOUT); break; case TR_RES_BAD: + btpd_log(BTPD_L_ERROR, "bad data from tracker '%s' for '%s'.\n", + t->cur->url, torrent_name(t->tp)); case TR_RES_OK: if (t->event == TR_EV_STOPPED) t->active = 0; -- cgit 1.4.1