Browse Source

o Make the torrent sub struct exist for whole life time of the torrent.

o Better code for stopping the tracker. No more need for the http_redo hack.
master
Richard Nyberg 19 years ago
parent
commit
926838a009
7 changed files with 132 additions and 69 deletions
  1. +25
    -15
      btpd/content.c
  2. +5
    -1
      btpd/content.h
  3. +20
    -5
      btpd/net.c
  4. +6
    -2
      btpd/net.h
  5. +23
    -17
      btpd/torrent.c
  6. +49
    -27
      btpd/tracker_req.c
  7. +4
    -2
      btpd/tracker_req.h

+ 25
- 15
btpd/content.c View File

@@ -159,7 +159,7 @@ add_todo(struct content *cm, struct cm_op *op)
} }


void void
cm_destroy(struct torrent *tp)
cm_kill(struct torrent *tp)
{ {
struct content *cm = tp->cm; struct content *cm = tp->cm;
bts_close(cm->rds); bts_close(cm->rds);
@@ -168,7 +168,6 @@ cm_destroy(struct torrent *tp)
free(cm->hold_field); free(cm->hold_field);
free(cm->pos_field); free(cm->pos_field);
tp->cm = NULL; tp->cm = NULL;
torrent_on_cm_stopped(tp);
} }


void void
@@ -215,7 +214,14 @@ cm_stop(struct torrent *tp)
cm_write_done(tp); cm_write_done(tp);


if (BTPDQ_EMPTY(&cm->todoq)) if (BTPDQ_EMPTY(&cm->todoq))
cm_destroy(tp);
torrent_on_cm_stopped(tp);
}

int
cm_active(struct torrent *tp)
{
struct content *cm = tp->cm;
return cm->active || !BTPDQ_EMPTY(&cm->todoq);
} }


#define SAVE_INTERVAL (& (struct timeval) { 15, 0 }) #define SAVE_INTERVAL (& (struct timeval) { 15, 0 })
@@ -261,14 +267,14 @@ cm_td_cb(void *arg)
assert(cm->npieces_got < tp->meta.npieces); assert(cm->npieces_got < tp->meta.npieces);
cm->npieces_got++; cm->npieces_got++;
set_bit(cm->piece_field, op->u.test.piece); set_bit(cm->piece_field, op->u.test.piece);
if (tp->net != NULL)
if (net_active(tp))
dl_on_ok_piece(op->tp->net, op->u.test.piece); dl_on_ok_piece(op->tp->net, op->u.test.piece);
if (cm_full(tp)) if (cm_full(tp))
cm_write_done(tp); cm_write_done(tp);
} else { } else {
cm->ncontent_bytes -= torrent_piece_size(tp, op->u.test.piece); cm->ncontent_bytes -= torrent_piece_size(tp, op->u.test.piece);
bzero(cm->block_field + op->u.test.piece * cm->bppbf, cm->bppbf); bzero(cm->block_field + op->u.test.piece * cm->bppbf, cm->bppbf);
if (tp->net != NULL)
if (net_active(tp))
dl_on_bad_piece(tp->net, op->u.test.piece); dl_on_bad_piece(tp->net, op->u.test.piece);
} }
break; break;
@@ -281,16 +287,14 @@ cm_td_cb(void *arg)
if (!BTPDQ_EMPTY(&cm->todoq)) if (!BTPDQ_EMPTY(&cm->todoq))
run_todo(cm); run_todo(cm);
else if (!cm->active) else if (!cm->active)
cm_destroy(tp);
torrent_on_cm_stopped(tp);
} }


int
cm_start(struct torrent *tp)
void
cm_create(struct torrent *tp)
{ {
int err;
struct content *cm = btpd_calloc(1, sizeof(*cm));
size_t pfield_size = ceil(tp->meta.npieces / 8.0); size_t pfield_size = ceil(tp->meta.npieces / 8.0);
cm->active = 1;
struct content *cm = btpd_calloc(1, sizeof(*cm));
cm->bppbf = ceil((double)tp->meta.piece_length / (1 << 17)); cm->bppbf = ceil((double)tp->meta.piece_length / (1 << 17));
cm->piece_field = btpd_calloc(pfield_size, 1); cm->piece_field = btpd_calloc(pfield_size, 1);
cm->hold_field = btpd_calloc(pfield_size, 1); cm->hold_field = btpd_calloc(pfield_size, 1);
@@ -298,18 +302,24 @@ cm_start(struct torrent *tp)
cm->block_field = btpd_calloc(tp->meta.npieces * cm->bppbf, 1); cm->block_field = btpd_calloc(tp->meta.npieces * cm->bppbf, 1);


BTPDQ_INIT(&cm->todoq); BTPDQ_INIT(&cm->todoq);
evtimer_set(&cm->save_timer, save_timer_cb, tp);


if ((err = bts_open(&cm->rds, &tp->meta, fd_cb_rd, tp)) != 0)
btpd_err("Error opening stream (%s).\n", strerror(err));
tp->cm = cm; tp->cm = cm;
}


evtimer_set(&cm->save_timer, save_timer_cb, tp);
void
cm_start(struct torrent *tp)
{
struct content *cm = tp->cm;

if ((errno = bts_open(&cm->rds, &tp->meta, fd_cb_rd, tp)) != 0)
btpd_err("Error opening stream (%s).\n", strerror(errno));


cm->active = 1;
struct cm_op *op = btpd_calloc(1, sizeof(*op)); struct cm_op *op = btpd_calloc(1, sizeof(*op));
op->tp = tp; op->tp = tp;
op->type = CM_START; op->type = CM_START;
add_todo(cm, op); add_todo(cm, op);
return 0;
} }


int int


+ 5
- 1
btpd/content.h View File

@@ -3,9 +3,13 @@


void cm_init(void); void cm_init(void);


int cm_start(struct torrent *tp);
void cm_create(struct torrent *tp);
void cm_kill(struct torrent *tp);

void cm_start(struct torrent *tp);
void cm_stop(struct torrent * tp); void cm_stop(struct torrent * tp);


int cm_active(struct torrent *tp);
int cm_full(struct torrent *tp); int cm_full(struct torrent *tp);


uint8_t *cm_get_piece_field(struct torrent *tp); uint8_t *cm_get_piece_field(struct torrent *tp);


+ 20
- 5
btpd/net.c View File

@@ -52,7 +52,7 @@ net_torrent_has_peer(struct net *n, const uint8_t *id)
} }


void void
net_add_torrent(struct torrent *tp)
net_create(struct torrent *tp)
{ {
size_t field_size = ceil(tp->meta.npieces / 8.0); size_t field_size = ceil(tp->meta.npieces / 8.0);
size_t mem = sizeof(*(tp->net)) + field_size + size_t mem = sizeof(*(tp->net)) + field_size +
@@ -62,21 +62,32 @@ net_add_torrent(struct torrent *tp)
n->tp = tp; n->tp = tp;
tp->net = n; tp->net = n;


n->active = 1;
BTPDQ_INIT(&n->getlst); BTPDQ_INIT(&n->getlst);


n->busy_field = (uint8_t *)(n + 1); n->busy_field = (uint8_t *)(n + 1);
n->piece_count = (unsigned *)(n->busy_field + field_size); n->piece_count = (unsigned *)(n->busy_field + field_size);
}

void
net_kill(struct torrent *tp)
{
free(tp->net);
tp->net = NULL;
}


void
net_start(struct torrent *tp)
{
struct net *n = tp->net;
BTPDQ_INSERT_HEAD(&m_torrents, n, entry); BTPDQ_INSERT_HEAD(&m_torrents, n, entry);
m_ntorrents++; m_ntorrents++;
n->active = 1;
} }


void void
net_del_torrent(struct torrent *tp)
net_stop(struct torrent *tp)
{ {
struct net *n = tp->net; struct net *n = tp->net;
tp->net = NULL;


assert(m_ntorrents > 0); assert(m_ntorrents > 0);
m_ntorrents--; m_ntorrents--;
@@ -104,8 +115,12 @@ net_del_torrent(struct torrent *tp)
peer_kill(p); peer_kill(p);
p = next; p = next;
} }
}


free(n);
int
net_active(struct torrent *tp)
{
return tp->net->active;
} }


void void


+ 6
- 2
btpd/net.h View File

@@ -20,8 +20,12 @@ extern unsigned net_npeers;


void net_init(void); void net_init(void);


void net_add_torrent(struct torrent *tp);
void net_del_torrent(struct torrent *tp);
void net_create(struct torrent *tp);
void net_kill(struct torrent *tp);

void net_start(struct torrent *tp);
void net_stop(struct torrent *tp);
int net_active(struct torrent *tp);


int net_torrent_has_peer(struct net *n, const uint8_t *id); int net_torrent_has_peer(struct net *n, const uint8_t *id);




+ 23
- 17
btpd/torrent.c View File

@@ -126,11 +126,18 @@ torrent_start(const uint8_t *hash)
bcopy(relpath, tp->relpath, RELPATH_SIZE); bcopy(relpath, tp->relpath, RELPATH_SIZE);
tp->meta = *mi; tp->meta = *mi;
free(mi); free(mi);
BTPDQ_INSERT_TAIL(&m_torrents, tp, entry);
m_ntorrents++;
cm_start(tp);


return 0;
if ((error = tr_create(tp)) == 0) {
net_create(tp);
cm_create(tp);
BTPDQ_INSERT_TAIL(&m_torrents, tp, entry);
m_ntorrents++;
cm_start(tp);
} else {
clear_metainfo(&tp->meta);
free(tp);
}
return error;
} }


void void
@@ -140,16 +147,13 @@ torrent_stop(struct torrent *tp)
case T_STARTING: case T_STARTING:
case T_ACTIVE: case T_ACTIVE:
tp->state = T_STOPPING; 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);
tr_stop(tp);
net_stop(tp);
cm_stop(tp);
break; break;
case T_STOPPING: case T_STOPPING:
if (tp->tr != NULL)
tr_destroy(tp);
if (tr_active(tp))
tr_stop(tp);
break; break;
} }
} }
@@ -162,6 +166,9 @@ torrent_kill(struct torrent *tp)
m_ntorrents--; m_ntorrents--;
BTPDQ_REMOVE(&m_torrents, tp, entry); BTPDQ_REMOVE(&m_torrents, tp, entry);
clear_metainfo(&tp->meta); clear_metainfo(&tp->meta);
tr_kill(tp);
net_kill(tp);
cm_kill(tp);
free(tp); free(tp);
if (m_ntorrents == 0) if (m_ntorrents == 0)
btpd_on_no_torrents(); btpd_on_no_torrents();
@@ -171,16 +178,15 @@ void
torrent_on_cm_started(struct torrent *tp) torrent_on_cm_started(struct torrent *tp)
{ {
tp->state = T_ACTIVE; tp->state = T_ACTIVE;
net_add_torrent(tp);
if (tr_start(tp) != 0)
torrent_stop(tp);
net_start(tp);
tr_start(tp);
} }


void void
torrent_on_cm_stopped(struct torrent *tp) torrent_on_cm_stopped(struct torrent *tp)
{ {
assert(tp->state == T_STOPPING); assert(tp->state == T_STOPPING);
if (tp->tr == NULL)
if (!tr_active(tp))
torrent_kill(tp); torrent_kill(tp);
} }


@@ -188,6 +194,6 @@ void
torrent_on_tr_stopped(struct torrent *tp) torrent_on_tr_stopped(struct torrent *tp)
{ {
assert(tp->state == T_STOPPING); assert(tp->state == T_STOPPING);
if (tp->cm == NULL)
if (!cm_active(tp))
torrent_kill(tp); torrent_kill(tp);
} }

+ 49
- 27
btpd/tracker_req.c View File

@@ -37,7 +37,7 @@ struct tracker {


static void tr_send(struct torrent *tp, enum tr_event event); static void tr_send(struct torrent *tp, enum tr_event event);


void
static void
maybe_connect_to(struct torrent *tp, const char *pinfo) maybe_connect_to(struct torrent *tp, const char *pinfo)
{ {
const char *pid; const char *pid;
@@ -66,21 +66,25 @@ maybe_connect_to(struct torrent *tp, const char *pinfo)




static int static int
parse_reply(struct torrent *tp, const char *content, size_t size)
parse_reply(struct torrent *tp, const char *content, size_t size, int parse)
{ {
const char *buf; const char *buf;
size_t len; size_t len;
const char *peers; const char *peers;
int interval; int interval;


if (benc_validate(content, size) != 0)
goto bad_data;

if ((buf = benc_dget_mem(content, "failure reason", &len)) != NULL) { if ((buf = benc_dget_mem(content, "failure reason", &len)) != NULL) {
btpd_log(BTPD_L_ERROR, "Tracker failure: %.*s.\n", (int)len, buf); btpd_log(BTPD_L_ERROR, "Tracker failure: %.*s.\n", (int)len, buf);
return 1; return 1;
} }


if ((benc_validate(content, size) != 0 ||
!benc_dct_chk(content, 2, BE_INT, 1, "interval",
BE_ANY, 1, "peers")))
if (!parse)
return 0;

if (!benc_dct_chk(content, 2, BE_INT, 1, "interval", BE_ANY, 1, "peers"))
goto bad_data; goto bad_data;


interval = benc_dget_int(content, "interval"); interval = benc_dget_int(content, "interval");
@@ -109,6 +113,19 @@ bad_data:
return 1; return 1;
} }


static void
tr_set_stopped(struct torrent *tp)
{
struct tracker *tr = tp->tr;
event_del(&tr->timer);
tr->ttype = TIMER_NONE;
if (tr->req != NULL) {
http_cancel(tr->req);
tr->req = NULL;
}
torrent_on_tr_stopped(tp);
}

static void static void
http_cb(struct http *req, struct http_res *res, void *arg) http_cb(struct http *req, struct http_res *res, void *arg)
{ {
@@ -116,9 +133,8 @@ http_cb(struct http *req, struct http_res *res, void *arg)
struct tracker *tr = tp->tr; struct tracker *tr = tp->tr;
assert(tr->ttype == TIMER_TIMEOUT); assert(tr->ttype == TIMER_TIMEOUT);
tr->req = NULL; tr->req = NULL;
if (res->res == HRES_OK &&
(tr->event == TR_EV_STOPPED
|| parse_reply(tp, res->content, res->length) == 0)) {
if (res->res == HRES_OK && parse_reply(tp, res->content, res->length,
tr->event != TR_EV_STOPPED) == 0) {
tr->nerrors = 0; tr->nerrors = 0;
tr->ttype = TIMER_INTERVAL; tr->ttype = TIMER_INTERVAL;
event_add(&tr->timer, (& (struct timeval) { tr->interval, 0 })); event_add(&tr->timer, (& (struct timeval) { tr->interval, 0 }));
@@ -128,7 +144,7 @@ http_cb(struct http *req, struct http_res *res, void *arg)
event_add(&tr->timer, RETRY_WAIT); event_add(&tr->timer, RETRY_WAIT);
} }
if (tr->event == TR_EV_STOPPED && (tr->nerrors == 0 || tr->nerrors >= 5)) if (tr->event == TR_EV_STOPPED && (tr->nerrors == 0 || tr->nerrors >= 5))
tr_destroy(tp);
tr_set_stopped(tp);
} }


static void static void
@@ -138,17 +154,15 @@ timer_cb(int fd, short type, void *arg)
struct tracker *tr = tp->tr; struct tracker *tr = tp->tr;
switch (tr->ttype) { switch (tr->ttype) {
case TIMER_TIMEOUT: case TIMER_TIMEOUT:
btpd_log(BTPD_L_ERROR, "Tracker request timed out for '%s'.\n",
tp->meta.name);
tr->nerrors++; tr->nerrors++;
if (tr->event == TR_EV_STOPPED && tr->nerrors >= 5) { if (tr->event == TR_EV_STOPPED && tr->nerrors >= 5) {
tr_destroy(tp);
tr_set_stopped(tp);
break; break;
} }
case TIMER_RETRY: case TIMER_RETRY:
if (tr->event == TR_EV_STOPPED) {
event_add(&tr->timer, REQ_TIMEOUT);
http_redo(&tr->req);
} else
tr_send(tp, tr->event);
tr_send(tp, tr->event);
break; break;
case TIMER_INTERVAL: case TIMER_INTERVAL:
tr_send(tp, TR_EV_EMPTY); tr_send(tp, TR_EV_EMPTY);
@@ -188,27 +202,21 @@ tr_send(struct torrent *tp, enum tr_event event)
} }


int int
tr_start(struct torrent *tp)
tr_create(struct torrent *tp)
{ {
assert(tp->tr == NULL);
if (strncmp(tp->meta.announce, "http://", sizeof("http://") - 1) != 0) { if (strncmp(tp->meta.announce, "http://", sizeof("http://") - 1) != 0) {
btpd_log(BTPD_L_ERROR, btpd_log(BTPD_L_ERROR,
"btpd currently has no support for the protocol specified in " "btpd currently has no support for the protocol specified in "
"'%s'.\n", tp->meta.announce); "'%s'.\n", tp->meta.announce);
return EINVAL; return EINVAL;
} }

struct tracker *tr = btpd_calloc(1, sizeof(*tr));
evtimer_set(&tr->timer, timer_cb, tp);
tp->tr = tr;

tr_send(tp, TR_EV_STARTED);

tp->tr = btpd_calloc(1, sizeof(*tp->tr));
evtimer_set(&tp->tr->timer, timer_cb, tp);
return 0; return 0;
} }


void void
tr_destroy(struct torrent *tp)
tr_kill(struct torrent *tp)
{ {
struct tracker *tr = tp->tr; struct tracker *tr = tp->tr;
tp->tr = NULL; tp->tr = NULL;
@@ -216,7 +224,12 @@ tr_destroy(struct torrent *tp)
if (tr->req != NULL) if (tr->req != NULL)
http_cancel(tr->req); http_cancel(tr->req);
free(tr); free(tr);
torrent_on_tr_stopped(tp);
}

void
tr_start(struct torrent *tp)
{
tr_send(tp, TR_EV_STARTED);
} }


void void
@@ -234,7 +247,16 @@ tr_complete(struct torrent *tp)
void void
tr_stop(struct torrent *tp) tr_stop(struct torrent *tp)
{ {
tr_send(tp, TR_EV_STOPPED);
if (tp->tr->event == TR_EV_STOPPED)
tr_set_stopped(tp);
else
tr_send(tp, TR_EV_STOPPED);
}

int
tr_active(struct torrent *tp)
{
return tp->tr->ttype != TIMER_NONE;
} }


unsigned unsigned


+ 4
- 2
btpd/tracker_req.h View File

@@ -1,11 +1,13 @@
#ifndef TRACKER_REQ_H #ifndef TRACKER_REQ_H
#define TRACKER_REQ_H #define TRACKER_REQ_H


int tr_start(struct torrent *tp);
int tr_create(struct torrent *tp);
void tr_kill(struct torrent *tp);
void tr_start(struct torrent *tp);
void tr_stop(struct torrent *tp); void tr_stop(struct torrent *tp);
void tr_refresh(struct torrent *tp); void tr_refresh(struct torrent *tp);
void tr_complete(struct torrent *tp); void tr_complete(struct torrent *tp);
void tr_destroy(struct torrent *tp);
unsigned tr_errors(struct torrent *tp); unsigned tr_errors(struct torrent *tp);
int tr_active(struct torrent *tp);


#endif #endif

Loading…
Cancel
Save