deactivate on shutdown. To not risk hanging indefinitely on unresponsive trackers, btpd will cancel tracker requests after a while.master
@@ -34,27 +34,58 @@ static struct event m_sigint; | |||
static struct event m_sigterm; | |||
static unsigned m_ntorrents; | |||
static struct torrent_tq m_torrents = BTPDQ_HEAD_INITIALIZER(m_torrents); | |||
static unsigned m_nactive; | |||
static int m_shutdown; | |||
void | |||
btpd_shutdown(void) | |||
btpd_exit(int code) | |||
{ | |||
struct torrent *tp; | |||
btpd_log(BTPD_L_BTPD, "Exiting.\n"); | |||
exit(code); | |||
} | |||
void | |||
btpd_tp_activated(struct torrent *tp) | |||
{ | |||
m_nactive++; | |||
} | |||
void | |||
btpd_tp_deactivated(struct torrent *tp) | |||
{ | |||
m_nactive--; | |||
if (m_nactive == 0 && m_shutdown) | |||
btpd_exit(0); | |||
} | |||
tp = BTPDQ_FIRST(&m_torrents); | |||
while (tp != NULL) { | |||
struct torrent *next = BTPDQ_NEXT(tp, entry); | |||
static void | |||
grace_cb(int fd, short type, void *arg) | |||
{ | |||
struct torrent *tp; | |||
BTPDQ_FOREACH(tp, &m_torrents, entry) | |||
torrent_deactivate(tp); | |||
tp = next; | |||
} | |||
void | |||
btpd_shutdown(struct timeval *grace_tv) | |||
{ | |||
if (m_nactive == 0) | |||
btpd_exit(0); | |||
else { | |||
struct torrent *tp; | |||
m_shutdown = 1; | |||
BTPDQ_FOREACH(tp, &m_torrents, entry) | |||
torrent_deactivate(tp); | |||
if (grace_tv != NULL) | |||
event_once(-1, EV_TIMEOUT, grace_cb, NULL, grace_tv); | |||
} | |||
btpd_log(BTPD_L_BTPD, "Exiting.\n"); | |||
exit(0); | |||
} | |||
static void | |||
signal_cb(int signal, short type, void *arg) | |||
{ | |||
btpd_log(BTPD_L_BTPD, "Got signal %d.\n", signal); | |||
btpd_shutdown(); | |||
btpd_shutdown((& (struct timeval) { 30, 0 })); | |||
} | |||
void | |||
@@ -48,7 +48,7 @@ void btpd_err(const char *fmt, ...); | |||
void *btpd_malloc(size_t size); | |||
void *btpd_calloc(size_t nmemb, size_t size); | |||
void btpd_shutdown(void); | |||
void btpd_shutdown(struct timeval *grace_tv); | |||
struct torrent * btpd_get_torrent(const uint8_t *hash); | |||
const struct torrent_tq *btpd_get_torrents(void); | |||
@@ -64,4 +64,7 @@ void td_release_lock(void); | |||
void td_post(void (*fun)(void *), void *arg); | |||
void td_post_end(void); | |||
void btpd_tp_activated(struct torrent *tp); | |||
void btpd_tp_deactivated(struct torrent *tp); | |||
#endif |
@@ -51,18 +51,36 @@ torrent_block_size(struct torrent *tp, uint32_t piece, uint32_t nblocks, | |||
void | |||
torrent_activate(struct torrent *tp) | |||
{ | |||
assert(tp->state == T_INACTIVE); | |||
tp->state = T_STARTING; | |||
cm_start(tp); | |||
if (tp->state == T_INACTIVE) { | |||
tp->state = T_STARTING; | |||
cm_start(tp); | |||
btpd_tp_activated(tp); | |||
} | |||
} | |||
void | |||
torrent_deactivate(struct torrent *tp) | |||
{ | |||
tp->state = T_STOPPING; | |||
tr_stop(tp); | |||
net_del_torrent(tp); | |||
cm_stop(tp); | |||
switch (tp->state) { | |||
case T_INACTIVE: | |||
break; | |||
case T_STARTING: | |||
case T_ACTIVE: | |||
tp->state = T_STOPPING; | |||
if (tp->tr != NULL) | |||
tr_stop(tp); | |||
if (tp->net != NULL) | |||
net_del_torrent(tp); | |||
if (tp->cm != NULL) | |||
cm_stop(tp); | |||
break; | |||
case T_STOPPING: | |||
if (tp->tr != NULL) | |||
tr_destroy(tp); | |||
break; | |||
default: | |||
abort(); | |||
} | |||
} | |||
int | |||
@@ -110,5 +128,18 @@ void | |||
torrent_on_cm_stopped(struct torrent *tp) | |||
{ | |||
assert(tp->state == T_STOPPING); | |||
tp->state = T_INACTIVE; | |||
if (tp->tr == NULL) { | |||
tp->state = T_INACTIVE; | |||
btpd_tp_deactivated(tp); | |||
} | |||
} | |||
void | |||
torrent_on_tr_stopped(struct torrent *tp) | |||
{ | |||
assert(tp->state == T_STOPPING); | |||
if (tp->cm == NULL) { | |||
tp->state = T_INACTIVE; | |||
btpd_tp_deactivated(tp); | |||
} | |||
} |
@@ -36,5 +36,6 @@ uint32_t torrent_block_size(struct torrent *tp, uint32_t piece, | |||
void torrent_on_cm_stopped(struct torrent *tp); | |||
void torrent_on_cm_started(struct torrent *tp); | |||
void torrent_on_tr_stopped(struct torrent *tp); | |||
#endif |
@@ -5,6 +5,7 @@ | |||
#include "benc.h" | |||
#include "subr.h" | |||
#include "http.h" | |||
#include "tracker_req.h" | |||
#define REQ_TIMEOUT (& (struct timeval) { 120, 0 }) | |||
#define RETRY_WAIT (& (struct timeval) { rand_between(35, 70), 0 }) | |||
@@ -128,14 +129,19 @@ http_cb(struct http *req, struct http_res *res, void *arg) | |||
struct torrent *tp = arg; | |||
struct tracker *tr = tp->tr; | |||
assert(tr->ttype == TIMER_TIMEOUT); | |||
tr->req = NULL; | |||
if ((http_succeeded(res) && | |||
parse_reply(tp, res->content, res->length) == 0)) { | |||
tr->nerrors = 0; | |||
tr->ttype = TIMER_INTERVAL; | |||
event_add(&tr->timer, (& (struct timeval) { tr->interval, 0 })); | |||
} else { | |||
tr->nerrors++; | |||
tr->ttype = TIMER_RETRY; | |||
event_add(&tr->timer, RETRY_WAIT); | |||
} | |||
if (tr->event == TR_EV_STOPPED && (tr->nerrors == 0 || tr->nerrors >= 5)) | |||
tr_destroy(tp); | |||
} | |||
static void | |||
@@ -145,8 +151,17 @@ timer_cb(int fd, short type, void *arg) | |||
struct tracker *tr = tp->tr; | |||
switch (tr->ttype) { | |||
case TIMER_TIMEOUT: | |||
tr->nerrors++; | |||
if (tr->event == TR_EV_STOPPED && tr->nerrors >= 5) { | |||
tr_destroy(tp); | |||
break; | |||
} | |||
case TIMER_RETRY: | |||
tr_send(tp, tp->tr->event); | |||
if (tr->event == TR_EV_STOPPED) { | |||
event_add(&tr->timer, REQ_TIMEOUT); | |||
http_redo(&tr->req); | |||
} else | |||
tr_send(tp, tr->event); | |||
break; | |||
case TIMER_INTERVAL: | |||
tr_send(tp, TR_EV_EMPTY); | |||
@@ -205,6 +220,18 @@ tr_start(struct torrent *tp) | |||
return 0; | |||
} | |||
void | |||
tr_destroy(struct torrent *tp) | |||
{ | |||
struct tracker *tr = tp->tr; | |||
tp->tr = NULL; | |||
event_del(&tr->timer); | |||
if (tr->req != NULL) | |||
http_cancel(tr->req); | |||
free(tr); | |||
torrent_on_tr_stopped(tp); | |||
} | |||
void | |||
tr_refresh(struct torrent *tp) | |||
{ | |||
@@ -5,5 +5,6 @@ int tr_start(struct torrent *tp); | |||
void tr_stop(struct torrent *tp); | |||
void tr_refresh(struct torrent *tp); | |||
void tr_complete(struct torrent *tp); | |||
void tr_destroy(struct torrent *tp); | |||
#endif |