Browse Source

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.
master
Richard Nyberg 19 years ago
parent
commit
c8f9335e6e
6 changed files with 113 additions and 19 deletions
  1. +40
    -9
      btpd/btpd.c
  2. +4
    -1
      btpd/btpd.h
  3. +39
    -8
      btpd/torrent.c
  4. +1
    -0
      btpd/torrent.h
  5. +28
    -1
      btpd/tracker_req.c
  6. +1
    -0
      btpd/tracker_req.h

+ 40
- 9
btpd/btpd.c View File

@@ -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


+ 4
- 1
btpd/btpd.h View File

@@ -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

+ 39
- 8
btpd/torrent.c View File

@@ -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);
}
}

+ 1
- 0
btpd/torrent.h View File

@@ -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

+ 28
- 1
btpd/tracker_req.c View File

@@ -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)
{


+ 1
- 0
btpd/tracker_req.h View File

@@ -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

Loading…
Cancel
Save