diff options
| author | Richard Nyberg <rnyberg@murmeldjur.se> | 2006-02-01 21:56:59 +0000 |
|---|---|---|
| committer | Richard Nyberg <rnyberg@murmeldjur.se> | 2006-02-01 21:56:59 +0000 |
| commit | c8f9335e6eb25b464803664abd8258869d564388 (patch) | |
| tree | 39ce9f8af983bf5a1685dd337817f843672a3589 | |
| parent | 44165a86d05e6eebc1aa0c3665a7ade27ebd535a (diff) | |
| download | btpd-c8f9335e6eb25b464803664abd8258869d564388.tar.gz btpd-c8f9335e6eb25b464803664abd8258869d564388.zip | |
Torrents can now be deactivated and btpd will wait for all torrents to
deactivate on shutdown. To not risk hanging indefinitely on unresponsive trackers, btpd will cancel tracker requests after a while.
| -rw-r--r-- | btpd/btpd.c | 49 | ||||
| -rw-r--r-- | btpd/btpd.h | 5 | ||||
| -rw-r--r-- | btpd/torrent.c | 47 | ||||
| -rw-r--r-- | btpd/torrent.h | 1 | ||||
| -rw-r--r-- | btpd/tracker_req.c | 29 | ||||
| -rw-r--r-- | btpd/tracker_req.h | 1 |
6 files changed, 113 insertions, 19 deletions
diff --git a/btpd/btpd.c b/btpd/btpd.c index 161c780..3a4a346 100644 --- a/btpd/btpd.c +++ b/btpd/btpd.c @@ -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 diff --git a/btpd/btpd.h b/btpd/btpd.h index 452087c..6feba67 100644 --- a/btpd/btpd.h +++ b/btpd/btpd.h @@ -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 diff --git a/btpd/torrent.c b/btpd/torrent.c index c362ad5..5c8ff89 100644 --- a/btpd/torrent.c +++ b/btpd/torrent.c @@ -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); + } } diff --git a/btpd/torrent.h b/btpd/torrent.h index 73a26c7..c84c9be 100644 --- a/btpd/torrent.h +++ b/btpd/torrent.h @@ -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 diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c index ebd2fde..5325a3d 100644 --- a/btpd/tracker_req.c +++ b/btpd/tracker_req.c @@ -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); @@ -206,6 +221,18 @@ tr_start(struct torrent *tp) } 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) { tr_send(tp, TR_EV_EMPTY); diff --git a/btpd/tracker_req.h b/btpd/tracker_req.h index 586bbb6..95cc170 100644 --- a/btpd/tracker_req.h +++ b/btpd/tracker_req.h @@ -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 |