diff options
| -rw-r--r-- | btpd/cli_if.c | 3 | ||||
| -rw-r--r-- | btpd/http_tr_if.c | 126 | ||||
| -rw-r--r-- | btpd/torrent.c | 32 | ||||
| -rw-r--r-- | btpd/torrent.h | 2 | ||||
| -rw-r--r-- | btpd/tracker_req.c | 378 | ||||
| -rw-r--r-- | btpd/tracker_req.h | 31 |
6 files changed, 320 insertions, 252 deletions
diff --git a/btpd/cli_if.c b/btpd/cli_if.c index a026b9e..e129b88 100644 --- a/btpd/cli_if.c +++ b/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; diff --git a/btpd/http_tr_if.c b/btpd/http_tr_if.c index 376bb02..beb29c0 100644 --- a/btpd/http_tr_if.c +++ b/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); } diff --git a/btpd/torrent.c b/btpd/torrent.c index c77e9da..c48e844 100644 --- a/btpd/torrent.c +++ b/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; } } diff --git a/btpd/torrent.h b/btpd/torrent.h index e2a0218..e8eee4c 100644 --- a/btpd/torrent.h +++ b/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; diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c index 06e281d..32c56e9 100644 --- a/btpd/tracker_req.c +++ b/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 diff --git a/btpd/tracker_req.h b/btpd/tracker_req.h index caedeb9..3ebd7a2 100644 --- a/btpd/tracker_req.h +++ b/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 |