Przeglądaj źródła

The mega whitespace patch.

Tabs have been converted to spaces and trailing whitespace have been removed.
I have fixed my emacs settings now :P
master
Richard Nyberg 19 lat temu
rodzic
commit
c285b374f8
28 zmienionych plików z 1608 dodań i 1608 usunięć
  1. +12
    -12
      btpd/btpd.c
  2. +7
    -7
      btpd/btpd.h
  3. +58
    -58
      btpd/cli_if.c
  4. +53
    -53
      btpd/download.c
  5. +224
    -224
      btpd/download_subr.c
  6. +73
    -73
      btpd/main.c
  7. +242
    -242
      btpd/net.c
  8. +9
    -9
      btpd/net.h
  9. +24
    -24
      btpd/net_buf.c
  10. +13
    -13
      btpd/net_buf.h
  11. +164
    -164
      btpd/peer.c
  12. +12
    -12
      btpd/peer.h
  13. +60
    -60
      btpd/queue.h
  14. +50
    -50
      btpd/torrent.c
  15. +2
    -2
      btpd/torrent.h
  16. +87
    -87
      btpd/tracker_req.c
  17. +6
    -6
      btpd/upload.c
  18. +18
    -18
      btpd/util.c
  19. +125
    -125
      cli/btcli.c
  20. +10
    -10
      cli/btinfo.c
  21. +36
    -36
      cli/btpd_if.c
  22. +1
    -1
      cli/btpd_if.h
  23. +105
    -105
      misc/benc.c
  24. +1
    -1
      misc/benc.h
  25. +100
    -100
      misc/metainfo.c
  26. +80
    -80
      misc/stream.c
  27. +1
    -1
      misc/stream.h
  28. +35
    -35
      misc/subr.c

+ 12
- 12
btpd/btpd.c Wyświetl plik

@@ -83,15 +83,15 @@ child_cb(int signal, short type, void *arg)
pid_t pid; pid_t pid;


while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
struct child *kid = BTPDQ_FIRST(&m_kids); struct child *kid = BTPDQ_FIRST(&m_kids);
while (kid != NULL && kid->pid != pid) while (kid != NULL && kid->pid != pid)
kid = BTPDQ_NEXT(kid, entry); kid = BTPDQ_NEXT(kid, entry);
assert(kid != NULL); assert(kid != NULL);
BTPDQ_REMOVE(&m_kids, kid, entry); BTPDQ_REMOVE(&m_kids, kid, entry);
kid->cb(kid->pid, kid->arg); kid->cb(kid->pid, kid->arg);
free(kid); free(kid);
} }
} }
} }


@@ -102,7 +102,7 @@ btpd_add_torrent(struct torrent *tp)
m_ntorrents++; m_ntorrents++;
} }


void void
btpd_del_torrent(struct torrent *tp) btpd_del_torrent(struct torrent *tp)
{ {
BTPDQ_REMOVE(&m_torrents, tp, entry); BTPDQ_REMOVE(&m_torrents, tp, entry);
@@ -126,7 +126,7 @@ btpd_get_torrent(const uint8_t *hash)
{ {
struct torrent *tp = BTPDQ_FIRST(&m_torrents); struct torrent *tp = BTPDQ_FIRST(&m_torrents);
while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0) while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0)
tp = BTPDQ_NEXT(tp, entry); tp = BTPDQ_NEXT(tp, entry);
return tp; return tp;
} }


@@ -145,7 +145,7 @@ btpd_init(void)
m_peer_id[sizeof(BTPD_VERSION) - 1] = '|'; m_peer_id[sizeof(BTPD_VERSION) - 1] = '|';
srandom(time(NULL)); srandom(time(NULL));
for (int i = sizeof(BTPD_VERSION); i < 20; i++) for (int i = sizeof(BTPD_VERSION); i < 20; i++)
m_peer_id[i] = rint(random() * 255.0 / RAND_MAX); m_peer_id[i] = rint(random() * 255.0 / RAND_MAX);


net_init(); net_init();
ipc_init(); ipc_init();


+ 7
- 7
btpd/btpd.h Wyświetl plik

@@ -30,13 +30,13 @@


#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) #define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION)


#define BTPD_L_ALL 0xffffffff #define BTPD_L_ALL 0xffffffff
#define BTPD_L_ERROR 0x00000001 #define BTPD_L_ERROR 0x00000001
#define BTPD_L_TRACKER 0x00000002 #define BTPD_L_TRACKER 0x00000002
#define BTPD_L_CONN 0x00000004 #define BTPD_L_CONN 0x00000004
#define BTPD_L_MSG 0x00000008 #define BTPD_L_MSG 0x00000008
#define BTPD_L_BTPD 0x00000010 #define BTPD_L_BTPD 0x00000010
#define BTPD_L_POL 0x00000020 #define BTPD_L_POL 0x00000020


void btpd_init(void); void btpd_init(void);




+ 58
- 58
btpd/cli_if.c Wyświetl plik

@@ -25,7 +25,7 @@ static void
errdie(int error) errdie(int error)
{ {
if (error != 0) if (error != 0)
btpd_err("io_buf: %s.\n", strerror(error)); btpd_err("io_buf: %s.\n", strerror(error));
} }


static void static void
@@ -34,7 +34,7 @@ cmd_stat(int argc, const char *args, FILE *fp)
struct torrent *tp; struct torrent *tp;
struct io_buffer iob; struct io_buffer iob;
errdie(buf_init(&iob, (1 << 14))); errdie(buf_init(&iob, (1 << 14)));
errdie(buf_swrite(&iob, "d")); errdie(buf_swrite(&iob, "d"));
errdie(buf_print(&iob, "6:npeersi%ue", net_npeers)); errdie(buf_print(&iob, "6:npeersi%ue", net_npeers));
errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents())); errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents()));
@@ -44,16 +44,16 @@ cmd_stat(int argc, const char *args, FILE *fp)
for (uint32_t i = 0; i < tp->meta.npieces; i++) for (uint32_t i = 0; i < tp->meta.npieces; i++)
if (tp->piece_count[i] > 0) if (tp->piece_count[i] > 0)
seen_npieces++; seen_npieces++;
errdie(buf_print(&iob, "d4:downi%" PRIu64 "e", tp->downloaded)); errdie(buf_print(&iob, "d4:downi%" PRIu64 "e", tp->downloaded));
errdie(buf_swrite(&iob, "4:hash20:")); errdie(buf_swrite(&iob, "4:hash20:"));
errdie(buf_write(&iob, tp->meta.info_hash, 20)); errdie(buf_write(&iob, tp->meta.info_hash, 20));
errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces)); errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces));
errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers)); errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers));
errdie(buf_print(&iob, "7:npiecesi%ue", tp->meta.npieces)); errdie(buf_print(&iob, "7:npiecesi%ue", tp->meta.npieces));
errdie(buf_print(&iob, "4:path%d:%s", errdie(buf_print(&iob, "4:path%d:%s",
(int)strlen(tp->relpath), tp->relpath)); (int)strlen(tp->relpath), tp->relpath));
errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces)); errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces));
errdie(buf_print(&iob, "2:upi%" PRIu64 "ee", tp->uploaded)); errdie(buf_print(&iob, "2:upi%" PRIu64 "ee", tp->uploaded));
} }
errdie(buf_swrite(&iob, "ee")); errdie(buf_swrite(&iob, "ee"));


@@ -71,33 +71,33 @@ cmd_add(int argc, const char *args, FILE *fp)


errdie(buf_write(&iob, "l", 1)); errdie(buf_write(&iob, "l", 1));
while (args != NULL) { while (args != NULL) {
size_t plen; size_t plen;
char path[PATH_MAX]; char path[PATH_MAX];
const char *pathp; const char *pathp;
if (!benc_isstr(args)) {
if (!benc_isstr(args)) { free(iob.buf);
free(iob.buf); return;
return; }
} benc_str(args, &pathp, &plen, &args);
if (plen >= PATH_MAX) {
benc_str(args, &pathp, &plen, &args); errdie(buf_print(&iob, "d4:codei%dee", ENAMETOOLONG));
continue;
if (plen >= PATH_MAX) { }
errdie(buf_print(&iob, "d4:codei%dee", ENAMETOOLONG)); bcopy(pathp, path, plen);
continue; path[plen] = '\0';
} btpd_log(BTPD_L_BTPD, "add request for %s.\n", path);
errdie(buf_print(&iob, "d4:codei%dee", torrent_load(path)));
bcopy(pathp, path, plen);
path[plen] = '\0';
btpd_log(BTPD_L_BTPD, "add request for %s.\n", path);
errdie(buf_print(&iob, "d4:codei%dee", torrent_load(path)));
} }
errdie(buf_write(&iob, "e", 1)); errdie(buf_write(&iob, "e", 1));


uint32_t len = iob.buf_off; uint32_t len = iob.buf_off;
fwrite(&len, sizeof(len), 1, fp); fwrite(&len, sizeof(len), 1, fp);
fwrite(iob.buf, 1, iob.buf_off, fp); fwrite(iob.buf, 1, iob.buf_off, fp);
free(iob.buf); free(iob.buf);
} }


static void static void
@@ -105,7 +105,7 @@ cmd_del(int argc, const char *args, FILE *fp)
{ {
struct io_buffer iob; struct io_buffer iob;
errdie(buf_init(&iob, (1 << 10))); errdie(buf_init(&iob, (1 << 10)));
errdie(buf_swrite(&iob, "l")); errdie(buf_swrite(&iob, "l"));


while (args != NULL) { while (args != NULL) {
@@ -114,18 +114,18 @@ cmd_del(int argc, const char *args, FILE *fp)
struct torrent *tp; struct torrent *tp;


if (!benc_isstr(args) || if (!benc_isstr(args) ||
benc_str(args, &hash, &len, &args) != 0 || len != 20) { benc_str(args, &hash, &len, &args) != 0 || len != 20) {
free(iob.buf); free(iob.buf);
return; return;
} }


tp = btpd_get_torrent(hash); tp = btpd_get_torrent(hash);
if (tp != NULL) { if (tp != NULL) {
btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath); btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath);
torrent_unload(tp); torrent_unload(tp);
errdie(buf_swrite(&iob, "d4:codei0ee")); errdie(buf_swrite(&iob, "d4:codei0ee"));
} else { } else {
btpd_log(BTPD_L_BTPD, "del request didn't match.\n"); btpd_log(BTPD_L_BTPD, "del request didn't match.\n");
errdie(buf_print(&iob, "d4:codei%dee", ENOENT)); errdie(buf_print(&iob, "d4:codei%dee", ENOENT));
} }
} }
@@ -154,10 +154,10 @@ static struct {
int nlen; int nlen;
void (*fun)(int, const char *, FILE *); void (*fun)(int, const char *, FILE *);
} cmd_table[] = { } cmd_table[] = {
{ "add", 3, cmd_add }, { "add", 3, cmd_add },
{ "del", 3, cmd_del }, { "del", 3, cmd_del },
{ "die", 3, cmd_die }, { "die", 3, cmd_die },
{ "stat", 4, cmd_stat } { "stat", 4, cmd_stat }
}; };


static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]); static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
@@ -208,20 +208,20 @@ client_connection_cb(int sd, short type, void *arg)
FILE *fp; FILE *fp;


if ((nsd = accept(sd, NULL, NULL)) < 0) { if ((nsd = accept(sd, NULL, NULL)) < 0) {
if (errno == EWOULDBLOCK || errno == ECONNABORTED) if (errno == EWOULDBLOCK || errno == ECONNABORTED)
return; return;
else else
btpd_err("client accept: %s\n", strerror(errno)); btpd_err("client accept: %s\n", strerror(errno));
} }


if ((errno = set_blocking(nsd)) != 0) if ((errno = set_blocking(nsd)) != 0)
btpd_err("set_blocking: %s.\n", strerror(errno)); btpd_err("set_blocking: %s.\n", strerror(errno));


if ((fp = fdopen(nsd, "r+")) == NULL) { if ((fp = fdopen(nsd, "r+")) == NULL) {
close(nsd); close(nsd);
return; return;
} }
do_ipc(fp); do_ipc(fp);


fclose(fp); fclose(fp);
@@ -236,25 +236,25 @@ ipc_init(void)


addr.sun_family = PF_UNIX; addr.sun_family = PF_UNIX;
if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz) if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz)
btpd_err("'%s/sock' is too long.\n", btpd_dir); btpd_err("'%s/sock' is too long.\n", btpd_dir);
if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
btpd_err("sock: %s\n", strerror(errno)); btpd_err("sock: %s\n", strerror(errno));
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
if (errno == EADDRINUSE) { if (errno == EADDRINUSE) {
unlink(addr.sun_path); unlink(addr.sun_path);
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
btpd_err("bind: %s\n", strerror(errno)); btpd_err("bind: %s\n", strerror(errno));
} else } else
btpd_err("bind: %s\n", strerror(errno)); btpd_err("bind: %s\n", strerror(errno));
} }


if (chmod(addr.sun_path, 0600) == -1) if (chmod(addr.sun_path, 0600) == -1)
btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno)); btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno));
listen(sd, 4); listen(sd, 4);
set_nonblocking(sd); set_nonblocking(sd);


event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST, event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST,
client_connection_cb, NULL); client_connection_cb, NULL);
event_add(&m_cli_incoming, NULL); event_add(&m_cli_incoming, NULL);
} }

+ 53
- 53
btpd/download.c Wyświetl plik

@@ -18,14 +18,14 @@ dl_stop(struct torrent *tp)
peer = BTPDQ_FIRST(&tp->peers); peer = BTPDQ_FIRST(&tp->peers);
while (peer != NULL) { while (peer != NULL) {
struct peer *next = BTPDQ_NEXT(peer, p_entry); struct peer *next = BTPDQ_NEXT(peer, p_entry);
BTPDQ_REMOVE(&tp->peers, peer, p_entry); BTPDQ_REMOVE(&tp->peers, peer, p_entry);
BTPDQ_INSERT_TAIL(&net_unattached, peer, p_entry); BTPDQ_INSERT_TAIL(&net_unattached, peer, p_entry);
peer->flags &= ~PF_ATTACHED; peer->flags &= ~PF_ATTACHED;
peer = next; peer = next;
} }


while ((piece = BTPDQ_FIRST(&tp->getlst)) != NULL) while ((piece = BTPDQ_FIRST(&tp->getlst)) != NULL)
piece_free(piece); piece_free(piece);
} }


/* /*
@@ -40,24 +40,24 @@ dl_on_piece_ann(struct peer *p, uint32_t index)
struct torrent *tp = p->tp; struct torrent *tp = p->tp;
tp->piece_count[index]++; tp->piece_count[index]++;
if (has_bit(tp->piece_field, index)) if (has_bit(tp->piece_field, index))
return; return;
struct piece *pc = dl_find_piece(tp, index); struct piece *pc = dl_find_piece(tp, index);
if (tp->endgame) { if (tp->endgame) {
assert(pc != NULL); assert(pc != NULL);
peer_want(p, index); peer_want(p, index);
if (!peer_chokes(p) && !peer_laden(p)) if (!peer_chokes(p) && !peer_laden(p))
dl_assign_requests_eg(p); dl_assign_requests_eg(p);
} else if (pc == NULL) { } else if (pc == NULL) {
peer_want(p, index); peer_want(p, index);
if (!peer_chokes(p) && !peer_laden(p)) { if (!peer_chokes(p) && !peer_laden(p)) {
pc = dl_new_piece(tp, index); pc = dl_new_piece(tp, index);
if (pc != NULL) if (pc != NULL)
dl_piece_assign_requests(pc, p); dl_piece_assign_requests(pc, p);
} }
} else if (!piece_full(pc)) { } else if (!piece_full(pc)) {
peer_want(p, index); peer_want(p, index);
if (!peer_chokes(p) && !peer_laden(p)) if (!peer_chokes(p) && !peer_laden(p))
dl_piece_assign_requests(pc, p); dl_piece_assign_requests(pc, p);
} }
} }


@@ -67,11 +67,11 @@ dl_on_download(struct peer *p)
assert(peer_wanted(p)); assert(peer_wanted(p));
struct torrent *tp = p->tp; struct torrent *tp = p->tp;
if (tp->endgame) { if (tp->endgame) {
dl_assign_requests_eg(p); dl_assign_requests_eg(p);
} else { } else {
unsigned count = dl_assign_requests(p); unsigned count = dl_assign_requests(p);
if (count == 0 && !p->tp->endgame) // We may have entered end game. if (count == 0 && !p->tp->endgame) // We may have entered end game.
assert(!peer_wanted(p) || peer_laden(p)); assert(!peer_wanted(p) || peer_laden(p));
} }
} }


@@ -79,23 +79,23 @@ void
dl_on_unchoke(struct peer *p) dl_on_unchoke(struct peer *p)
{ {
if (peer_wanted(p)) if (peer_wanted(p))
dl_on_download(p); dl_on_download(p);
} }


void void
dl_on_undownload(struct peer *p) dl_on_undownload(struct peer *p)
{ {
if (!p->tp->endgame) if (!p->tp->endgame)
dl_unassign_requests(p); dl_unassign_requests(p);
else else
dl_unassign_requests_eg(p); dl_unassign_requests_eg(p);
} }


void void
dl_on_choke(struct peer *p) dl_on_choke(struct peer *p)
{ {
if (p->nreqs_out > 0) if (p->nreqs_out > 0)
dl_on_undownload(p); dl_on_undownload(p);
} }


/** /**
@@ -115,21 +115,21 @@ dl_on_ok_piece(struct piece *pc)


struct net_buf *have = nb_create_have(pc->index); struct net_buf *have = nb_create_have(pc->index);
BTPDQ_FOREACH(p, &tp->peers, p_entry) BTPDQ_FOREACH(p, &tp->peers, p_entry)
peer_send(p, have); peer_send(p, have);


if (tp->endgame) if (tp->endgame)
BTPDQ_FOREACH(p, &tp->peers, p_entry) BTPDQ_FOREACH(p, &tp->peers, p_entry)
if (peer_has(p, pc->index)) if (peer_has(p, pc->index))
peer_unwant(p, pc->index); peer_unwant(p, pc->index);


assert(pc->nreqs == 0); assert(pc->nreqs == 0);
piece_free(pc); piece_free(pc);


if (torrent_has_all(tp)) { if (torrent_has_all(tp)) {
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath); btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath);
tracker_req(tp, TR_COMPLETED); tracker_req(tp, TR_COMPLETED);
BTPDQ_FOREACH(p, &tp->peers, p_entry) BTPDQ_FOREACH(p, &tp->peers, p_entry)
assert(p->nwant == 0); assert(p->nwant == 0);
} }
} }


@@ -145,21 +145,21 @@ dl_on_bad_piece(struct piece *pc)
pc->index, tp->relpath); pc->index, tp->relpath);


for (uint32_t i = 0; i < pc->nblocks; i++) { for (uint32_t i = 0; i < pc->nblocks; i++) {
clear_bit(pc->down_field, i); clear_bit(pc->down_field, i);
clear_bit(pc->have_field, i); clear_bit(pc->have_field, i);
} }
pc->ngot = 0; pc->ngot = 0;
pc->nbusy = 0; pc->nbusy = 0;
msync(tp->imem, tp->isiz, MS_ASYNC); msync(tp->imem, tp->isiz, MS_ASYNC);


if (tp->endgame) { if (tp->endgame) {
struct peer *p; struct peer *p;
BTPDQ_FOREACH(p, &tp->peers, p_entry) { BTPDQ_FOREACH(p, &tp->peers, p_entry) {
if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p)) if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p))
dl_assign_requests_eg(p); dl_assign_requests_eg(p);
} }
} else } else
dl_on_piece_unfull(pc); // XXX: May get bad data again. dl_on_piece_unfull(pc); // XXX: May get bad data again.
} }


void void
@@ -186,14 +186,14 @@ dl_on_lost_peer(struct peer *p)
tp->piece_count[i]--; tp->piece_count[i]--;


if (p->nreqs_out > 0) if (p->nreqs_out > 0)
dl_on_undownload(p); dl_on_undownload(p);
#if 0 #if 0
struct piece *pc = BTPDQ_FIRST(&tp->getlst); struct piece *pc = BTPDQ_FIRST(&tp->getlst);
while (pc != NULL) { while (pc != NULL) {
struct piece *next = BTPDQ_NEXT(pc, entry); struct piece *next = BTPDQ_NEXT(pc, entry);
if (peer_has(p, pc->index) && tp->piece_count[pc->index] == 0) if (peer_has(p, pc->index) && tp->piece_count[pc->index] == 0)
dl_on_peerless_piece(pc); dl_on_peerless_piece(pc);
pc = next; pc = next;
} }
#endif #endif
} }
@@ -238,12 +238,12 @@ dl_on_block(struct peer *p, struct block_request *req,
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); BTPDQ_REMOVE(&blk->reqs, req, blk_entry);
free(req); free(req);
pc->nreqs--; pc->nreqs--;
// XXX: Needs to be looked at if we introduce snubbing. // XXX: Needs to be looked at if we introduce snubbing.
clear_bit(pc->down_field, begin / PIECE_BLOCKLEN); clear_bit(pc->down_field, begin / PIECE_BLOCKLEN);
pc->nbusy--; pc->nbusy--;
if (pc->ngot == pc->nblocks) if (pc->ngot == pc->nblocks)
dl_on_piece(pc); dl_on_piece(pc);
if (peer_leech_ok(p) && !peer_laden(p)) if (peer_leech_ok(p) && !peer_laden(p))
dl_assign_requests(p); dl_assign_requests(p);
} }
} }

+ 224
- 224
btpd/download_subr.c Wyświetl plik

@@ -33,7 +33,7 @@ static struct piece *
piece_alloc(struct torrent *tp, uint32_t index) piece_alloc(struct torrent *tp, uint32_t index)
{ {
assert(!has_bit(tp->busy_field, index) assert(!has_bit(tp->busy_field, index)
&& tp->npcs_busy < tp->meta.npieces); && tp->npcs_busy < tp->meta.npieces);
struct piece *pc; struct piece *pc;
size_t mem, field, blocks; size_t mem, field, blocks;
unsigned nblocks; unsigned nblocks;
@@ -48,8 +48,8 @@ piece_alloc(struct torrent *tp, uint32_t index)
pc->tp = tp; pc->tp = tp;
pc->down_field = (uint8_t *)(pc + 1); pc->down_field = (uint8_t *)(pc + 1);
pc->have_field = pc->have_field =
tp->block_field + tp->block_field +
index * (size_t)ceil(tp->meta.piece_length / (double)(1 << 17)); index * (size_t)ceil(tp->meta.piece_length / (double)(1 << 17));


pc->index = index; pc->index = index;
pc->nblocks = nblocks; pc->nblocks = nblocks;
@@ -58,19 +58,19 @@ piece_alloc(struct torrent *tp, uint32_t index)
pc->next_block = 0; pc->next_block = 0;


for (unsigned i = 0; i < nblocks; i++) for (unsigned i = 0; i < nblocks; i++)
if (has_bit(pc->have_field, i)) if (has_bit(pc->have_field, i))
pc->ngot++; pc->ngot++;


pc->blocks = (struct block *)(pc->down_field + field); pc->blocks = (struct block *)(pc->down_field + field);
for (unsigned i = 0; i < nblocks; i++) { for (unsigned i = 0; i < nblocks; i++) {
uint32_t start = i * PIECE_BLOCKLEN; uint32_t start = i * PIECE_BLOCKLEN;
uint32_t len = torrent_block_size(pc, i); uint32_t len = torrent_block_size(pc, i);
struct block *blk = &pc->blocks[i]; struct block *blk = &pc->blocks[i];
blk->pc = pc; blk->pc = pc;
BTPDQ_INIT(&blk->reqs); BTPDQ_INIT(&blk->reqs);
blk->msg = nb_create_request(index, start, len); blk->msg = nb_create_request(index, start, len);
nb_hold(blk->msg); nb_hold(blk->msg);
} }


tp->npcs_busy++; tp->npcs_busy++;
set_bit(tp->busy_field, index); set_bit(tp->busy_field, index);
@@ -87,13 +87,13 @@ piece_free(struct piece *pc)
clear_bit(tp->busy_field, pc->index); clear_bit(tp->busy_field, pc->index);
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); BTPDQ_REMOVE(&pc->tp->getlst, pc, entry);
for (unsigned i = 0; i < pc->nblocks; i++) { for (unsigned i = 0; i < pc->nblocks; i++) {
struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs);
while (req != NULL) { while (req != NULL) {
struct block_request *next = BTPDQ_NEXT(req, blk_entry); struct block_request *next = BTPDQ_NEXT(req, blk_entry);
free(req); free(req);
req = next; req = next;
} }
nb_drop(pc->blocks[i].msg); nb_drop(pc->blocks[i].msg);
} }
free(pc); free(pc);
} }
@@ -109,16 +109,16 @@ dl_should_enter_endgame(struct torrent *tp)
{ {
int should; int should;
if (tp->have_npieces + tp->npcs_busy == tp->meta.npieces) { if (tp->have_npieces + tp->npcs_busy == tp->meta.npieces) {
should = 1; should = 1;
struct piece *pc; struct piece *pc;
BTPDQ_FOREACH(pc, &tp->getlst, entry) { BTPDQ_FOREACH(pc, &tp->getlst, entry) {
if (!piece_full(pc)) { if (!piece_full(pc)) {
should = 0; should = 0;
break; break;
} }
} }
} else } else
should = 0; should = 0;
return should; return should;
} }


@@ -127,19 +127,19 @@ dl_piece_insert_eg(struct piece *pc)
{ {
struct piece_tq *getlst = &pc->tp->getlst; struct piece_tq *getlst = &pc->tp->getlst;
if (pc->nblocks == pc->ngot) if (pc->nblocks == pc->ngot)
BTPDQ_INSERT_TAIL(getlst, pc, entry); BTPDQ_INSERT_TAIL(getlst, pc, entry);
else { else {
unsigned r = pc->nreqs / (pc->nblocks - pc->ngot); unsigned r = pc->nreqs / (pc->nblocks - pc->ngot);
struct piece *it; struct piece *it;
BTPDQ_FOREACH(it, getlst, entry) { BTPDQ_FOREACH(it, getlst, entry) {
if ((it->nblocks == it->ngot if ((it->nblocks == it->ngot
|| r < it->nreqs / (it->nblocks - it->ngot))) { || r < it->nreqs / (it->nblocks - it->ngot))) {
BTPDQ_INSERT_BEFORE(it, pc, entry); BTPDQ_INSERT_BEFORE(it, pc, entry);
break; break;
} }
} }
if (it == NULL) if (it == NULL)
BTPDQ_INSERT_TAIL(getlst, pc, entry); BTPDQ_INSERT_TAIL(getlst, pc, entry);
} }
} }


@@ -163,25 +163,25 @@ dl_enter_endgame(struct torrent *tp)


pi = 0; pi = 0;
BTPDQ_FOREACH(pc, &tp->getlst, entry) { BTPDQ_FOREACH(pc, &tp->getlst, entry) {
for (unsigned i = 0; i < pc->nblocks; i++) for (unsigned i = 0; i < pc->nblocks; i++)
clear_bit(pc->down_field, i); clear_bit(pc->down_field, i);
pc->nbusy = 0; pc->nbusy = 0;
pcs[pi] = pc; pcs[pi] = pc;
pi++; pi++;
} }
BTPDQ_INIT(&tp->getlst); BTPDQ_INIT(&tp->getlst);
while (pi > 0) { while (pi > 0) {
pi--; pi--;
dl_piece_insert_eg(pcs[pi]); dl_piece_insert_eg(pcs[pi]);
} }
BTPDQ_FOREACH(p, &tp->peers, p_entry) { BTPDQ_FOREACH(p, &tp->peers, p_entry) {
assert(p->nwant == 0); assert(p->nwant == 0);
BTPDQ_FOREACH(pc, &tp->getlst, entry) { BTPDQ_FOREACH(pc, &tp->getlst, entry) {
if (peer_has(p, pc->index)) if (peer_has(p, pc->index))
peer_want(p, pc->index); peer_want(p, pc->index);
} }
if (p->nwant > 0 && peer_leech_ok(p) && !peer_laden(p)) if (p->nwant > 0 && peer_leech_ok(p) && !peer_laden(p))
dl_assign_requests_eg(p); dl_assign_requests_eg(p);
} }
} }


@@ -190,8 +190,8 @@ dl_find_piece(struct torrent *tp, uint32_t index)
{ {
struct piece *pc; struct piece *pc;
BTPDQ_FOREACH(pc, &tp->getlst, entry) BTPDQ_FOREACH(pc, &tp->getlst, entry)
if (pc->index == index) if (pc->index == index)
break; break;
return pc; return pc;
} }


@@ -199,31 +199,31 @@ static int
test_hash(struct torrent *tp, uint8_t *hash, unsigned long index) test_hash(struct torrent *tp, uint8_t *hash, unsigned long index)
{ {
if (tp->meta.piece_hash != NULL) if (tp->meta.piece_hash != NULL)
return memcmp(hash, tp->meta.piece_hash[index], SHA_DIGEST_LENGTH); return memcmp(hash, tp->meta.piece_hash[index], SHA_DIGEST_LENGTH);
else { else {
char piece_hash[SHA_DIGEST_LENGTH]; char piece_hash[SHA_DIGEST_LENGTH];
int fd; int fd;
int bufi; int bufi;
int err; int err;
err = vopen(&fd, O_RDONLY, "%s/torrent", tp->relpath);
err = vopen(&fd, O_RDONLY, "%s/torrent", tp->relpath); if (err != 0)
if (err != 0) btpd_err("test_hash: %s\n", strerror(err));
btpd_err("test_hash: %s\n", strerror(err)); err = lseek(fd, tp->meta.pieces_off + index * SHA_DIGEST_LENGTH,
SEEK_SET);
err = lseek(fd, tp->meta.pieces_off + index * SHA_DIGEST_LENGTH, if (err < 0)
SEEK_SET); btpd_err("test_hash: %s\n", strerror(errno));
if (err < 0) bufi = 0;
btpd_err("test_hash: %s\n", strerror(errno)); while (bufi < SHA_DIGEST_LENGTH) {
ssize_t nread =
bufi = 0; read(fd, piece_hash + bufi, SHA_DIGEST_LENGTH - bufi);
while (bufi < SHA_DIGEST_LENGTH) { bufi += nread;
ssize_t nread = }
read(fd, piece_hash + bufi, SHA_DIGEST_LENGTH - bufi); close(fd);
bufi += nread; return memcmp(hash, piece_hash, SHA_DIGEST_LENGTH);
}
close(fd);
return memcmp(hash, piece_hash, SHA_DIGEST_LENGTH);
} }
} }


@@ -244,18 +244,18 @@ torrent_test_piece(struct piece *pc)
off_t plen = torrent_piece_size(tp, pc->index); off_t plen = torrent_piece_size(tp, pc->index);


if ((bts = bts_open_ro(&tp->meta, pc->index * tp->meta.piece_length, if ((bts = bts_open_ro(&tp->meta, pc->index * tp->meta.piece_length,
ro_fd_cb, tp)) == NULL) ro_fd_cb, tp)) == NULL)
btpd_err("Out of memory.\n"); btpd_err("Out of memory.\n");


if ((err = bts_sha(bts, plen, hash)) != 0) if ((err = bts_sha(bts, plen, hash)) != 0)
btpd_err("Ouch! %s\n", strerror(err)); btpd_err("Ouch! %s\n", strerror(err));


bts_close_ro(bts); bts_close_ro(bts);


if (test_hash(tp, hash, pc->index) == 0) if (test_hash(tp, hash, pc->index) == 0)
dl_on_ok_piece(pc); dl_on_ok_piece(pc);
else else
dl_on_bad_piece(pc); dl_on_bad_piece(pc);
} }


void void
@@ -268,7 +268,7 @@ static int
dl_piece_startable(struct peer *p, uint32_t index) dl_piece_startable(struct peer *p, uint32_t index)
{ {
return peer_has(p, index) && !has_bit(p->tp->piece_field, index) return peer_has(p, index) && !has_bit(p->tp->piece_field, index)
&& !has_bit(p->tp->busy_field, index); && !has_bit(p->tp->busy_field, index);
} }


/* /*
@@ -287,39 +287,39 @@ dl_choose_rarest(struct peer *p, uint32_t *res)
assert(tp->endgame == 0); assert(tp->endgame == 0);


for (i = 0; i < tp->meta.npieces && !dl_piece_startable(p, i); i++) for (i = 0; i < tp->meta.npieces && !dl_piece_startable(p, i); i++)
; ;


if (i == tp->meta.npieces) if (i == tp->meta.npieces)
return ENOENT; return ENOENT;
uint32_t min_i = i; uint32_t min_i = i;
uint32_t min_c = 1; uint32_t min_c = 1;
for(i++; i < tp->meta.npieces; i++) { for(i++; i < tp->meta.npieces; i++) {
if (dl_piece_startable(p, i)) { if (dl_piece_startable(p, i)) {
if (tp->piece_count[i] == tp->piece_count[min_i]) if (tp->piece_count[i] == tp->piece_count[min_i])
min_c++; min_c++;
else if (tp->piece_count[i] < tp->piece_count[min_i]) { else if (tp->piece_count[i] < tp->piece_count[min_i]) {
min_i = i; min_i = i;
min_c = 1; min_c = 1;
} }
} }
} }
if (min_c > 1) { if (min_c > 1) {
min_c = 1 + rint((double)random() * (min_c - 1) / RAND_MAX); min_c = 1 + rint((double)random() * (min_c - 1) / RAND_MAX);
for (i = min_i; min_c > 0; i++) { for (i = min_i; min_c > 0; i++) {
if (dl_piece_startable(p, i) if (dl_piece_startable(p, i)
&& tp->piece_count[i] == tp->piece_count[min_i]) { && tp->piece_count[i] == tp->piece_count[min_i]) {
min_c--; min_c--;
min_i = i; min_i = i;
} }
} }
} }
*res = min_i; *res = min_i;
return 0; return 0;
} }


/* /*
* Called from either dl_piece_assign_requests or dl_new_piece, * Called from either dl_piece_assign_requests or dl_new_piece,
* when a pice becomes full. The wanted level of the peers * when a pice becomes full. The wanted level of the peers
* that has this piece will be decreased. This function is * that has this piece will be decreased. This function is
* the only one that may trigger end game. * the only one that may trigger end game.
@@ -329,11 +329,11 @@ dl_on_piece_full(struct piece *pc)
{ {
struct peer *p; struct peer *p;
BTPDQ_FOREACH(p, &pc->tp->peers, p_entry) { BTPDQ_FOREACH(p, &pc->tp->peers, p_entry) {
if (peer_has(p, pc->index)) if (peer_has(p, pc->index))
peer_unwant(p, pc->index); peer_unwant(p, pc->index);
} }
if (dl_should_enter_endgame(pc->tp)) if (dl_should_enter_endgame(pc->tp))
dl_enter_endgame(pc->tp); dl_enter_endgame(pc->tp);
} }


/* /*
@@ -351,13 +351,13 @@ dl_new_piece(struct torrent *tp, uint32_t index)
btpd_log(BTPD_L_POL, "Started on piece %u.\n", index); btpd_log(BTPD_L_POL, "Started on piece %u.\n", index);
struct piece *pc = piece_alloc(tp, index); struct piece *pc = piece_alloc(tp, index);
if (pc->ngot == pc->nblocks) { if (pc->ngot == pc->nblocks) {
dl_on_piece_full(pc); dl_on_piece_full(pc);
dl_on_piece(pc); dl_on_piece(pc);
if (dl_should_enter_endgame(tp)) if (dl_should_enter_endgame(tp))
dl_enter_endgame(tp); dl_enter_endgame(tp);
return NULL; return NULL;
} else } else
return pc; return pc;
} }


/* /*
@@ -374,13 +374,13 @@ dl_on_piece_unfull(struct piece *pc)
struct peer *p; struct peer *p;
assert(!piece_full(pc) && tp->endgame == 0); assert(!piece_full(pc) && tp->endgame == 0);
BTPDQ_FOREACH(p, &tp->peers, p_entry) BTPDQ_FOREACH(p, &tp->peers, p_entry)
if (peer_has(p, pc->index)) if (peer_has(p, pc->index))
peer_want(p, pc->index); peer_want(p, pc->index);
p = BTPDQ_FIRST(&tp->peers); p = BTPDQ_FIRST(&tp->peers);
while (p != NULL && !piece_full(pc)) { while (p != NULL && !piece_full(pc)) {
if (peer_leech_ok(p) && !peer_laden(p)) if (peer_leech_ok(p) && !peer_laden(p))
dl_piece_assign_requests(pc, p); // Cannot provoke end game here. dl_piece_assign_requests(pc, p); // Cannot provoke end game here.
p = BTPDQ_NEXT(p, p_entry); p = BTPDQ_NEXT(p, p_entry);
} }
} }


@@ -400,27 +400,27 @@ dl_piece_assign_requests(struct piece *pc, struct peer *p)
assert(!piece_full(pc) && !peer_laden(p)); assert(!piece_full(pc) && !peer_laden(p));
unsigned count = 0; unsigned count = 0;
do { do {
while ((has_bit(pc->have_field, pc->next_block) while ((has_bit(pc->have_field, pc->next_block)
|| has_bit(pc->down_field, pc->next_block))) || has_bit(pc->down_field, pc->next_block)))
INCNEXTBLOCK(pc); INCNEXTBLOCK(pc);
struct block *blk = &pc->blocks[pc->next_block];
struct block *blk = &pc->blocks[pc->next_block]; struct block_request *req = btpd_malloc(sizeof(*req));
struct block_request *req = btpd_malloc(sizeof(*req)); req->p = p;
req->p = p; req->blk = blk;
req->blk = blk; BTPDQ_INSERT_TAIL(&blk->reqs, req, blk_entry);
BTPDQ_INSERT_TAIL(&blk->reqs, req, blk_entry); peer_request(p, req);
set_bit(pc->down_field, pc->next_block);
peer_request(p, req); pc->nbusy++;
pc->nreqs++;
set_bit(pc->down_field, pc->next_block); count++;
pc->nbusy++; INCNEXTBLOCK(pc);
pc->nreqs++;
count++;
INCNEXTBLOCK(pc);
} while (!piece_full(pc) && !peer_laden(p)); } while (!piece_full(pc) && !peer_laden(p));


if (piece_full(pc)) if (piece_full(pc))
dl_on_piece_full(pc); dl_on_piece_full(pc);


return count; return count;
} }
@@ -444,24 +444,24 @@ dl_assign_requests(struct peer *p)
struct torrent *tp = p->tp; struct torrent *tp = p->tp;
unsigned count = 0; unsigned count = 0;
BTPDQ_FOREACH(pc, &tp->getlst, entry) { BTPDQ_FOREACH(pc, &tp->getlst, entry) {
if (piece_full(pc) || !peer_has(p, pc->index)) if (piece_full(pc) || !peer_has(p, pc->index))
continue; continue;
count += dl_piece_assign_requests(pc, p); count += dl_piece_assign_requests(pc, p);
if (tp->endgame) if (tp->endgame)
break; break;
if (!piece_full(pc)) if (!piece_full(pc))
assert(peer_laden(p)); assert(peer_laden(p));
if (peer_laden(p)) if (peer_laden(p))
break; break;
} }
while (!peer_laden(p) && !tp->endgame) { while (!peer_laden(p) && !tp->endgame) {
uint32_t index; uint32_t index;
if (dl_choose_rarest(p, &index) == 0) { if (dl_choose_rarest(p, &index) == 0) {
pc = dl_new_piece(tp, index); pc = dl_new_piece(tp, index);
if (pc != NULL) if (pc != NULL)
count += dl_piece_assign_requests(pc, p); count += dl_piece_assign_requests(pc, p);
} else } else
break; break;
} }
return count; return count;
} }
@@ -470,32 +470,32 @@ void
dl_unassign_requests(struct peer *p) dl_unassign_requests(struct peer *p)
{ {
while (p->nreqs_out > 0) { while (p->nreqs_out > 0) {
struct block_request *req = BTPDQ_FIRST(&p->my_reqs); struct block_request *req = BTPDQ_FIRST(&p->my_reqs);
struct piece *pc = req->blk->pc; struct piece *pc = req->blk->pc;
int was_full = piece_full(pc); int was_full = piece_full(pc);
while (req != NULL) {
while (req != NULL) { struct block_request *next = BTPDQ_NEXT(req, p_entry);
struct block_request *next = BTPDQ_NEXT(req, p_entry); uint32_t blki = nb_get_begin(req->blk->msg) / PIECE_BLOCKLEN;
struct block *blk = req->blk;
uint32_t blki = nb_get_begin(req->blk->msg) / PIECE_BLOCKLEN; // XXX: Needs to be looked at if we introduce snubbing.
struct block *blk = req->blk; assert(has_bit(pc->down_field, blki));
// XXX: Needs to be looked at if we introduce snubbing. clear_bit(pc->down_field, blki);
assert(has_bit(pc->down_field, blki)); pc->nbusy--;
clear_bit(pc->down_field, blki); BTPDQ_REMOVE(&p->my_reqs, req, p_entry);
pc->nbusy--; p->nreqs_out--;
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); BTPDQ_REMOVE(&blk->reqs, req, blk_entry);
p->nreqs_out--; free(req);
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); pc->nreqs--;
free(req); while (next != NULL && next->blk->pc != pc)
pc->nreqs--; next = BTPDQ_NEXT(next, p_entry);
req = next;
while (next != NULL && next->blk->pc != pc) }
next = BTPDQ_NEXT(next, p_entry); if (was_full && !piece_full(pc))
req = next; dl_on_piece_unfull(pc);
}
if (was_full && !piece_full(pc))
dl_on_piece_unfull(pc);
} }
assert(BTPDQ_EMPTY(&p->my_reqs)); assert(BTPDQ_EMPTY(&p->my_reqs));
} }
@@ -505,18 +505,18 @@ dl_piece_assign_requests_eg(struct piece *pc, struct peer *p)
{ {
unsigned first_block = pc->next_block; unsigned first_block = pc->next_block;
do { do {
if ((has_bit(pc->have_field, pc->next_block) if ((has_bit(pc->have_field, pc->next_block)
|| peer_requested(p, &pc->blocks[pc->next_block]))) { || peer_requested(p, &pc->blocks[pc->next_block]))) {
INCNEXTBLOCK(pc); INCNEXTBLOCK(pc);
continue; continue;
} }
struct block_request *req = btpd_calloc(1, sizeof(*req)); struct block_request *req = btpd_calloc(1, sizeof(*req));
req->blk = &pc->blocks[pc->next_block]; req->blk = &pc->blocks[pc->next_block];
req->p = p; req->p = p;
BTPDQ_INSERT_TAIL(&pc->blocks[pc->next_block].reqs, req, blk_entry); BTPDQ_INSERT_TAIL(&pc->blocks[pc->next_block].reqs, req, blk_entry);
pc->nreqs++; pc->nreqs++;
INCNEXTBLOCK(pc); INCNEXTBLOCK(pc);
peer_request(p, req); peer_request(p, req);
} while (!peer_laden(p) && pc->next_block != first_block); } while (!peer_laden(p) && pc->next_block != first_block);
} }


@@ -530,20 +530,20 @@ dl_assign_requests_eg(struct peer *p)


struct piece *pc = BTPDQ_FIRST(&tp->getlst); struct piece *pc = BTPDQ_FIRST(&tp->getlst);
while (!peer_laden(p) && pc != NULL) { while (!peer_laden(p) && pc != NULL) {
struct piece *next = BTPDQ_NEXT(pc, entry); struct piece *next = BTPDQ_NEXT(pc, entry);
if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) {
dl_piece_assign_requests_eg(pc, p); dl_piece_assign_requests_eg(pc, p);
BTPDQ_REMOVE(&tp->getlst, pc, entry); BTPDQ_REMOVE(&tp->getlst, pc, entry);
BTPDQ_INSERT_HEAD(&tmp, pc, entry); BTPDQ_INSERT_HEAD(&tmp, pc, entry);
} }
pc = next; pc = next;
} }


pc = BTPDQ_FIRST(&tmp); pc = BTPDQ_FIRST(&tmp);
while (pc != NULL) { while (pc != NULL) {
struct piece *next = BTPDQ_NEXT(pc, entry); struct piece *next = BTPDQ_NEXT(pc, entry);
dl_piece_insert_eg(pc); dl_piece_insert_eg(pc);
pc = next; pc = next;
} }
} }


@@ -556,31 +556,31 @@ dl_unassign_requests_eg(struct peer *p)
BTPDQ_INIT(&tmp); BTPDQ_INIT(&tmp);


while (p->nreqs_out > 0) { while (p->nreqs_out > 0) {
req = BTPDQ_FIRST(&p->my_reqs); req = BTPDQ_FIRST(&p->my_reqs);
pc = req->blk->pc;
pc = req->blk->pc; BTPDQ_REMOVE(&pc->tp->getlst, pc, entry);
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); BTPDQ_INSERT_HEAD(&tmp, pc, entry);
BTPDQ_INSERT_HEAD(&tmp, pc, entry); while (req != NULL) {
struct block_request *next = BTPDQ_NEXT(req, p_entry);
while (req != NULL) { BTPDQ_REMOVE(&p->my_reqs, req, p_entry);
struct block_request *next = BTPDQ_NEXT(req, p_entry); p->nreqs_out--;
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); BTPDQ_REMOVE(&req->blk->reqs, req, blk_entry);
p->nreqs_out--; free(req);
BTPDQ_REMOVE(&req->blk->reqs, req, blk_entry); pc->nreqs--;
free(req); while (next != NULL && next->blk->pc != pc)
pc->nreqs--; next = BTPDQ_NEXT(next, p_entry);
req = next;
while (next != NULL && next->blk->pc != pc) }
next = BTPDQ_NEXT(next, p_entry);
req = next;
}
} }
assert(BTPDQ_EMPTY(&p->my_reqs)); assert(BTPDQ_EMPTY(&p->my_reqs));


pc = BTPDQ_FIRST(&tmp); pc = BTPDQ_FIRST(&tmp);
while (pc != NULL) { while (pc != NULL) {
struct piece *next = BTPDQ_NEXT(pc, entry); struct piece *next = BTPDQ_NEXT(pc, entry);
dl_piece_insert_eg(pc); dl_piece_insert_eg(pc);
pc = next; pc = next;
} }
} }

+ 73
- 73
btpd/main.c Wyświetl plik

@@ -28,15 +28,15 @@ find_homedir(void)
{ {
char *res = getenv("BTPD_HOME"); char *res = getenv("BTPD_HOME");
if (res == NULL) { if (res == NULL) {
char *home = getenv("HOME"); char *home = getenv("HOME");
if (home == NULL) { if (home == NULL) {
struct passwd *pwent = getpwuid(getuid()); struct passwd *pwent = getpwuid(getuid());
if (pwent == NULL) if (pwent == NULL)
errx(1, "Can't find my home directory.\n"); errx(1, "Can't find my home directory.\n");
home = pwent->pw_dir; home = pwent->pw_dir;
endpwent(); endpwent();
} }
asprintf(&res, "%s/.btpd", home); asprintf(&res, "%s/.btpd", home);
} }
return res; return res;
} }
@@ -47,7 +47,7 @@ setup_daemon(const char *dir)
int pidfd; int pidfd;


if (dir == NULL) if (dir == NULL)
dir = find_homedir(); dir = find_homedir();


btpd_dir = dir; btpd_dir = dir;


@@ -79,49 +79,49 @@ static void
usage(void) usage(void)
{ {
printf("Usage: btpd [options]\n" printf("Usage: btpd [options]\n"
"\n" "\n"
"Options:\n" "Options:\n"
"\n" "\n"
"--bw-hz n\n" "--bw-hz n\n"
"\tRun the bandwidth limiter at n hz.\n" "\tRun the bandwidth limiter at n hz.\n"
"\tDefault is 8 hz.\n" "\tDefault is 8 hz.\n"
"\n" "\n"
"--bw-in n\n" "--bw-in n\n"
"\tLimit incoming BitTorrent traffic to n kB/s.\n" "\tLimit incoming BitTorrent traffic to n kB/s.\n"
"\tDefault is 0 which means unlimited.\n" "\tDefault is 0 which means unlimited.\n"
"\n" "\n"
"--bw-out n\n" "--bw-out n\n"
"\tLimit outgoing BitTorrent traffic to n kB/s.\n" "\tLimit outgoing BitTorrent traffic to n kB/s.\n"
"\tDefault is 0 which means unlimited.\n" "\tDefault is 0 which means unlimited.\n"
"\n" "\n"
"-d\n" "-d\n"
"\tKeep the btpd process in the foregorund and log to std{out,err}.\n" "\tKeep the btpd process in the foregorund and log to std{out,err}.\n"
"\tThis option is intended for debugging purposes.\n" "\tThis option is intended for debugging purposes.\n"
"\n" "\n"
"--ipc key\n" "--ipc key\n"
"\tThe same key must be used by the cli to talk to this\n" "\tThe same key must be used by the cli to talk to this\n"
"\tbtpd instance. You shouldn't need to use this option.\n" "\tbtpd instance. You shouldn't need to use this option.\n"
"\n" "\n"
"--logfile file\n" "--logfile file\n"
"\tLog to the given file. By default btpd logs to ./btpd.log.\n" "\tLog to the given file. By default btpd logs to ./btpd.log.\n"
"\n" "\n"
"-p n, --port n\n" "-p n, --port n\n"
"\tListen at port n. Default is 6881.\n" "\tListen at port n. Default is 6881.\n"
"\n" "\n"
"--help\n" "--help\n"
"\tShow this help.\n" "\tShow this help.\n"
"\n"); "\n");
exit(1); exit(1);
} }


static int longval = 0; static int longval = 0;


static struct option longopts[] = { static struct option longopts[] = {
{ "port", required_argument, NULL, 'p' }, { "port", required_argument, NULL, 'p' },
{ "bw-in", required_argument, &longval, 1 }, { "bw-in", required_argument, &longval, 1 },
{ "bw-out", required_argument, &longval, 2 }, { "bw-out", required_argument, &longval, 2 },
{ "help", no_argument, &longval, 5 }, { "help", no_argument, &longval, 5 },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };


int int
@@ -132,38 +132,38 @@ main(int argc, char **argv)
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");


for (;;) { for (;;) {
switch (getopt_long(argc, argv, "dp:", longopts, NULL)) { switch (getopt_long(argc, argv, "dp:", longopts, NULL)) {
case -1: case -1:
goto args_done; goto args_done;
case 'd': case 'd':
btpd_daemon = 0; btpd_daemon = 0;
break; break;
case 'p': case 'p':
net_port = atoi(optarg); net_port = atoi(optarg);
break; break;
case 0: case 0:
switch (longval) { switch (longval) {
case 1: case 1:
net_bw_limit_in = atoi(optarg) * 1024; net_bw_limit_in = atoi(optarg) * 1024;
break; break;
case 2: case 2:
net_bw_limit_out = atoi(optarg) * 1024; net_bw_limit_out = atoi(optarg) * 1024;
break; break;
default: default:
usage(); usage();
} }
break; break;
case '?': case '?':
default: default:
usage(); usage();
} }
} }
args_done: args_done:
argc -= optind; argc -= optind;
argv += optind; argv += optind;


if (argc != 0) if (argc != 0)
usage(); usage();


setup_daemon(dir); setup_daemon(dir);




+ 242
- 242
btpd/net.c Wyświetl plik

@@ -55,10 +55,10 @@ net_del_torrent(struct torrent *tp)


struct peer *p = BTPDQ_FIRST(&net_unattached); struct peer *p = BTPDQ_FIRST(&net_unattached);
while (p != NULL) { while (p != NULL) {
struct peer *next = BTPDQ_NEXT(p, p_entry); struct peer *next = BTPDQ_NEXT(p, p_entry);
if (p->tp == tp) if (p->tp == tp)
peer_kill(p); peer_kill(p);
p = next; p = next;
} }
} }


@@ -89,67 +89,67 @@ net_write(struct peer *p, unsigned long wmax)
niov = 0; niov = 0;
assert((nl = BTPDQ_FIRST(&p->outq)) != NULL); assert((nl = BTPDQ_FIRST(&p->outq)) != NULL);
while ((niov < IOV_MAX && nl != NULL while ((niov < IOV_MAX && nl != NULL
&& (!limited || (limited && wmax > 0)))) { && (!limited || (limited && wmax > 0)))) {
if (niov > 0) { if (niov > 0) {
iov[niov].iov_base = nl->nb->buf; iov[niov].iov_base = nl->nb->buf;
iov[niov].iov_len = nl->nb->len; iov[niov].iov_len = nl->nb->len;
} else { } else {
iov[niov].iov_base = nl->nb->buf + p->outq_off; iov[niov].iov_base = nl->nb->buf + p->outq_off;
iov[niov].iov_len = nl->nb->len - p->outq_off; iov[niov].iov_len = nl->nb->len - p->outq_off;
} }
if (limited) { if (limited) {
if (iov[niov].iov_len > wmax) if (iov[niov].iov_len > wmax)
iov[niov].iov_len = wmax; iov[niov].iov_len = wmax;
wmax -= iov[niov].iov_len; wmax -= iov[niov].iov_len;
} }
niov++; niov++;
nl = BTPDQ_NEXT(nl, entry); nl = BTPDQ_NEXT(nl, entry);
} }


nwritten = writev(p->sd, iov, niov); nwritten = writev(p->sd, iov, niov);
if (nwritten < 0) { if (nwritten < 0) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
event_add(&p->out_ev, WRITE_TIMEOUT); event_add(&p->out_ev, WRITE_TIMEOUT);
return 0; return 0;
} else { } else {
btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno)); btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno));
peer_kill(p); peer_kill(p);
return 0; return 0;
} }
} else if (nwritten == 0) { } else if (nwritten == 0) {
btpd_log(BTPD_L_CONN, "connection closed by peer.\n"); btpd_log(BTPD_L_CONN, "connection closed by peer.\n");
peer_kill(p); peer_kill(p);
return 0; return 0;
} }


bcount = nwritten; bcount = nwritten;


nl = BTPDQ_FIRST(&p->outq); nl = BTPDQ_FIRST(&p->outq);
while (bcount > 0) { while (bcount > 0) {
unsigned long bufdelta = nl->nb->len - p->outq_off; unsigned long bufdelta = nl->nb->len - p->outq_off;
if (bcount >= bufdelta) { if (bcount >= bufdelta) {
peer_sent(p, nl->nb); peer_sent(p, nl->nb);
if (nl->nb->type == NB_TORRENTDATA) { if (nl->nb->type == NB_TORRENTDATA) {
p->tp->uploaded += bufdelta; p->tp->uploaded += bufdelta;
p->count_up += bufdelta; p->count_up += bufdelta;
} }
bcount -= bufdelta; bcount -= bufdelta;
BTPDQ_REMOVE(&p->outq, nl, entry); BTPDQ_REMOVE(&p->outq, nl, entry);
nb_drop(nl->nb); nb_drop(nl->nb);
free(nl); free(nl);
p->outq_off = 0; p->outq_off = 0;
nl = BTPDQ_FIRST(&p->outq); nl = BTPDQ_FIRST(&p->outq);
} else { } else {
if (nl->nb->type == NB_TORRENTDATA) { if (nl->nb->type == NB_TORRENTDATA) {
p->tp->uploaded += bcount; p->tp->uploaded += bcount;
p->count_up += bcount; p->count_up += bcount;
} }
p->outq_off += bcount; p->outq_off += bcount;
bcount = 0; bcount = 0;
} }
} }
if (!BTPDQ_EMPTY(&p->outq)) if (!BTPDQ_EMPTY(&p->outq))
event_add(&p->out_ev, WRITE_TIMEOUT); event_add(&p->out_ev, WRITE_TIMEOUT);


return nwritten; return nwritten;
} }
@@ -169,55 +169,55 @@ net_dispatch_msg(struct peer *p, const char *buf)


switch (p->net.msg_num) { switch (p->net.msg_num) {
case MSG_CHOKE: case MSG_CHOKE:
peer_on_choke(p); peer_on_choke(p);
break; break;
case MSG_UNCHOKE: case MSG_UNCHOKE:
peer_on_unchoke(p); peer_on_unchoke(p);
break; break;
case MSG_INTEREST: case MSG_INTEREST:
peer_on_interest(p); peer_on_interest(p);
break; break;
case MSG_UNINTEREST: case MSG_UNINTEREST:
peer_on_uninterest(p); peer_on_uninterest(p);
break; break;
case MSG_HAVE: case MSG_HAVE:
peer_on_have(p, net_read32(buf)); peer_on_have(p, net_read32(buf));
break; break;
case MSG_BITFIELD: case MSG_BITFIELD:
if (p->npieces == 0) if (p->npieces == 0)
peer_on_bitfield(p, buf); peer_on_bitfield(p, buf);
else else
res = 1; res = 1;
break; break;
case MSG_REQUEST: case MSG_REQUEST:
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) { if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) {
index = net_read32(buf); index = net_read32(buf);
begin = net_read32(buf + 4); begin = net_read32(buf + 4);
length = net_read32(buf + 8); length = net_read32(buf + 8);
if ((length > PIECE_BLOCKLEN if ((length > PIECE_BLOCKLEN
|| index >= p->tp->meta.npieces || index >= p->tp->meta.npieces
|| !has_bit(p->tp->piece_field, index) || !has_bit(p->tp->piece_field, index)
|| begin + length > torrent_piece_size(p->tp, index))) { || begin + length > torrent_piece_size(p->tp, index))) {
btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n", btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n",
index, begin, length, p); index, begin, length, p);
res = 1; res = 1;
break; break;
} }
peer_on_request(p, index, begin, length); peer_on_request(p, index, begin, length);
} }
break; break;
case MSG_CANCEL: case MSG_CANCEL:
index = net_read32(buf); index = net_read32(buf);
begin = net_read32(buf + 4); begin = net_read32(buf + 4);
length = net_read32(buf + 8); length = net_read32(buf + 8);
peer_on_cancel(p, index, begin, length); peer_on_cancel(p, index, begin, length);
break; break;
case MSG_PIECE: case MSG_PIECE:
length = p->net.msg_len - 9; length = p->net.msg_len - 9;
peer_on_piece(p, p->net.pc_index, p->net.pc_begin, length, buf); peer_on_piece(p, p->net.pc_index, p->net.pc_begin, length, buf);
break; break;
default: default:
abort(); abort();
} }
return res; return res;
} }
@@ -231,18 +231,18 @@ net_mh_ok(struct peer *p)
case MSG_UNCHOKE: case MSG_UNCHOKE:
case MSG_INTEREST: case MSG_INTEREST:
case MSG_UNINTEREST: case MSG_UNINTEREST:
return mlen == 1; return mlen == 1;
case MSG_HAVE: case MSG_HAVE:
return mlen == 5; return mlen == 5;
case MSG_BITFIELD: case MSG_BITFIELD:
return mlen == (uint32_t)ceil(p->tp->meta.npieces / 8.0) + 1; return mlen == (uint32_t)ceil(p->tp->meta.npieces / 8.0) + 1;
case MSG_REQUEST: case MSG_REQUEST:
case MSG_CANCEL: case MSG_CANCEL:
return mlen == 13; return mlen == 13;
case MSG_PIECE: case MSG_PIECE:
return mlen <= PIECE_BLOCKLEN + 9; return mlen <= PIECE_BLOCKLEN + 9;
default: default:
return 0; return 0;
} }
} }


@@ -250,8 +250,8 @@ static void
net_progress(struct peer *p, size_t length) net_progress(struct peer *p, size_t length)
{ {
if (p->net.state == BTP_MSGBODY && p->net.msg_num == MSG_PIECE) { if (p->net.state == BTP_MSGBODY && p->net.msg_num == MSG_PIECE) {
p->tp->downloaded += length; p->tp->downloaded += length;
p->count_dwn += length; p->count_dwn += length;
} }
} }


@@ -261,63 +261,63 @@ net_state(struct peer *p, const char *buf)
switch (p->net.state) { switch (p->net.state) {
case SHAKE_PSTR: case SHAKE_PSTR:
if (bcmp(buf, "\x13""BitTorrent protocol", 20) != 0) if (bcmp(buf, "\x13""BitTorrent protocol", 20) != 0)
goto bad; goto bad;
net_set_state(p, SHAKE_INFO, 20); net_set_state(p, SHAKE_INFO, 20);
break; break;
case SHAKE_INFO: case SHAKE_INFO:
if (p->flags & PF_INCOMING) { if (p->flags & PF_INCOMING) {
struct torrent *tp; struct torrent *tp;
BTPDQ_FOREACH(tp, &m_torrents, net_entry) BTPDQ_FOREACH(tp, &m_torrents, net_entry)
if (bcmp(buf, tp->meta.info_hash, 20) == 0) if (bcmp(buf, tp->meta.info_hash, 20) == 0)
break; break;
if (tp == NULL) if (tp == NULL)
goto bad; goto bad;
p->tp = tp; p->tp = tp;
peer_send(p, nb_create_shake(p->tp)); peer_send(p, nb_create_shake(p->tp));
} else if (bcmp(buf, p->tp->meta.info_hash, 20) != 0) } else if (bcmp(buf, p->tp->meta.info_hash, 20) != 0)
goto bad; goto bad;
net_set_state(p, SHAKE_ID, 20); net_set_state(p, SHAKE_ID, 20);
break; break;
case SHAKE_ID: case SHAKE_ID:
if ((torrent_has_peer(p->tp, buf) if ((torrent_has_peer(p->tp, buf)
|| bcmp(buf, btpd_get_peer_id(), 20) == 0)) || bcmp(buf, btpd_get_peer_id(), 20) == 0))
goto bad; goto bad;
bcopy(buf, p->id, 20); bcopy(buf, p->id, 20);
peer_on_shake(p); peer_on_shake(p);
net_set_state(p, BTP_MSGSIZE, 4); net_set_state(p, BTP_MSGSIZE, 4);
break; break;
case BTP_MSGSIZE: case BTP_MSGSIZE:
p->net.msg_len = net_read32(buf); p->net.msg_len = net_read32(buf);
if (p->net.msg_len == 0) if (p->net.msg_len == 0)
peer_on_keepalive(p); peer_on_keepalive(p);
else else
net_set_state(p, BTP_MSGHEAD, 1); net_set_state(p, BTP_MSGHEAD, 1);
break; break;
case BTP_MSGHEAD: case BTP_MSGHEAD:
p->net.msg_num = buf[0]; p->net.msg_num = buf[0];
if (!net_mh_ok(p)) if (!net_mh_ok(p))
goto bad; goto bad;
else if (p->net.msg_len == 1) { else if (p->net.msg_len == 1) {
if (net_dispatch_msg(p, buf) != 0) if (net_dispatch_msg(p, buf) != 0)
goto bad; goto bad;
net_set_state(p, BTP_MSGSIZE, 4); net_set_state(p, BTP_MSGSIZE, 4);
} else if (p->net.msg_num == MSG_PIECE) } else if (p->net.msg_num == MSG_PIECE)
net_set_state(p, BTP_PIECEMETA, 8); net_set_state(p, BTP_PIECEMETA, 8);
else else
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 1); net_set_state(p, BTP_MSGBODY, p->net.msg_len - 1);
break; break;
case BTP_PIECEMETA: case BTP_PIECEMETA:
p->net.pc_index = net_read32(buf); p->net.pc_index = net_read32(buf);
p->net.pc_begin = net_read32(buf + 4); p->net.pc_begin = net_read32(buf + 4);
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 9); net_set_state(p, BTP_MSGBODY, p->net.msg_len - 9);
break; break;
case BTP_MSGBODY: case BTP_MSGBODY:
if (net_dispatch_msg(p, buf) != 0) if (net_dispatch_msg(p, buf) != 0)
goto bad; goto bad;
net_set_state(p, BTP_MSGSIZE, 4); net_set_state(p, BTP_MSGSIZE, 4);
break; break;
default: default:
abort(); abort();
} }


return 0; return 0;
@@ -336,44 +336,44 @@ net_read(struct peer *p, unsigned long rmax)
size_t rest = p->net.buf != NULL ? p->net.st_bytes - p->net.off : 0; size_t rest = p->net.buf != NULL ? p->net.st_bytes - p->net.off : 0;
char buf[GRBUFLEN]; char buf[GRBUFLEN];
struct iovec iov[2] = { struct iovec iov[2] = {
{ {
p->net.buf + p->net.off, p->net.buf + p->net.off,
rest rest
}, { }, {
buf, buf,
sizeof(buf) sizeof(buf)
} }
}; };


if (rmax > 0) { if (rmax > 0) {
if (iov[0].iov_len > rmax) if (iov[0].iov_len > rmax)
iov[0].iov_len = rmax; iov[0].iov_len = rmax;
iov[1].iov_len = min(rmax - iov[0].iov_len, iov[1].iov_len); iov[1].iov_len = min(rmax - iov[0].iov_len, iov[1].iov_len);
} }


ssize_t nread = readv(p->sd, iov, 2); ssize_t nread = readv(p->sd, iov, 2);
if (nread < 0 && errno == EAGAIN) if (nread < 0 && errno == EAGAIN)
goto out; goto out;
else if (nread < 0) { else if (nread < 0) {
btpd_log(BTPD_L_CONN, "Read error (%s) on %p.\n", strerror(errno), p); btpd_log(BTPD_L_CONN, "Read error (%s) on %p.\n", strerror(errno), p);
peer_kill(p); peer_kill(p);
return 0; return 0;
} else if (nread == 0) { } else if (nread == 0) {
btpd_log(BTPD_L_CONN, "Connection closed by %p.\n", p); btpd_log(BTPD_L_CONN, "Connection closed by %p.\n", p);
peer_kill(p); peer_kill(p);
return 0; return 0;
} }


if (rest > 0) { if (rest > 0) {
if (nread < rest) { if (nread < rest) {
p->net.off += nread; p->net.off += nread;
net_progress(p, nread); net_progress(p, nread);
goto out; goto out;
} }
net_progress(p, rest); net_progress(p, rest);
if (net_state(p, p->net.buf) != 0) if (net_state(p, p->net.buf) != 0)
return nread; return nread;
free(p->net.buf); free(p->net.buf);
p->net.buf = NULL; p->net.buf = NULL;
p->net.off = 0; p->net.off = 0;
} }
@@ -381,18 +381,18 @@ net_read(struct peer *p, unsigned long rmax)
iov[1].iov_len = nread - rest; iov[1].iov_len = nread - rest;
while (p->net.st_bytes <= iov[1].iov_len) { while (p->net.st_bytes <= iov[1].iov_len) {
size_t consumed = p->net.st_bytes; size_t consumed = p->net.st_bytes;
net_progress(p, consumed); net_progress(p, consumed);
if (net_state(p, iov[1].iov_base) != 0) if (net_state(p, iov[1].iov_base) != 0)
return nread; return nread;
iov[1].iov_base += consumed; iov[1].iov_base += consumed;
iov[1].iov_len -= consumed; iov[1].iov_len -= consumed;
} }


if (iov[1].iov_len > 0) { if (iov[1].iov_len > 0) {
net_progress(p, iov[1].iov_len); net_progress(p, iov[1].iov_len);
p->net.off = iov[1].iov_len; p->net.off = iov[1].iov_len;
p->net.buf = btpd_malloc(p->net.st_bytes); p->net.buf = btpd_malloc(p->net.st_bytes);
bcopy(iov[1].iov_base, p->net.buf, iov[1].iov_len); bcopy(iov[1].iov_base, p->net.buf, iov[1].iov_len);
} }


out: out:
@@ -403,15 +403,15 @@ out:
int int
net_connect2(struct sockaddr *sa, socklen_t salen, int *sd) net_connect2(struct sockaddr *sa, socklen_t salen, int *sd)
{ {
if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
return errno; return errno;
set_nonblocking(*sd); set_nonblocking(*sd);


if (connect(*sd, sa, salen) == -1 && errno != EINPROGRESS) { if (connect(*sd, sa, salen) == -1 && errno != EINPROGRESS) {
btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno)); btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno));
close(*sd); close(*sd);
return errno; return errno;
} }


return 0; return 0;
@@ -422,17 +422,17 @@ net_connect(const char *ip, int port, int *sd)
{ {
struct addrinfo hints, *res; struct addrinfo hints, *res;
char portstr[6]; char portstr[6];
assert(net_npeers < net_max_peers); assert(net_npeers < net_max_peers);


if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr))
return EINVAL; return EINVAL;
bzero(&hints, sizeof(hints)); bzero(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST; hints.ai_flags = AI_NUMERICHOST;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(ip, portstr, &hints, &res) != 0) if (getaddrinfo(ip, portstr, &hints, &res) != 0)
return errno; return errno;


int error = net_connect2(res->ai_addr, res->ai_addrlen, sd); int error = net_connect2(res->ai_addr, res->ai_addrlen, sd);
freeaddrinfo(res); freeaddrinfo(res);
@@ -446,21 +446,21 @@ net_connection_cb(int sd, short type, void *arg)


nsd = accept(sd, NULL, NULL); nsd = accept(sd, NULL, NULL);
if (nsd < 0) { if (nsd < 0) {
if (errno == EWOULDBLOCK || errno == ECONNABORTED) if (errno == EWOULDBLOCK || errno == ECONNABORTED)
return; return;
else else
btpd_err("accept4: %s\n", strerror(errno)); btpd_err("accept4: %s\n", strerror(errno));
} }


if (set_nonblocking(nsd) != 0) { if (set_nonblocking(nsd) != 0) {
close(nsd); close(nsd);
return; return;
} }


assert(net_npeers <= net_max_peers); assert(net_npeers <= net_max_peers);
if (net_npeers == net_max_peers) { if (net_npeers == net_max_peers) {
close(nsd); close(nsd);
return; return;
} }


peer_create_in(nsd); peer_create_in(nsd);
@@ -474,35 +474,35 @@ long
compute_rate_sub(long rate) compute_rate_sub(long rate)
{ {
if (rate > 256 * RATEHISTORY) if (rate > 256 * RATEHISTORY)
return rate / RATEHISTORY; return rate / RATEHISTORY;
else else
return 256; return 256;
} }


static void static void
compute_peer_rates(void) { compute_peer_rates(void) {
struct torrent *tp; struct torrent *tp;
BTPDQ_FOREACH(tp, &m_torrents, net_entry) { BTPDQ_FOREACH(tp, &m_torrents, net_entry) {
struct peer *p; struct peer *p;
BTPDQ_FOREACH(p, &tp->peers, p_entry) { BTPDQ_FOREACH(p, &tp->peers, p_entry) {
if (p->count_up > 0 || peer_active_up(p)) { if (p->count_up > 0 || peer_active_up(p)) {
p->rate_up += p->count_up - compute_rate_sub(p->rate_up); p->rate_up += p->count_up - compute_rate_sub(p->rate_up);
if (p->rate_up < 0) if (p->rate_up < 0)
p->rate_up = 0; p->rate_up = 0;
p->count_up = 0; p->count_up = 0;
} }
if (p->count_dwn > 0 || peer_active_down(p)) { if (p->count_dwn > 0 || peer_active_down(p)) {
p->rate_dwn += p->count_dwn - compute_rate_sub(p->rate_dwn); p->rate_dwn += p->count_dwn - compute_rate_sub(p->rate_dwn);
if (p->rate_dwn < 0) if (p->rate_dwn < 0)
p->rate_dwn = 0; p->rate_dwn = 0;
p->count_dwn = 0; p->count_dwn = 0;
} }
} }
} }
} }


void void
net_bw_cb(int sd, short type, void *arg) net_bw_cb(int sd, short type, void *arg)
{ {
struct peer *p; struct peer *p;


@@ -514,31 +514,31 @@ net_bw_cb(int sd, short type, void *arg)
m_bw_bytes_in = net_bw_limit_in; m_bw_bytes_in = net_bw_limit_in;


if (net_bw_limit_in > 0) { if (net_bw_limit_in > 0) {
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) { while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) {
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); BTPDQ_REMOVE(&net_bw_readq, p, rq_entry);
p->flags &= ~PF_ON_READQ; p->flags &= ~PF_ON_READQ;
m_bw_bytes_in -= net_read(p, m_bw_bytes_in); m_bw_bytes_in -= net_read(p, m_bw_bytes_in);
} }
} else { } else {
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) { while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) {
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); BTPDQ_REMOVE(&net_bw_readq, p, rq_entry);
p->flags &= ~PF_ON_READQ; p->flags &= ~PF_ON_READQ;
net_read(p, 0); net_read(p, 0);
} }
} }


if (net_bw_limit_out) { if (net_bw_limit_out) {
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) {
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
p->flags &= ~PF_ON_WRITEQ; p->flags &= ~PF_ON_WRITEQ;
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); m_bw_bytes_out -= net_write(p, m_bw_bytes_out);
} }
} else { } else {
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) { while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) {
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
p->flags &= ~PF_ON_WRITEQ; p->flags &= ~PF_ON_WRITEQ;
net_write(p, 0); net_write(p, 0);
} }
} }
} }


@@ -547,12 +547,12 @@ net_read_cb(int sd, short type, void *arg)
{ {
struct peer *p = (struct peer *)arg; struct peer *p = (struct peer *)arg;
if (net_bw_limit_in == 0) if (net_bw_limit_in == 0)
net_read(p, 0); net_read(p, 0);
else if (m_bw_bytes_in > 0) else if (m_bw_bytes_in > 0)
m_bw_bytes_in -= net_read(p, m_bw_bytes_in); m_bw_bytes_in -= net_read(p, m_bw_bytes_in);
else { else {
p->flags |= PF_ON_READQ; p->flags |= PF_ON_READQ;
BTPDQ_INSERT_TAIL(&net_bw_readq, p, rq_entry); BTPDQ_INSERT_TAIL(&net_bw_readq, p, rq_entry);
} }
} }


@@ -561,17 +561,17 @@ net_write_cb(int sd, short type, void *arg)
{ {
struct peer *p = (struct peer *)arg; struct peer *p = (struct peer *)arg;
if (type == EV_TIMEOUT) { if (type == EV_TIMEOUT) {
btpd_log(BTPD_L_CONN, "Write attempt timed out.\n"); btpd_log(BTPD_L_CONN, "Write attempt timed out.\n");
peer_kill(p); peer_kill(p);
return; return;
} }
if (net_bw_limit_out == 0) { if (net_bw_limit_out == 0) {
net_write(p, 0); net_write(p, 0);
} else if (m_bw_bytes_out > 0) { } else if (m_bw_bytes_out > 0) {
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); m_bw_bytes_out -= net_write(p, m_bw_bytes_out);
} else { } else {
p->flags |= PF_ON_WRITEQ; p->flags |= PF_ON_WRITEQ;
BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry);
} }
} }


@@ -583,13 +583,13 @@ net_init(void)


int nfiles = getdtablesize(); int nfiles = getdtablesize();
if (nfiles <= 20) if (nfiles <= 20)
btpd_err("Too few open files allowed (%d). " btpd_err("Too few open files allowed (%d). "
"Check \"ulimit -n\"\n", nfiles); "Check \"ulimit -n\"\n", nfiles);
else if (nfiles < 64) else if (nfiles < 64)
btpd_log(BTPD_L_BTPD, btpd_log(BTPD_L_BTPD,
"You have restricted the number of open files to %d. " "You have restricted the number of open files to %d. "
"More could be beneficial to the download performance.\n", "More could be beneficial to the download performance.\n",
nfiles); nfiles);
net_max_peers = nfiles - 20; net_max_peers = nfiles - 20;


int sd; int sd;
@@ -600,10 +600,10 @@ net_init(void)
addr.sin_port = htons(net_port); addr.sin_port = htons(net_port);


if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
btpd_err("socket: %s\n", strerror(errno)); btpd_err("socket: %s\n", strerror(errno));
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
btpd_err("bind: %s\n", strerror(errno)); btpd_err("bind: %s\n", strerror(errno));
listen(sd, 10); listen(sd, 10);
set_nonblocking(sd); set_nonblocking(sd);




+ 9
- 9
btpd/net.h Wyświetl plik

@@ -1,15 +1,15 @@
#ifndef BTPD_NET_H #ifndef BTPD_NET_H
#define BTPD_NET_H #define BTPD_NET_H


#define MSG_CHOKE 0 #define MSG_CHOKE 0
#define MSG_UNCHOKE 1 #define MSG_UNCHOKE 1
#define MSG_INTEREST 2 #define MSG_INTEREST 2
#define MSG_UNINTEREST 3 #define MSG_UNINTEREST 3
#define MSG_HAVE 4 #define MSG_HAVE 4
#define MSG_BITFIELD 5 #define MSG_BITFIELD 5
#define MSG_REQUEST 6 #define MSG_REQUEST 6
#define MSG_PIECE 7 #define MSG_PIECE 7
#define MSG_CANCEL 8 #define MSG_CANCEL 8


#define WRITE_TIMEOUT (& (struct timeval) { 60, 0 }) #define WRITE_TIMEOUT (& (struct timeval) { 60, 0 })




+ 24
- 24
btpd/net_buf.c Wyświetl plik

@@ -123,12 +123,12 @@ nb_create_multihave(struct torrent *tp)
{ {
struct net_buf *out = nb_create_alloc(NB_MULTIHAVE, 9 * tp->have_npieces); struct net_buf *out = nb_create_alloc(NB_MULTIHAVE, 9 * tp->have_npieces);
for (uint32_t i = 0, count = 0; count < tp->have_npieces; i++) { for (uint32_t i = 0, count = 0; count < tp->have_npieces; i++) {
if (has_bit(tp->piece_field, i)) { if (has_bit(tp->piece_field, i)) {
net_write32(out->buf + count * 9, 5); net_write32(out->buf + count * 9, 5);
out->buf[count * 9 + 4] = MSG_HAVE; out->buf[count * 9 + 4] = MSG_HAVE;
net_write32(out->buf + count * 9 + 5, i); net_write32(out->buf + count * 9 + 5, i);
count++; count++;
} }
} }
return out; return out;
} }
@@ -137,7 +137,7 @@ struct net_buf *
nb_create_unchoke(void) nb_create_unchoke(void)
{ {
if (m_unchoke == NULL) if (m_unchoke == NULL)
m_unchoke = nb_singleton(nb_create_onesized(MSG_UNCHOKE, NB_UNCHOKE)); m_unchoke = nb_singleton(nb_create_onesized(MSG_UNCHOKE, NB_UNCHOKE));
return m_unchoke; return m_unchoke;
} }


@@ -145,7 +145,7 @@ struct net_buf *
nb_create_choke(void) nb_create_choke(void)
{ {
if (m_choke == NULL) if (m_choke == NULL)
m_choke = nb_singleton(nb_create_onesized(MSG_CHOKE, NB_CHOKE)); m_choke = nb_singleton(nb_create_onesized(MSG_CHOKE, NB_CHOKE));
return m_choke; return m_choke;
} }


@@ -153,8 +153,8 @@ struct net_buf *
nb_create_uninterest(void) nb_create_uninterest(void)
{ {
if (m_uninterest == NULL) if (m_uninterest == NULL)
m_uninterest = m_uninterest =
nb_singleton(nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST)); nb_singleton(nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST));
return m_uninterest; return m_uninterest;
} }


@@ -162,8 +162,8 @@ struct net_buf *
nb_create_interest(void) nb_create_interest(void)
{ {
if (m_interest == NULL) if (m_interest == NULL)
m_interest = m_interest =
nb_singleton(nb_create_onesized(MSG_INTEREST, NB_INTEREST)); nb_singleton(nb_create_onesized(MSG_INTEREST, NB_INTEREST));
return m_interest; return m_interest;
} }


@@ -183,7 +183,7 @@ nb_create_bitdata(struct torrent *tp)
{ {
uint32_t plen = ceil(tp->meta.npieces / 8.0); uint32_t plen = ceil(tp->meta.npieces / 8.0);
struct net_buf *out = struct net_buf *out =
nb_create_set(NB_BITDATA, tp->piece_field, plen, kill_buf_no); nb_create_set(NB_BITDATA, tp->piece_field, plen, kill_buf_no);
return out; return out;
} }


@@ -205,9 +205,9 @@ nb_get_index(struct net_buf *nb)
case NB_HAVE: case NB_HAVE:
case NB_PIECE: case NB_PIECE:
case NB_REQUEST: case NB_REQUEST:
return net_read32(nb->buf + 5); return net_read32(nb->buf + 5);
default: default:
abort(); abort();
} }
} }


@@ -218,9 +218,9 @@ nb_get_begin(struct net_buf *nb)
case NB_CANCEL: case NB_CANCEL:
case NB_PIECE: case NB_PIECE:
case NB_REQUEST: case NB_REQUEST:
return net_read32(nb->buf + 9); return net_read32(nb->buf + 9);
default: default:
abort(); abort();
} }
} }


@@ -230,11 +230,11 @@ nb_get_length(struct net_buf *nb)
switch (nb->type) { switch (nb->type) {
case NB_CANCEL: case NB_CANCEL:
case NB_REQUEST: case NB_REQUEST:
return net_read32(nb->buf + 13); return net_read32(nb->buf + 13);
case NB_PIECE: case NB_PIECE:
return net_read32(nb->buf) - 9; return net_read32(nb->buf) - 9;
default: default:
abort(); abort();
} }
} }


@@ -244,11 +244,11 @@ nb_drop(struct net_buf *nb)
assert(nb->refs > 0); assert(nb->refs > 0);
nb->refs--; nb->refs--;
if (nb->refs == 0) { if (nb->refs == 0) {
nb->kill_buf(nb->buf, nb->len); nb->kill_buf(nb->buf, nb->len);
free(nb); free(nb);
return 1; return 1;
} else } else
return 0; return 0;
} }


void void


+ 13
- 13
btpd/net_buf.h Wyświetl plik

@@ -1,19 +1,19 @@
#ifndef BTPD_NET_BUF_H #ifndef BTPD_NET_BUF_H
#define BTPD_NET_BUF_H #define BTPD_NET_BUF_H


#define NB_CHOKE 0 #define NB_CHOKE 0
#define NB_UNCHOKE 1 #define NB_UNCHOKE 1
#define NB_INTEREST 2 #define NB_INTEREST 2
#define NB_UNINTEREST 3 #define NB_UNINTEREST 3
#define NB_HAVE 4 #define NB_HAVE 4
#define NB_BITFIELD 5 #define NB_BITFIELD 5
#define NB_REQUEST 6 #define NB_REQUEST 6
#define NB_PIECE 7 #define NB_PIECE 7
#define NB_CANCEL 8 #define NB_CANCEL 8
#define NB_TORRENTDATA 10 #define NB_TORRENTDATA 10
#define NB_MULTIHAVE 11 #define NB_MULTIHAVE 11
#define NB_BITDATA 12 #define NB_BITDATA 12
#define NB_SHAKE 13 #define NB_SHAKE 13


struct net_buf { struct net_buf {
short type; short type;


+ 164
- 164
btpd/peer.c Wyświetl plik

@@ -18,13 +18,13 @@ peer_kill(struct peer *p)


if (p->flags & PF_ATTACHED) { if (p->flags & PF_ATTACHED) {
ul_on_lost_peer(p); ul_on_lost_peer(p);
dl_on_lost_peer(p); dl_on_lost_peer(p);
} else } else
BTPDQ_REMOVE(&net_unattached, p, p_entry); BTPDQ_REMOVE(&net_unattached, p, p_entry);
if (p->flags & PF_ON_READQ) if (p->flags & PF_ON_READQ)
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); BTPDQ_REMOVE(&net_bw_readq, p, rq_entry);
if (p->flags & PF_ON_WRITEQ) if (p->flags & PF_ON_WRITEQ)
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);


close(p->sd); close(p->sd);
event_del(&p->in_ev); event_del(&p->in_ev);
@@ -32,14 +32,14 @@ peer_kill(struct peer *p)


nl = BTPDQ_FIRST(&p->outq); nl = BTPDQ_FIRST(&p->outq);
while (nl != NULL) { while (nl != NULL) {
struct nb_link *next = BTPDQ_NEXT(nl, entry); struct nb_link *next = BTPDQ_NEXT(nl, entry);
nb_drop(nl->nb); nb_drop(nl->nb);
free(nl); free(nl);
nl = next; nl = next;
} }


if (p->net.buf != NULL) if (p->net.buf != NULL)
free(p->net.buf); free(p->net.buf);
if (p->piece_field != NULL) if (p->piece_field != NULL)
free(p->piece_field); free(p->piece_field);
free(p); free(p);
@@ -54,8 +54,8 @@ peer_send(struct peer *p, struct net_buf *nb)
nb_hold(nb); nb_hold(nb);


if (BTPDQ_EMPTY(&p->outq)) { if (BTPDQ_EMPTY(&p->outq)) {
assert(p->outq_off == 0); assert(p->outq_off == 0);
event_add(&p->out_ev, WRITE_TIMEOUT); event_add(&p->out_ev, WRITE_TIMEOUT);
} }
BTPDQ_INSERT_TAIL(&p->outq, nl, entry); BTPDQ_INSERT_TAIL(&p->outq, nl, entry);
} }
@@ -71,23 +71,23 @@ int
peer_unsend(struct peer *p, struct nb_link *nl) peer_unsend(struct peer *p, struct nb_link *nl)
{ {
if (!(nl == BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) { if (!(nl == BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) {
BTPDQ_REMOVE(&p->outq, nl, entry); BTPDQ_REMOVE(&p->outq, nl, entry);
if (nl->nb->type == NB_TORRENTDATA) { if (nl->nb->type == NB_TORRENTDATA) {
assert(p->npiece_msgs > 0); assert(p->npiece_msgs > 0);
p->npiece_msgs--; p->npiece_msgs--;
} }
nb_drop(nl->nb); nb_drop(nl->nb);
free(nl); free(nl);
if (BTPDQ_EMPTY(&p->outq)) { if (BTPDQ_EMPTY(&p->outq)) {
if (p->flags & PF_ON_WRITEQ) { if (p->flags & PF_ON_WRITEQ) {
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
p->flags &= ~PF_ON_WRITEQ; p->flags &= ~PF_ON_WRITEQ;
} else } else
event_del(&p->out_ev); event_del(&p->out_ev);
} }
return 1; return 1;
} else } else
return 0; return 0;
} }


void void
@@ -95,51 +95,51 @@ peer_sent(struct peer *p, struct net_buf *nb)
{ {
switch (nb->type) { switch (nb->type) {
case NB_CHOKE: case NB_CHOKE:
btpd_log(BTPD_L_MSG, "sent choke to %p\n", p); btpd_log(BTPD_L_MSG, "sent choke to %p\n", p);
break; break;
case NB_UNCHOKE: case NB_UNCHOKE:
btpd_log(BTPD_L_MSG, "sent unchoke to %p\n", p); btpd_log(BTPD_L_MSG, "sent unchoke to %p\n", p);
p->flags &= ~PF_NO_REQUESTS; p->flags &= ~PF_NO_REQUESTS;
break; break;
case NB_INTEREST: case NB_INTEREST:
btpd_log(BTPD_L_MSG, "sent interest to %p\n", p); btpd_log(BTPD_L_MSG, "sent interest to %p\n", p);
break; break;
case NB_UNINTEREST: case NB_UNINTEREST:
btpd_log(BTPD_L_MSG, "sent uninterest to %p\n", p); btpd_log(BTPD_L_MSG, "sent uninterest to %p\n", p);
break; break;
case NB_HAVE: case NB_HAVE:
btpd_log(BTPD_L_MSG, "sent have(%u) to %p\n", btpd_log(BTPD_L_MSG, "sent have(%u) to %p\n",
nb_get_index(nb), p); nb_get_index(nb), p);
break; break;
case NB_BITFIELD: case NB_BITFIELD:
btpd_log(BTPD_L_MSG, "sent bitfield to %p\n", p); btpd_log(BTPD_L_MSG, "sent bitfield to %p\n", p);
break; break;
case NB_REQUEST: case NB_REQUEST:
btpd_log(BTPD_L_MSG, "sent request(%u,%u,%u) to %p\n", btpd_log(BTPD_L_MSG, "sent request(%u,%u,%u) to %p\n",
nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p); nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p);
break; break;
case NB_PIECE: case NB_PIECE:
btpd_log(BTPD_L_MSG, "sent piece(%u,%u,%u) to %p\n", btpd_log(BTPD_L_MSG, "sent piece(%u,%u,%u) to %p\n",
nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p); nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p);
break; break;
case NB_CANCEL: case NB_CANCEL:
btpd_log(BTPD_L_MSG, "sent cancel(%u,%u,%u) to %p\n", btpd_log(BTPD_L_MSG, "sent cancel(%u,%u,%u) to %p\n",
nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p); nb_get_index(nb), nb_get_begin(nb), nb_get_length(nb), p);
break; break;
case NB_TORRENTDATA: case NB_TORRENTDATA:
btpd_log(BTPD_L_MSG, "sent data to %p\n", p); btpd_log(BTPD_L_MSG, "sent data to %p\n", p);
assert(p->npiece_msgs > 0); assert(p->npiece_msgs > 0);
p->npiece_msgs--; p->npiece_msgs--;
break; break;
case NB_MULTIHAVE: case NB_MULTIHAVE:
btpd_log(BTPD_L_MSG, "sent multihave to %p\n", p); btpd_log(BTPD_L_MSG, "sent multihave to %p\n", p);
break; break;
case NB_BITDATA: case NB_BITDATA:
btpd_log(BTPD_L_MSG, "sent bitdata to %p\n", p); btpd_log(BTPD_L_MSG, "sent bitdata to %p\n", p);
break; break;
case NB_SHAKE: case NB_SHAKE:
btpd_log(BTPD_L_MSG, "sent shake to %p\n", p); btpd_log(BTPD_L_MSG, "sent shake to %p\n", p);
break; break;
} }
} }


@@ -157,8 +157,8 @@ peer_requested(struct peer *p, struct block *blk)
{ {
struct block_request *req; struct block_request *req;
BTPDQ_FOREACH(req, &p->my_reqs, p_entry) BTPDQ_FOREACH(req, &p->my_reqs, p_entry)
if (req->blk == blk) if (req->blk == blk)
return 1; return 1;
return 0; return 0;
} }


@@ -171,15 +171,15 @@ peer_cancel(struct peer *p, struct block_request *req, struct net_buf *nb)
int removed = 0; int removed = 0;
struct nb_link *nl; struct nb_link *nl;
BTPDQ_FOREACH(nl, &p->outq, entry) { BTPDQ_FOREACH(nl, &p->outq, entry) {
if (nl->nb == req->blk->msg) { if (nl->nb == req->blk->msg) {
removed = peer_unsend(p, nl); removed = peer_unsend(p, nl);
break; break;
} }
} }
if (!removed) if (!removed)
peer_send(p, nb); peer_send(p, nb);
if (p->nreqs_out == 0) if (p->nreqs_out == 0)
peer_on_no_reqs(p); peer_on_no_reqs(p);
} }


void void
@@ -194,14 +194,14 @@ peer_choke(struct peer *p)
{ {
struct nb_link *nl = BTPDQ_FIRST(&p->outq); struct nb_link *nl = BTPDQ_FIRST(&p->outq);
while (nl != NULL) { while (nl != NULL) {
struct nb_link *next = BTPDQ_NEXT(nl, entry); struct nb_link *next = BTPDQ_NEXT(nl, entry);
if (nl->nb->type == NB_PIECE) { if (nl->nb->type == NB_PIECE) {
struct nb_link *data = next; struct nb_link *data = next;
next = BTPDQ_NEXT(next, entry); next = BTPDQ_NEXT(next, entry);
if (peer_unsend(p, nl)) if (peer_unsend(p, nl))
peer_unsend(p, data); peer_unsend(p, data);
} }
nl = next; nl = next;
} }


p->flags |= PF_I_CHOKE; p->flags |= PF_I_CHOKE;
@@ -214,19 +214,19 @@ peer_want(struct peer *p, uint32_t index)
assert(p->nwant < p->npieces); assert(p->nwant < p->npieces);
p->nwant++; p->nwant++;
if (p->nwant == 1) { if (p->nwant == 1) {
if (p->nreqs_out == 0) { if (p->nreqs_out == 0) {
assert((p->flags & PF_DO_UNWANT) == 0); assert((p->flags & PF_DO_UNWANT) == 0);
int unsent = 0; int unsent = 0;
struct nb_link *nl = BTPDQ_LAST(&p->outq, nb_tq); struct nb_link *nl = BTPDQ_LAST(&p->outq, nb_tq);
if (nl != NULL && nl->nb->type == NB_UNINTEREST) if (nl != NULL && nl->nb->type == NB_UNINTEREST)
unsent = peer_unsend(p, nl); unsent = peer_unsend(p, nl);
if (!unsent) if (!unsent)
peer_send(p, nb_create_interest()); peer_send(p, nb_create_interest());
} else { } else {
assert((p->flags & PF_DO_UNWANT) != 0); assert((p->flags & PF_DO_UNWANT) != 0);
p->flags &= ~PF_DO_UNWANT; p->flags &= ~PF_DO_UNWANT;
} }
p->flags |= PF_I_WANT; p->flags |= PF_I_WANT;
} }
} }


@@ -236,11 +236,11 @@ peer_unwant(struct peer *p, uint32_t index)
assert(p->nwant > 0); assert(p->nwant > 0);
p->nwant--; p->nwant--;
if (p->nwant == 0) { if (p->nwant == 0) {
p->flags &= ~PF_I_WANT; p->flags &= ~PF_I_WANT;
if (p->nreqs_out == 0) if (p->nreqs_out == 0)
peer_send(p, nb_create_uninterest()); peer_send(p, nb_create_uninterest());
else else
p->flags |= PF_DO_UNWANT; p->flags |= PF_DO_UNWANT;
} }
} }


@@ -280,7 +280,7 @@ peer_create_out(struct torrent *tp, const uint8_t *id,
struct peer *p; struct peer *p;


if (net_connect(ip, port, &sd) != 0) if (net_connect(ip, port, &sd) != 0)
return; return;


p = peer_create_common(sd); p = peer_create_common(sd);
p->tp = tp; p->tp = tp;
@@ -299,7 +299,7 @@ peer_create_out_compact(struct torrent *tp, const char *compact)
addr.sin_port = *(short *)(compact + 4); addr.sin_port = *(short *)(compact + 4);


if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0) if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0)
return; return;


p = peer_create_common(sd); p = peer_create_common(sd);
p->tp = tp; p->tp = tp;
@@ -310,9 +310,9 @@ void
peer_on_no_reqs(struct peer *p) peer_on_no_reqs(struct peer *p)
{ {
if ((p->flags & PF_DO_UNWANT) != 0) { if ((p->flags & PF_DO_UNWANT) != 0) {
assert(p->nwant == 0); assert(p->nwant == 0);
p->flags &= ~PF_DO_UNWANT; p->flags &= ~PF_DO_UNWANT;
peer_send(p, nb_create_uninterest()); peer_send(p, nb_create_uninterest());
} }
} }


@@ -328,7 +328,7 @@ peer_on_shake(struct peer *p)
uint8_t printid[21]; uint8_t printid[21];
int i; int i;
for (i = 0; i < 20 && isprint(p->id[i]); i++) for (i = 0; i < 20 && isprint(p->id[i]); i++)
printid[i] = p->id[i]; printid[i] = p->id[i];
printid[i] = '\0'; printid[i] = '\0';
btpd_log(BTPD_L_MSG, "received shake(%s) from %p\n", printid, p); btpd_log(BTPD_L_MSG, "received shake(%s) from %p\n", printid, p);
p->piece_field = btpd_calloc(1, (int)ceil(p->tp->meta.npieces / 8.0)); p->piece_field = btpd_calloc(1, (int)ceil(p->tp->meta.npieces / 8.0));
@@ -349,19 +349,19 @@ peer_on_choke(struct peer *p)
{ {
btpd_log(BTPD_L_MSG, "received choke from %p\n", p); btpd_log(BTPD_L_MSG, "received choke from %p\n", p);
if ((p->flags & PF_P_CHOKE) != 0) if ((p->flags & PF_P_CHOKE) != 0)
return; return;
else { else {
if (p->nreqs_out > 0) if (p->nreqs_out > 0)
peer_on_no_reqs(p); peer_on_no_reqs(p);
p->flags |= PF_P_CHOKE; p->flags |= PF_P_CHOKE;
dl_on_choke(p); dl_on_choke(p);
struct nb_link *nl = BTPDQ_FIRST(&p->outq); struct nb_link *nl = BTPDQ_FIRST(&p->outq);
while (nl != NULL) { while (nl != NULL) {
struct nb_link *next = BTPDQ_NEXT(nl, entry); struct nb_link *next = BTPDQ_NEXT(nl, entry);
if (nl->nb->type == NB_REQUEST) if (nl->nb->type == NB_REQUEST)
peer_unsend(p, nl); peer_unsend(p, nl);
nl = next; nl = next;
} }
} }
} }


@@ -370,10 +370,10 @@ peer_on_unchoke(struct peer *p)
{ {
btpd_log(BTPD_L_MSG, "received unchoke from %p\n", p); btpd_log(BTPD_L_MSG, "received unchoke from %p\n", p);
if ((p->flags & PF_P_CHOKE) == 0) if ((p->flags & PF_P_CHOKE) == 0)
return; return;
else { else {
p->flags &= ~PF_P_CHOKE; p->flags &= ~PF_P_CHOKE;
dl_on_unchoke(p); dl_on_unchoke(p);
} }
} }


@@ -382,10 +382,10 @@ peer_on_interest(struct peer *p)
{ {
btpd_log(BTPD_L_MSG, "received interest from %p\n", p); btpd_log(BTPD_L_MSG, "received interest from %p\n", p);
if ((p->flags & PF_P_WANT) != 0) if ((p->flags & PF_P_WANT) != 0)
return; return;
else { else {
p->flags |= PF_P_WANT; p->flags |= PF_P_WANT;
ul_on_interest(p); ul_on_interest(p);
} }
} }


@@ -394,10 +394,10 @@ peer_on_uninterest(struct peer *p)
{ {
btpd_log(BTPD_L_MSG, "received uninterest from %p\n", p); btpd_log(BTPD_L_MSG, "received uninterest from %p\n", p);
if ((p->flags & PF_P_WANT) == 0) if ((p->flags & PF_P_WANT) == 0)
return; return;
else { else {
p->flags &= ~PF_P_WANT; p->flags &= ~PF_P_WANT;
ul_on_uninterest(p); ul_on_uninterest(p);
} }
} }


@@ -406,9 +406,9 @@ peer_on_have(struct peer *p, uint32_t index)
{ {
btpd_log(BTPD_L_MSG, "received have(%u) from %p\n", index, p); btpd_log(BTPD_L_MSG, "received have(%u) from %p\n", index, p);
if (!has_bit(p->piece_field, index)) { if (!has_bit(p->piece_field, index)) {
set_bit(p->piece_field, index); set_bit(p->piece_field, index);
p->npieces++; p->npieces++;
dl_on_piece_ann(p, index); dl_on_piece_ann(p, index);
} }
} }


@@ -419,10 +419,10 @@ peer_on_bitfield(struct peer *p, const uint8_t *field)
assert(p->npieces == 0); assert(p->npieces == 0);
bcopy(field, p->piece_field, (size_t)ceil(p->tp->meta.npieces / 8.0)); bcopy(field, p->piece_field, (size_t)ceil(p->tp->meta.npieces / 8.0));
for (uint32_t i = 0; i < p->tp->meta.npieces; i++) { for (uint32_t i = 0; i < p->tp->meta.npieces; i++) {
if (has_bit(p->piece_field, i)) { if (has_bit(p->piece_field, i)) {
p->npieces++; p->npieces++;
dl_on_piece_ann(p, i); dl_on_piece_ann(p, i);
} }
} }
} }


@@ -432,22 +432,22 @@ peer_on_piece(struct peer *p, uint32_t index, uint32_t begin,
{ {
struct block_request *req; struct block_request *req;
BTPDQ_FOREACH(req, &p->my_reqs, p_entry) BTPDQ_FOREACH(req, &p->my_reqs, p_entry)
if ((nb_get_begin(req->blk->msg) == begin && if ((nb_get_begin(req->blk->msg) == begin &&
nb_get_index(req->blk->msg) == index && nb_get_index(req->blk->msg) == index &&
nb_get_length(req->blk->msg) == length)) nb_get_length(req->blk->msg) == length))
break; break;
if (req != NULL) { if (req != NULL) {
btpd_log(BTPD_L_MSG, "received piece(%u,%u,%u) from %p\n", btpd_log(BTPD_L_MSG, "received piece(%u,%u,%u) from %p\n",
index, begin, length, p); index, begin, length, p);
assert(p->nreqs_out > 0); assert(p->nreqs_out > 0);
p->nreqs_out--; p->nreqs_out--;
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); BTPDQ_REMOVE(&p->my_reqs, req, p_entry);
dl_on_block(p, req, index, begin, length, data); dl_on_block(p, req, index, begin, length, data);
if (p->nreqs_out == 0) if (p->nreqs_out == 0)
peer_on_no_reqs(p); peer_on_no_reqs(p);
} else } else
btpd_log(BTPD_L_MSG, "discarded piece(%u,%u,%u) from %p\n", btpd_log(BTPD_L_MSG, "discarded piece(%u,%u,%u) from %p\n",
index, begin, length, p); index, begin, length, p);
} }


void void
@@ -455,18 +455,18 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin,
uint32_t length) uint32_t length)
{ {
btpd_log(BTPD_L_MSG, "received request(%u,%u,%u) from %p\n", btpd_log(BTPD_L_MSG, "received request(%u,%u,%u) from %p\n",
index, begin, length, p); index, begin, length, p);
if ((p->flags & PF_NO_REQUESTS) == 0) { if ((p->flags & PF_NO_REQUESTS) == 0) {
off_t cbegin = index * p->tp->meta.piece_length + begin; off_t cbegin = index * p->tp->meta.piece_length + begin;
char * content = torrent_get_bytes(p->tp, cbegin, length); char * content = torrent_get_bytes(p->tp, cbegin, length);
peer_send(p, nb_create_piece(index, begin, length)); peer_send(p, nb_create_piece(index, begin, length));
peer_send(p, nb_create_torrentdata(content, length)); peer_send(p, nb_create_torrentdata(content, length));
p->npiece_msgs++; p->npiece_msgs++;
if (p->npiece_msgs >= MAXPIECEMSGS) { if (p->npiece_msgs >= MAXPIECEMSGS) {
peer_send(p, nb_create_choke()); peer_send(p, nb_create_choke());
peer_send(p, nb_create_unchoke()); peer_send(p, nb_create_unchoke());
p->flags |= PF_NO_REQUESTS; p->flags |= PF_NO_REQUESTS;
} }
} }
} }


@@ -475,18 +475,18 @@ peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin,
uint32_t length) uint32_t length)
{ {
btpd_log(BTPD_L_MSG, "received cancel(%u,%u,%u) from %p\n", btpd_log(BTPD_L_MSG, "received cancel(%u,%u,%u) from %p\n",
index, begin, length, p); index, begin, length, p);
struct nb_link *nl; struct nb_link *nl;
BTPDQ_FOREACH(nl, &p->outq, entry) BTPDQ_FOREACH(nl, &p->outq, entry)
if (nl->nb->type == NB_PIECE if (nl->nb->type == NB_PIECE
&& nb_get_begin(nl->nb) == begin && nb_get_begin(nl->nb) == begin
&& nb_get_index(nl->nb) == index && nb_get_index(nl->nb) == index
&& nb_get_length(nl->nb) == length) { && nb_get_length(nl->nb) == length) {
struct nb_link *data = BTPDQ_NEXT(nl, entry); struct nb_link *data = BTPDQ_NEXT(nl, entry);
if (peer_unsend(p, nl)) if (peer_unsend(p, nl))
peer_unsend(p, data); peer_unsend(p, data);
break; break;
} }
} }


int int
@@ -529,5 +529,5 @@ int
peer_active_up(struct peer *p) peer_active_up(struct peer *p)
{ {
return (p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT return (p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT
|| p->npiece_msgs > 0; || p->npiece_msgs > 0;
} }

+ 12
- 12
btpd/peer.h Wyświetl plik

@@ -1,16 +1,16 @@
#ifndef BTPD_PEER_H #ifndef BTPD_PEER_H
#define BTPD_PEER_H #define BTPD_PEER_H


#define PF_I_WANT 0x1 /* We want to download from the peer */ #define PF_I_WANT 0x1 /* We want to download from the peer */
#define PF_I_CHOKE 0x2 /* We choke the peer */ #define PF_I_CHOKE 0x2 /* We choke the peer */
#define PF_P_WANT 0x4 /* The peer wants to download from us */ #define PF_P_WANT 0x4 /* The peer wants to download from us */
#define PF_P_CHOKE 0x8 /* The peer is choking us */ #define PF_P_CHOKE 0x8 /* The peer is choking us */
#define PF_ON_READQ 0x10 #define PF_ON_READQ 0x10
#define PF_ON_WRITEQ 0x20 #define PF_ON_WRITEQ 0x20
#define PF_ATTACHED 0x40 #define PF_ATTACHED 0x40
#define PF_NO_REQUESTS 0x80 #define PF_NO_REQUESTS 0x80
#define PF_INCOMING 0x100 #define PF_INCOMING 0x100
#define PF_DO_UNWANT 0x200 #define PF_DO_UNWANT 0x200


#define MAXPIECEMSGS 128 #define MAXPIECEMSGS 128
#define MAXPIPEDREQUESTS 10 #define MAXPIPEDREQUESTS 10
@@ -52,8 +52,8 @@ struct peer {
struct { struct {
uint32_t msg_len; uint32_t msg_len;
uint8_t msg_num; uint8_t msg_num;
uint32_t pc_index; uint32_t pc_index;
uint32_t pc_begin; uint32_t pc_begin;
enum net_state state; enum net_state state;
size_t st_bytes; size_t st_bytes;
char *buf; char *buf;


+ 60
- 60
btpd/queue.h Wyświetl plik

@@ -1,5 +1,5 @@
/* /*
* @(#)queue.h 8.5 (Berkeley) 8/20/94 * @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD: src/sys/sys/queue.h,v 1.58.2.1 2005/01/31 23:26:57 imp Exp $ * $FreeBSD: src/sys/sys/queue.h,v 1.58.2.1 2005/01/31 23:26:57 imp Exp $
*/ */


@@ -9,86 +9,86 @@
/* /*
* Tail queue declarations. * Tail queue declarations.
*/ */
#define BTPDQ_HEAD(name, type) \ #define BTPDQ_HEAD(name, type) \
struct name { \ struct name { \
struct type *tqh_first; /* first element */ \ struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \ struct type **tqh_last; /* addr of last next element */ \
} }


#define BTPDQ_HEAD_INITIALIZER(head) \ #define BTPDQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first } { NULL, &(head).tqh_first }


#define BTPDQ_ENTRY(type) \ #define BTPDQ_ENTRY(type) \
struct { \ struct { \
struct type *tqe_next; /* next element */ \ struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \ struct type **tqe_prev; /* address of previous next element */ \
} }


#define BTPDQ_EMPTY(head) ((head)->tqh_first == NULL) #define BTPDQ_EMPTY(head) ((head)->tqh_first == NULL)


#define BTPDQ_FIRST(head) ((head)->tqh_first) #define BTPDQ_FIRST(head) ((head)->tqh_first)


#define BTPDQ_LAST(head, headname) \ #define BTPDQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last)) (*(((struct headname *)((head)->tqh_last))->tqh_last))


#define BTPDQ_NEXT(elm, field) ((elm)->field.tqe_next) #define BTPDQ_NEXT(elm, field) ((elm)->field.tqe_next)


#define BTPDQ_PREV(elm, headname, field) \ #define BTPDQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))


#define BTPDQ_FOREACH(var, head, field) \ #define BTPDQ_FOREACH(var, head, field) \
for ((var) = BTPDQ_FIRST((head)); \ for ((var) = BTPDQ_FIRST((head)); \
(var); \ (var); \
(var) = BTPDQ_NEXT((var), field)) (var) = BTPDQ_NEXT((var), field))


#define BTPDQ_INIT(head) do { \ #define BTPDQ_INIT(head) do { \
BTPDQ_FIRST((head)) = NULL; \ BTPDQ_FIRST((head)) = NULL; \
(head)->tqh_last = &BTPDQ_FIRST((head)); \ (head)->tqh_last = &BTPDQ_FIRST((head)); \
} while (0) } while (0)


#define BTPDQ_INSERT_AFTER(head, listelm, elm, field) do { \ #define BTPDQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((BTPDQ_NEXT((elm), field) = BTPDQ_NEXT((listelm), field)) != NULL)\ if ((BTPDQ_NEXT((elm), field) = BTPDQ_NEXT((listelm), field)) != NULL)\
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ BTPDQ_NEXT((elm), field)->field.tqe_prev = \
&BTPDQ_NEXT((elm), field); \ &BTPDQ_NEXT((elm), field); \
else { \ else { \
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ (head)->tqh_last = &BTPDQ_NEXT((elm), field); \
} \ } \
BTPDQ_NEXT((listelm), field) = (elm); \ BTPDQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &BTPDQ_NEXT((listelm), field); \ (elm)->field.tqe_prev = &BTPDQ_NEXT((listelm), field); \
} while (0) } while (0)


#define BTPDQ_INSERT_BEFORE(listelm, elm, field) do { \ #define BTPDQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
BTPDQ_NEXT((elm), field) = (listelm); \ BTPDQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \ *(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &BTPDQ_NEXT((elm), field); \ (listelm)->field.tqe_prev = &BTPDQ_NEXT((elm), field); \
} while (0) } while (0)


#define BTPDQ_INSERT_HEAD(head, elm, field) do { \ #define BTPDQ_INSERT_HEAD(head, elm, field) do { \
if ((BTPDQ_NEXT((elm), field) = BTPDQ_FIRST((head))) != NULL) \ if ((BTPDQ_NEXT((elm), field) = BTPDQ_FIRST((head))) != NULL) \
BTPDQ_FIRST((head))->field.tqe_prev = \ BTPDQ_FIRST((head))->field.tqe_prev = \
&BTPDQ_NEXT((elm), field); \ &BTPDQ_NEXT((elm), field); \
else \ else \
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ (head)->tqh_last = &BTPDQ_NEXT((elm), field); \
BTPDQ_FIRST((head)) = (elm); \ BTPDQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &BTPDQ_FIRST((head)); \ (elm)->field.tqe_prev = &BTPDQ_FIRST((head)); \
} while (0) } while (0)


#define BTPDQ_INSERT_TAIL(head, elm, field) do { \ #define BTPDQ_INSERT_TAIL(head, elm, field) do { \
BTPDQ_NEXT((elm), field) = NULL; \ BTPDQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \ (elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \ *(head)->tqh_last = (elm); \
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ (head)->tqh_last = &BTPDQ_NEXT((elm), field); \
} while (0) } while (0)


#define BTPDQ_REMOVE(head, elm, field) do { \ #define BTPDQ_REMOVE(head, elm, field) do { \
if ((BTPDQ_NEXT((elm), field)) != NULL) \ if ((BTPDQ_NEXT((elm), field)) != NULL) \
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ BTPDQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \ (elm)->field.tqe_prev; \
else { \ else { \
(head)->tqh_last = (elm)->field.tqe_prev; \ (head)->tqh_last = (elm)->field.tqe_prev; \
} \ } \
*(elm)->field.tqe_prev = BTPDQ_NEXT((elm), field); \ *(elm)->field.tqe_prev = BTPDQ_NEXT((elm), field); \
} while (0) } while (0)


#endif #endif

+ 50
- 50
btpd/torrent.c Wyświetl plik

@@ -40,7 +40,7 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz)


tp->relpath = strdup(file); tp->relpath = strdup(file);
if (tp->relpath == NULL) if (tp->relpath == NULL)
btpd_err("Out of memory.\n"); btpd_err("Out of memory.\n");


tp->piece_count = btpd_calloc(mi->npieces, sizeof(tp->piece_count[0])); tp->piece_count = btpd_calloc(mi->npieces, sizeof(tp->piece_count[0]));
tp->busy_field = btpd_calloc(ceil(mi->npieces / 8.0), 1); tp->busy_field = btpd_calloc(ceil(mi->npieces / 8.0), 1);
@@ -53,11 +53,11 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz)


tp->piece_field = tp->imem; tp->piece_field = tp->imem;
tp->block_field = tp->block_field =
(uint8_t *)tp->imem + (size_t)ceil(mi->npieces / 8.0); (uint8_t *)tp->imem + (size_t)ceil(mi->npieces / 8.0);


for (uint32_t i = 0; i < mi->npieces; i++) for (uint32_t i = 0; i < mi->npieces; i++)
if (has_bit(tp->piece_field, i)) if (has_bit(tp->piece_field, i))
tp->have_npieces++; tp->have_npieces++;


tp->meta = *mi; tp->meta = *mi;
free(mi); free(mi);
@@ -80,38 +80,38 @@ torrent_load2(const char *name, struct metainfo *mi)
const char *file = name; const char *file = name;


if ((error = vopen(&ifd, O_RDWR, "%s/resume", file)) != 0) { if ((error = vopen(&ifd, O_RDWR, "%s/resume", file)) != 0) {
btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n", btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n",
file, strerror(error)); file, strerror(error));
return error; return error;
} }


if (fstat(ifd, &sb) == -1) { if (fstat(ifd, &sb) == -1) {
error = errno; error = errno;
btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n", btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n",
file, strerror(error)); file, strerror(error));
close(ifd); close(ifd);
return error; return error;
} }


memsiz = memsiz =
ceil(mi->npieces / 8.0) + ceil(mi->npieces / 8.0) +
mi->npieces * ceil(mi->piece_length / (double)(1 << 17)); mi->npieces * ceil(mi->piece_length / (double)(1 << 17));


if (sb.st_size != memsiz) { if (sb.st_size != memsiz) {
btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file); btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file);
close(ifd); close(ifd);
return EINVAL; return EINVAL;
} }


mem = mmap(NULL, memsiz, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); mem = mmap(NULL, memsiz, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
if (mem == MAP_FAILED) if (mem == MAP_FAILED)
btpd_err("Error mmap'ing %s.i: %s.\n", file, strerror(errno)); btpd_err("Error mmap'ing %s.i: %s.\n", file, strerror(errno));


close(ifd); close(ifd);


if ((error = torrent_load3(file, mi, mem, memsiz) != 0)) { if ((error = torrent_load3(file, mi, mem, memsiz) != 0)) {
munmap(mem, memsiz); munmap(mem, memsiz);
return error; return error;
} }


return 0; return 0;
@@ -126,22 +126,22 @@ torrent_load(const char *name)
snprintf(file, PATH_MAX, "%s/torrent", name); snprintf(file, PATH_MAX, "%s/torrent", name);


if ((error = load_metainfo(file, -1, 0, &mi)) != 0) { if ((error = load_metainfo(file, -1, 0, &mi)) != 0) {
btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n", btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n",
file, strerror(error)); file, strerror(error));
return error; return error;
} }


if (btpd_get_torrent(mi->info_hash) != NULL) { if (btpd_get_torrent(mi->info_hash) != NULL) {
btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file);
error = EEXIST; error = EEXIST;
} }


if (error == 0) if (error == 0)
error = torrent_load2(name, mi); error = torrent_load2(name, mi);


if (error != 0) { if (error != 0) {
clear_metainfo(mi); clear_metainfo(mi);
free(mi); free(mi);
} }


return error; return error;
@@ -171,14 +171,14 @@ off_t
torrent_bytes_left(struct torrent *tp) torrent_bytes_left(struct torrent *tp)
{ {
if (tp->have_npieces == 0) if (tp->have_npieces == 0)
return tp->meta.total_length; return tp->meta.total_length;
else if (has_bit(tp->piece_field, tp->meta.npieces - 1)) { else if (has_bit(tp->piece_field, tp->meta.npieces - 1)) {
return tp->meta.total_length - return tp->meta.total_length -
((tp->have_npieces - 1) * tp->meta.piece_length + ((tp->have_npieces - 1) * tp->meta.piece_length +
tp->meta.total_length % tp->meta.piece_length); tp->meta.total_length % tp->meta.piece_length);
} else } else
return tp->meta.total_length - return tp->meta.total_length -
tp->have_npieces * tp->meta.piece_length; tp->have_npieces * tp->meta.piece_length;
} }


char * char *
@@ -187,9 +187,9 @@ torrent_get_bytes(struct torrent *tp, off_t start, size_t len)
char *buf = btpd_malloc(len); char *buf = btpd_malloc(len);
struct bt_stream_ro *bts; struct bt_stream_ro *bts;
if ((bts = bts_open_ro(&tp->meta, start, ro_fd_cb, tp)) == NULL) if ((bts = bts_open_ro(&tp->meta, start, ro_fd_cb, tp)) == NULL)
btpd_err("Out of memory.\n"); btpd_err("Out of memory.\n");
if (bts_read_ro(bts, buf, len) != 0) if (bts_read_ro(bts, buf, len) != 0)
btpd_err("Io error.\n"); btpd_err("Io error.\n");
bts_close_ro(bts); bts_close_ro(bts);
return buf; return buf;
} }
@@ -200,11 +200,11 @@ torrent_put_bytes(struct torrent *tp, const char *buf, off_t start, size_t len)
int err; int err;
struct bt_stream_wo *bts; struct bt_stream_wo *bts;
if ((bts = bts_open_wo(&tp->meta, start, wo_fd_cb, tp)) == NULL) if ((bts = bts_open_wo(&tp->meta, start, wo_fd_cb, tp)) == NULL)
btpd_err("Out of memory.\n"); btpd_err("Out of memory.\n");
if ((err = bts_write_wo(bts, buf, len)) != 0) if ((err = bts_write_wo(bts, buf, len)) != 0)
btpd_err("Io error1: %s\n", strerror(err)); btpd_err("Io error1: %s\n", strerror(err));
if ((err = bts_close_wo(bts)) != 0) if ((err = bts_close_wo(bts)) != 0)
btpd_err("Io error2: %s\n", strerror(err)); btpd_err("Io error2: %s\n", strerror(err));
} }


int int
@@ -213,11 +213,11 @@ torrent_has_peer(struct torrent *tp, const uint8_t *id)
int has = 0; int has = 0;
struct peer *p = BTPDQ_FIRST(&tp->peers); struct peer *p = BTPDQ_FIRST(&tp->peers);
while (p != NULL) { while (p != NULL) {
if (bcmp(p->id, id, 20) == 0) { if (bcmp(p->id, id, 20) == 0) {
has = 1; has = 1;
break; break;
} }
p = BTPDQ_NEXT(p, p_entry); p = BTPDQ_NEXT(p, p_entry);
} }
return has; return has;
} }
@@ -226,10 +226,10 @@ off_t
torrent_piece_size(struct torrent *tp, uint32_t index) torrent_piece_size(struct torrent *tp, uint32_t index)
{ {
if (index < tp->meta.npieces - 1) if (index < tp->meta.npieces - 1)
return tp->meta.piece_length; return tp->meta.piece_length;
else { else {
off_t allbutlast = tp->meta.piece_length * (tp->meta.npieces - 1); off_t allbutlast = tp->meta.piece_length * (tp->meta.npieces - 1);
return tp->meta.total_length - allbutlast; return tp->meta.total_length - allbutlast;
} }
} }


@@ -237,10 +237,10 @@ uint32_t
torrent_block_size(struct piece *pc, uint32_t index) torrent_block_size(struct piece *pc, uint32_t index)
{ {
if (index < pc->nblocks - 1) if (index < pc->nblocks - 1)
return PIECE_BLOCKLEN; return PIECE_BLOCKLEN;
else { else {
uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1); uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1);
return torrent_piece_size(pc->tp, pc->index) - allbutlast; return torrent_piece_size(pc->tp, pc->index) - allbutlast;
} }
} }




+ 2
- 2
btpd/torrent.h Wyświetl plik

@@ -52,7 +52,7 @@ struct torrent {
unsigned *piece_count; unsigned *piece_count;


uint64_t uploaded, downloaded; uint64_t uploaded, downloaded;
unsigned npeers; unsigned npeers;
struct peer_tq peers; struct peer_tq peers;


@@ -66,7 +66,7 @@ off_t torrent_bytes_left(struct torrent *tp);


char *torrent_get_bytes(struct torrent *tp, off_t start, size_t len); char *torrent_get_bytes(struct torrent *tp, off_t start, size_t len);
void torrent_put_bytes(struct torrent *tp, const char *buf, void torrent_put_bytes(struct torrent *tp, const char *buf,
off_t start, size_t len); off_t start, size_t len);


int torrent_load(const char *metafile); int torrent_load(const char *metafile);




+ 87
- 87
btpd/tracker_req.c Wyświetl plik

@@ -38,28 +38,28 @@ maybe_connect_to(struct torrent *tp, const char *pinfo)
size_t len; size_t len;


if (!benc_isdct(pinfo)) if (!benc_isdct(pinfo))
return; return;


if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20) if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20)
return; return;


if (bcmp(btpd_get_peer_id(), pid, 20) == 0) if (bcmp(btpd_get_peer_id(), pid, 20) == 0)
return; return;


if (torrent_has_peer(tp, pid)) if (torrent_has_peer(tp, pid))
return; return;


if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0) if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0)
goto out; goto out;


if (benc_dget_int64(pinfo, "port", &port) != 0) if (benc_dget_int64(pinfo, "port", &port) != 0)
goto out; goto out;


peer_create_out(tp, pid, ip, port); peer_create_out(tp, pid, ip, port);


out: out:
if (ip != NULL) if (ip != NULL)
free(ip); free(ip);
} }


static void static void
@@ -73,31 +73,31 @@ tracker_done(pid_t pid, void *arg)
struct torrent *tp; struct torrent *tp;


if ((tp = btpd_get_torrent(req->info_hash)) == NULL) if ((tp = btpd_get_torrent(req->info_hash)) == NULL)
goto out; goto out;


if (benc_validate(req->res->buf, req->res->buf_off) != 0 if (benc_validate(req->res->buf, req->res->buf_off) != 0
|| !benc_isdct(req->res->buf)) { || !benc_isdct(req->res->buf)) {
if (req->res->buf_off != 0) { if (req->res->buf_off != 0) {
fwrite(req->res->buf, 1, req->res->buf_off, (stdout)); fwrite(req->res->buf, 1, req->res->buf_off, (stdout));
putchar('\n'); putchar('\n');
} }
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); failed = 1;
failed = 1; goto out;
goto out;
} }


if ((benc_dget_strz(req->res->buf, "failure reason", &buf, NULL)) == 0) { if ((benc_dget_strz(req->res->buf, "failure reason", &buf, NULL)) == 0) {
btpd_log(BTPD_L_ERROR, "Tracker failure: %s.\n", buf); btpd_log(BTPD_L_ERROR, "Tracker failure: %s.\n", buf);
free(buf); free(buf);
failed = 1; failed = 1;
goto out; goto out;
} }


if ((benc_dget_uint32(req->res->buf, "interval", &interval)) != 0) { if ((benc_dget_uint32(req->res->buf, "interval", &interval)) != 0) {
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
failed = 1; failed = 1;
goto out; goto out;
} }


//tp->tracker_time = btpd_seconds + interval; //tp->tracker_time = btpd_seconds + interval;
@@ -106,34 +106,34 @@ tracker_done(pid_t pid, void *arg)
size_t length; size_t length;


if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) {
for (peers = benc_first(peers); for (peers = benc_first(peers);
peers != NULL && net_npeers < net_max_peers; peers != NULL && net_npeers < net_max_peers;
peers = benc_next(peers)) peers = benc_next(peers))
maybe_connect_to(tp, peers); maybe_connect_to(tp, peers);
} }


if (error == EINVAL) { if (error == EINVAL) {
error = benc_dget_str(req->res->buf, "peers", &peers, &length); error = benc_dget_str(req->res->buf, "peers", &peers, &length);
if (error == 0 && length % 6 == 0) { if (error == 0 && length % 6 == 0) {
size_t i; size_t i;
for (i = 0; i < length && net_npeers < net_max_peers; i += 6) for (i = 0; i < length && net_npeers < net_max_peers; i += 6)
peer_create_out_compact(tp, peers + i); peer_create_out_compact(tp, peers + i);
} }
} }


if (error != 0) { if (error != 0) {
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
failed = 1; failed = 1;
goto out; goto out;
} }


out: out:
if (failed) { if (failed) {
if (req->tr_event == TR_STARTED) { if (req->tr_event == TR_STARTED) {
btpd_log(BTPD_L_BTPD, btpd_log(BTPD_L_BTPD,
"Start request failed for %s.\n", tp->relpath); "Start request failed for %s.\n", tp->relpath);
torrent_unload(tp); torrent_unload(tp);
} else } else
;//tp->tracker_time = btpd_seconds + 10; ;//tp->tracker_time = btpd_seconds + 10;
} }
munmap(req->res, REQ_SIZE); munmap(req->res, REQ_SIZE);
@@ -145,16 +145,16 @@ event2str(enum tr_event ev)
{ {
switch (ev) { switch (ev) {
case TR_STARTED: case TR_STARTED:
return "started"; return "started";
case TR_STOPPED: case TR_STOPPED:
return "stopped"; return "stopped";
case TR_COMPLETED: case TR_COMPLETED:
return "completed"; return "completed";
case TR_EMPTY: case TR_EMPTY:
return ""; return "";
default: default:
btpd_err("Bad tracker event %d.\n", ev); btpd_err("Bad tracker event %d.\n", ev);
return ""; // Shut GCC up! return ""; // Shut GCC up!
} }
} }


@@ -173,28 +173,28 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url)
qc = (strchr(tp->meta.announce, '?') == NULL) ? '?' : '&'; qc = (strchr(tp->meta.announce, '?') == NULL) ? '?' : '&';


for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]); snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]);


for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]); snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);


left = torrent_bytes_left(tp); left = torrent_bytes_left(tp);


i = asprintf(url, "%s%cinfo_hash=%s" i = asprintf(url, "%s%cinfo_hash=%s"
"&peer_id=%s" "&peer_id=%s"
"&port=%d" "&port=%d"
"&uploaded=%" PRIu64 "&uploaded=%" PRIu64
"&downloaded=%" PRIu64 "&downloaded=%" PRIu64
"&left=%" PRIu64 "&left=%" PRIu64
"&compact=1" "&compact=1"
"%s%s", "%s%s",
tp->meta.announce, qc, e_hash, e_id, net_port, tp->meta.announce, qc, e_hash, e_id, net_port,
tp->uploaded, tp->downloaded, left, tp->uploaded, tp->downloaded, left,
req->tr_event == TR_EMPTY ? "" : "&event=", req->tr_event == TR_EMPTY ? "" : "&event=",
event); event);


if (i < 0) if (i < 0)
return ENOMEM; return ENOMEM;
return 0; return 0;
} }


@@ -204,12 +204,12 @@ http_cb(void *ptr, size_t size, size_t nmemb, void *stream)
struct tracker_req *req = (struct tracker_req *)stream; struct tracker_req *req = (struct tracker_req *)stream;
size_t nbytes = size * nmemb; size_t nbytes = size * nmemb;
if (nbytes <= req->res->buf_len - req->res->buf_off) { if (nbytes <= req->res->buf_len - req->res->buf_off) {
memcpy(req->res->buf + req->res->buf_off, ptr, nbytes); memcpy(req->res->buf + req->res->buf_off, ptr, nbytes);
req->res->buf_off += nbytes; req->res->buf_off += nbytes;
return nbytes; return nbytes;
} }
else else
return 0; return 0;
} }


static void static void
@@ -222,31 +222,31 @@ http_helper(struct tracker_req *req, struct torrent *tp)
int err; int err;


if (create_url(req, tp, &url) != 0) if (create_url(req, tp, &url) != 0)
goto memory_error; goto memory_error;


if (curl_global_init(0) != 0) if (curl_global_init(0) != 0)
goto libcurl_error; goto libcurl_error;
if ((handle = curl_easy_init()) == NULL) if ((handle = curl_easy_init()) == NULL)
goto libcurl_error; goto libcurl_error;


err = curl_easy_setopt(handle, CURLOPT_URL, url); err = curl_easy_setopt(handle, CURLOPT_URL, url);
if (err == 0) if (err == 0)
err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION); err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION);
if (err == 0) if (err == 0)
err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb);
if (err == 0) if (err == 0)
err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, req); err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, req);
if (err == 0) if (err == 0)
err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, cerror); err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, cerror);
if (err != 0) { if (err != 0) {
strncpy(cerror, curl_easy_strerror(err), CURL_ERROR_SIZE - 1); strncpy(cerror, curl_easy_strerror(err), CURL_ERROR_SIZE - 1);
goto handle_error; goto handle_error;
} }


req->res->buf_off = 0; req->res->buf_off = 0;
if (curl_easy_perform(handle) != 0) if (curl_easy_perform(handle) != 0)
goto handle_error; goto handle_error;


#if 0 #if 0
curl_easy_cleanup(handle); curl_easy_cleanup(handle);
@@ -263,12 +263,12 @@ libcurl_error:
strncpy(cerror, "Generic libcurl error", CURL_ERROR_SIZE - 1); strncpy(cerror, "Generic libcurl error", CURL_ERROR_SIZE - 1);
goto handle_error; goto handle_error;


handle_error: handle_error:
req->res->buf_off = req->res->buf_off =
snprintf(req->res->buf, req->res->buf_len, snprintf(req->res->buf, req->res->buf_len,
"d%d:%s%d:%se", (int)strlen(fr), fr, (int)strlen(cerror), cerror); "d%d:%s%d:%se", (int)strlen(fr), fr, (int)strlen(cerror), cerror);
if (req->res->buf_off >= req->res->buf_len) if (req->res->buf_off >= req->res->buf_len)
req->res->buf_off = 0; req->res->buf_off = 0;


exit(1); exit(1);
} }
@@ -281,7 +281,7 @@ tracker_req(struct torrent *tp, enum tr_event tr_event)


btpd_log(BTPD_L_TRACKER, btpd_log(BTPD_L_TRACKER,
"request for %s, event: %s.\n", "request for %s, event: %s.\n",
tp->relpath, event2str(tr_event)); tp->relpath, event2str(tr_event));


req = (struct tracker_req *)btpd_calloc(1, sizeof(*req)); req = (struct tracker_req *)btpd_calloc(1, sizeof(*req));


@@ -289,7 +289,7 @@ tracker_req(struct torrent *tp, enum tr_event tr_event)
MAP_ANON | MAP_SHARED, -1, 0); MAP_ANON | MAP_SHARED, -1, 0);


if (req->res == MAP_FAILED) if (req->res == MAP_FAILED)
btpd_err("Failed mmap: %s\n", strerror(errno)); btpd_err("Failed mmap: %s\n", strerror(errno));


req->res->buf_len = REQ_SIZE - sizeof(*req->res); req->res->buf_len = REQ_SIZE - sizeof(*req->res);
req->res->buf_off = 0; req->res->buf_off = 0;
@@ -302,12 +302,12 @@ tracker_req(struct torrent *tp, enum tr_event tr_event)


pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
btpd_err("Couldn't fork (%s).\n", strerror(errno)); btpd_err("Couldn't fork (%s).\n", strerror(errno));
} else if (pid == 0) { // Child } else if (pid == 0) { // Child
int nfiles = getdtablesize(); int nfiles = getdtablesize();
for (int i = 0; i < nfiles; i++) for (int i = 0; i < nfiles; i++)
close(i); close(i);
http_helper(req, tp); http_helper(req, tp);
} else } else
btpd_add_child(pid, tracker_done, req); btpd_add_child(pid, tracker_done, req);
} }

+ 6
- 6
btpd/upload.c Wyświetl plik

@@ -11,7 +11,7 @@ choke_do(void)
struct peer *p; struct peer *p;
BTPDQ_FOREACH(p, &m_peerq, ul_entry) BTPDQ_FOREACH(p, &m_peerq, ul_entry)
if (p->flags & PF_I_CHOKE) if (p->flags & PF_I_CHOKE)
peer_unchoke(p); peer_unchoke(p);
} }


static void static void
@@ -36,7 +36,7 @@ ul_on_lost_peer(struct peer *p)
BTPDQ_REMOVE(&m_peerq, p, ul_entry); BTPDQ_REMOVE(&m_peerq, p, ul_entry);
m_npeers--; m_npeers--;
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT)
choke_do(); choke_do();
} }


void void
@@ -44,8 +44,8 @@ ul_on_lost_torrent(struct torrent *tp)
{ {
struct peer *p; struct peer *p;
BTPDQ_FOREACH(p, &tp->peers, p_entry) { BTPDQ_FOREACH(p, &tp->peers, p_entry) {
BTPDQ_REMOVE(&m_peerq, p, ul_entry); BTPDQ_REMOVE(&m_peerq, p, ul_entry);
m_npeers--; m_npeers--;
} }
choke_do(); choke_do();
} }
@@ -54,14 +54,14 @@ void
ul_on_interest(struct peer *p) ul_on_interest(struct peer *p)
{ {
if ((p->flags & PF_I_CHOKE) == 0) if ((p->flags & PF_I_CHOKE) == 0)
choke_do(); choke_do();
} }


void void
ul_on_uninterest(struct peer *p) ul_on_uninterest(struct peer *p)
{ {
if ((p->flags & PF_I_CHOKE) == 0) if ((p->flags & PF_I_CHOKE) == 0)
choke_do(); choke_do();
} }


void void


+ 18
- 18
btpd/util.c Wyświetl plik

@@ -8,7 +8,7 @@ btpd_malloc(size_t size)
{ {
void *a; void *a;
if ((a = malloc(size)) == NULL) if ((a = malloc(size)) == NULL)
btpd_err("Failed to allocate %d bytes.\n", (int)size); btpd_err("Failed to allocate %d bytes.\n", (int)size);
return a; return a;
} }


@@ -17,7 +17,7 @@ btpd_calloc(size_t nmemb, size_t size)
{ {
void *a; void *a;
if ((a = calloc(nmemb, size)) == NULL) if ((a = calloc(nmemb, size)) == NULL)
btpd_err("Failed to allocate %d bytes.\n", (int)(nmemb * size)); btpd_err("Failed to allocate %d bytes.\n", (int)(nmemb * size));
return a; return a;
} }


@@ -25,17 +25,17 @@ static const char *
logtype_str(uint32_t type) logtype_str(uint32_t type)
{ {
if (type & BTPD_L_BTPD) if (type & BTPD_L_BTPD)
return "btpd"; return "btpd";
else if (type & BTPD_L_ERROR) else if (type & BTPD_L_ERROR)
return "error"; return "error";
else if (type & BTPD_L_CONN) else if (type & BTPD_L_CONN)
return "conn"; return "conn";
else if (type & BTPD_L_TRACKER) else if (type & BTPD_L_TRACKER)
return "tracker"; return "tracker";
else if (type & BTPD_L_MSG) else if (type & BTPD_L_MSG)
return "msg"; return "msg";
else else
return ""; return "";
} }


void void
@@ -44,11 +44,11 @@ btpd_err(const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
if (BTPD_L_ERROR & btpd_logmask) { if (BTPD_L_ERROR & btpd_logmask) {
char tbuf[20]; char tbuf[20];
time_t tp = time(NULL); time_t tp = time(NULL);
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); strftime(tbuf, 20, "%b %e %T", localtime(&tp));
printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR)); printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR));
vprintf(fmt, ap); vprintf(fmt, ap);
} }
va_end(ap); va_end(ap);
exit(1); exit(1);
@@ -60,11 +60,11 @@ btpd_log(uint32_t type, const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
if (type & btpd_logmask) { if (type & btpd_logmask) {
char tbuf[20]; char tbuf[20];
time_t tp = time(NULL); time_t tp = time(NULL);
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); strftime(tbuf, 20, "%b %e %T", localtime(&tp));
printf("%s %s: ", tbuf, logtype_str(type)); printf("%s %s: ", tbuf, logtype_str(type));
vprintf(fmt, ap); vprintf(fmt, ap);
} }
va_end(ap); va_end(ap);
} }

+ 125
- 125
cli/btcli.c Wyświetl plik

@@ -24,16 +24,16 @@ static void
usage() usage()
{ {
printf("Usage: btcli command [options] [files]\n" printf("Usage: btcli command [options] [files]\n"
"Commands:\n" "Commands:\n"
"add <file_1> ... [file_n]\n" "add <file_1> ... [file_n]\n"
"\tAdd the given torrents to btpd.\n" "\tAdd the given torrents to btpd.\n"
"\n" "\n"
"del <file_1> ... [file_n]\n" "del <file_1> ... [file_n]\n"
"\tRemove the given torrents from btpd.\n" "\tRemove the given torrents from btpd.\n"
"\n" "\n"
"die\n" "die\n"
"\tShut down btpd.\n" "\tShut down btpd.\n"
"\n" "\n"
"list\n" "list\n"
"\tList active torrents.\n" "\tList active torrents.\n"
"\n" "\n"
@@ -47,13 +47,13 @@ usage()
"-w n\n" "-w n\n"
"\tRepeat every n seconds.\n" "\tRepeat every n seconds.\n"
"\n" "\n"
"Common options:\n" "Common options:\n"
"--ipc key\n" "--ipc key\n"
"\tTalk to the btpd started with the same key.\n" "\tTalk to the btpd started with the same key.\n"
"\n" "\n"
"--help\n" "--help\n"
"\tShow this help.\n" "\tShow this help.\n"
"\n"); "\n");
exit(1); exit(1);
} }


@@ -62,12 +62,12 @@ handle_error(int error)
{ {
switch (error) { switch (error) {
case 0: case 0:
break; break;
case ENOENT: case ENOENT:
case ECONNREFUSED: case ECONNREFUSED:
errx(1, "Couldn't connect. Check that btpd is running."); errx(1, "Couldn't connect. Check that btpd is running.");
default: default:
errx(1, "%s", strerror(error)); errx(1, "%s", strerror(error));
} }
} }


@@ -76,11 +76,11 @@ do_ipc_open(char *ipctok, struct ipc **ipc)
{ {
switch (ipc_open(ipctok, ipc)) { switch (ipc_open(ipctok, ipc)) {
case 0: case 0:
break; break;
case EINVAL: case EINVAL:
errx(1, "--ipc argument only takes letters and digits."); errx(1, "--ipc argument only takes letters and digits.");
case ENAMETOOLONG: case ENAMETOOLONG:
errx(1, "--ipc argument is too long."); errx(1, "--ipc argument is too long.");
} }
} }


@@ -96,10 +96,10 @@ hash_cb(uint32_t index, uint8_t *hash, void *arg)
{ {
struct cb *cb = arg; struct cb *cb = arg;
if (hash != NULL) if (hash != NULL)
if (bcmp(hash, cb->meta->piece_hash[index], SHA_DIGEST_LENGTH) == 0) { if (bcmp(hash, cb->meta->piece_hash[index], SHA_DIGEST_LENGTH) == 0) {
set_bit(cb->piece_field, index); set_bit(cb->piece_field, index);
cb->have++; cb->have++;
} }
printf("\rTested: %5.1f%%", 100.0 * (index + 1) / cb->meta->npieces); printf("\rTested: %5.1f%%", 100.0 * (index + 1) / cb->meta->npieces);
fflush(stdout); fflush(stdout);
} }
@@ -120,7 +120,7 @@ gen_ifile(char *path)
size_t field_len; size_t field_len;


if ((errno = load_metainfo(path, -1, 1, &mi)) != 0) if ((errno = load_metainfo(path, -1, 1, &mi)) != 0)
err(1, "load_metainfo: %s", path); err(1, "load_metainfo: %s", path);


field_len = ceil(mi->npieces / 8.0); field_len = ceil(mi->npieces / 8.0);
cb.path = path; cb.path = path;
@@ -129,24 +129,24 @@ gen_ifile(char *path)
cb.meta = mi; cb.meta = mi;


if (cb.piece_field == NULL) if (cb.piece_field == NULL)
errx(1, "Out of memory.\n"); errx(1, "Out of memory.\n");


if ((errno = bts_hashes(mi, fd_cb, hash_cb, &cb)) != 0) if ((errno = bts_hashes(mi, fd_cb, hash_cb, &cb)) != 0)
err(1, "bts_hashes"); err(1, "bts_hashes");
printf("\nHave: %5.1f%%\n", 100.0 * cb.have / cb.meta->npieces); printf("\nHave: %5.1f%%\n", 100.0 * cb.have / cb.meta->npieces);


if ((errno = vopen(&fd, O_WRONLY|O_CREAT, "%s.i", path)) != 0) if ((errno = vopen(&fd, O_WRONLY|O_CREAT, "%s.i", path)) != 0)
err(1, "opening %s.i", path); err(1, "opening %s.i", path);


if (ftruncate(fd, field_len + mi->npieces * if (ftruncate(fd, field_len + mi->npieces *
(off_t)ceil(mi->piece_length / (double)(1 << 17))) < 0) (off_t)ceil(mi->piece_length / (double)(1 << 17))) < 0)
err(1, "ftruncate: %s", path); err(1, "ftruncate: %s", path);


if (write(fd, cb.piece_field, field_len) != field_len) if (write(fd, cb.piece_field, field_len) != field_len)
err(1, "write %s.i", path); err(1, "write %s.i", path);


if (close(fd) < 0) if (close(fd) < 0)
err(1, "close %s.i", path); err(1, "close %s.i", path);


clear_metainfo(mi); clear_metainfo(mi);
free(mi); free(mi);
@@ -173,45 +173,45 @@ cmd_add(int argc, char **argv)
int ch; int ch;
char *ipctok = NULL; char *ipctok = NULL;
while ((ch = getopt_long(argc, argv, "", add_opts, NULL)) != -1) { while ((ch = getopt_long(argc, argv, "", add_opts, NULL)) != -1) {
switch(ch) { switch(ch) {
case 1: case 1:
ipctok = optarg; ipctok = optarg;
break; break;
default: default:
usage(); usage();
} }
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;


if (argc < 1) if (argc < 1)
usage(); usage();


for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
int64_t code; int64_t code;
char *res; char *res;
int fd; int fd;
char *path; char *path;
errno = vopen(&fd, O_RDONLY, "%s.i", argv[i]); errno = vopen(&fd, O_RDONLY, "%s.i", argv[i]);
if (errno == ENOENT) { if (errno == ENOENT) {
printf("Testing %s for content.\n", argv[i]); printf("Testing %s for content.\n", argv[i]);
gen_ifile(argv[i]); gen_ifile(argv[i]);
} else if (errno != 0) } else if (errno != 0)
err(1, "open %s.i", argv[i]); err(1, "open %s.i", argv[i]);
else else
close(fd); close(fd);
if ((errno = canon_path(argv[i], &path)) != 0)
if ((errno = canon_path(argv[i], &path)) != 0) err(1, "canon_path");
err(1, "canon_path"); do_add(ipctok, &path, 1, &res);
do_add(ipctok, &path, 1, &res); free(path);
free(path); benc_dget_int64(benc_first(res), "code", &code);
benc_dget_int64(benc_first(res), "code", &code); if (code == EEXIST)
if (code == EEXIST) printf("btpd already had %s.\n", argv[i]);
printf("btpd already had %s.\n", argv[i]); else if (code != 0) {
else if (code != 0) { printf("btpd indicates error: %s for %s.\n",
printf("btpd indicates error: %s for %s.\n", strerror(code), argv[i]);
strerror(code), argv[i]); }
}
free(res); free(res);
} }
} }
@@ -237,45 +237,45 @@ cmd_del(int argc, char **argv)
int ch; int ch;
char *ipctok = NULL; char *ipctok = NULL;
while ((ch = getopt_long(argc, argv, "", del_opts, NULL)) != -1) { while ((ch = getopt_long(argc, argv, "", del_opts, NULL)) != -1) {
switch(ch) { switch(ch) {
case 1: case 1:
ipctok = optarg; ipctok = optarg;
break; break;
default: default:
usage(); usage();
} }
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;


if (argc < 1) if (argc < 1)
usage(); usage();


uint8_t hashes[argc][20]; uint8_t hashes[argc][20];
char *res; char *res;
const char *d; const char *d;


for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
struct metainfo *mi; struct metainfo *mi;
if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0) if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0)
err(1, "load_metainfo: %s", argv[i]); err(1, "load_metainfo: %s", argv[i]);
bcopy(mi->info_hash, hashes[i], 20); bcopy(mi->info_hash, hashes[i], 20);
clear_metainfo(mi); clear_metainfo(mi);
free(mi); free(mi);
} }
do_del(ipctok, hashes, argc, &res); do_del(ipctok, hashes, argc, &res);
d = benc_first(res); d = benc_first(res);
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
int64_t code; int64_t code;
benc_dget_int64(d, "code", &code); benc_dget_int64(d, "code", &code);
if (code == ENOENT) if (code == ENOENT)
printf("btpd didn't have %s.\n", argv[i]); printf("btpd didn't have %s.\n", argv[i]);
else if (code != 0) { else if (code != 0) {
printf("btpd indicates error: %s for %s.\n", printf("btpd indicates error: %s for %s.\n",
strerror(code), argv[i]); strerror(code), argv[i]);
} }
d = benc_next(d); d = benc_next(d);
} }
free(res); free(res);
} }
@@ -302,13 +302,13 @@ cmd_die(int argc, char **argv)
char *ipctok = NULL; char *ipctok = NULL;


while ((ch = getopt_long(argc, argv, "", die_opts, NULL)) != -1) { while ((ch = getopt_long(argc, argv, "", die_opts, NULL)) != -1) {
switch (ch) { switch (ch) {
case 1: case 1:
ipctok = optarg; ipctok = optarg;
break; break;
default: default:
usage(); usage();
} }
} }
do_die(ipctok); do_die(ipctok);
} }
@@ -420,14 +420,14 @@ grok_stat(char *ipctok, int iflag, int wait,
again: again:
do_stat(ipctok, &res); do_stat(ipctok, &res);
gettimeofday(&tv_cur, NULL); gettimeofday(&tv_cur, NULL);
if (old == NULL) if (old == NULL)
ds = wait; ds = wait;
else { else {
struct timeval delta; struct timeval delta;
timersub(&tv_old, &tv_cur, &delta); timersub(&tv_old, &tv_cur, &delta);
ds = delta.tv_sec + delta.tv_usec / 1000000.0; ds = delta.tv_sec + delta.tv_usec / 1000000.0;
if (ds < 0) if (ds < 0)
ds = wait; ds = wait;
} }
tv_old = tv_cur; tv_old = tv_cur;
cur = parse_tors(res, hashes, nhashes); cur = parse_tors(res, hashes, nhashes);
@@ -484,7 +484,7 @@ cmd_stat(int argc, char **argv)
int iflag = 0; int iflag = 0;


while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) { while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) {
switch (ch) { switch (ch) {
case 'i': case 'i':
iflag = 1; iflag = 1;
break; break;
@@ -493,12 +493,12 @@ cmd_stat(int argc, char **argv)
if (wait <= 0) if (wait <= 0)
errx(1, "-w argument must be an integer > 0."); errx(1, "-w argument must be an integer > 0.");
break; break;
case 1: case 1:
ipctok = optarg; ipctok = optarg;
break; break;
default: default:
usage(); usage();
} }
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@@ -531,13 +531,13 @@ cmd_list(int argc, char **argv)
char *ipctok = NULL; char *ipctok = NULL;


while ((ch = getopt_long(argc, argv, "", list_opts, NULL)) != -1) { while ((ch = getopt_long(argc, argv, "", list_opts, NULL)) != -1) {
switch (ch) { switch (ch) {
case 1: case 1:
ipctok = optarg; ipctok = optarg;
break; break;
default: default:
usage(); usage();
} }
} }
char *res; char *res;
const char *p; const char *p;
@@ -572,18 +572,18 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
if (argc < 2) if (argc < 2)
usage(); usage();
int found = 0; int found = 0;
for (int i = 0; !found && i < ncmds; i++) { for (int i = 0; !found && i < ncmds; i++) {
if (strcmp(argv[1], cmd_table[i].name) == 0) { if (strcmp(argv[1], cmd_table[i].name) == 0) {
found = 1; found = 1;
cmd_table[i].fun(argc - 1, argv + 1); cmd_table[i].fun(argc - 1, argv + 1);
} }
} }


if (!found) if (!found)
usage(); usage();


return 0; return 0;
} }

+ 10
- 10
cli/btinfo.c Wyświetl plik

@@ -27,26 +27,26 @@ main(int argc, char **argv)
int ch; int ch;


while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1)
usage(); usage();


argc -= optind; argc -= optind;
argv += optind; argv += optind;


if (argc < 1) if (argc < 1)
usage(); usage();


while (argc > 0) { while (argc > 0) {
struct metainfo *mi; struct metainfo *mi;


if ((errno = load_metainfo(*argv, -1, 1, &mi)) != 0) if ((errno = load_metainfo(*argv, -1, 1, &mi)) != 0)
err(1, "load_metainfo: %s", *argv); err(1, "load_metainfo: %s", *argv);


print_metainfo(mi); print_metainfo(mi);
clear_metainfo(mi); clear_metainfo(mi);
free(mi); free(mi);


argc--; argc--;
argv++; argv++;
} }


return 0; return 0;


+ 36
- 36
cli/btpd_if.c Wyświetl plik

@@ -19,21 +19,21 @@ ipc_open(const char *key, struct ipc **out)
struct ipc *res; struct ipc *res;


if (key == NULL) if (key == NULL)
key = "default"; key = "default";
keylen = strlen(key); keylen = strlen(key);
for (int i = 0; i < keylen; i++) for (int i = 0; i < keylen; i++)
if (!isalnum(key[i])) if (!isalnum(key[i]))
return EINVAL; return EINVAL;


res = malloc(sizeof(*res)); res = malloc(sizeof(*res));
if (res == NULL) if (res == NULL)
return ENOMEM; return ENOMEM;


plen = sizeof(res->addr.sun_path); plen = sizeof(res->addr.sun_path);
if (snprintf(res->addr.sun_path, plen, if (snprintf(res->addr.sun_path, plen,
"/tmp/btpd_%u_%s", geteuid(), key) >= plen) { "/tmp/btpd_%u_%s", geteuid(), key) >= plen) {
free(res); free(res);
return ENAMETOOLONG; return ENAMETOOLONG;
} }
res->addr.sun_family = AF_UNIX; res->addr.sun_family = AF_UNIX;
*out = res; *out = res;
@@ -55,13 +55,13 @@ ipc_connect(struct ipc *ipc, FILE **out)
int error; int error;


if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
return errno; return errno;


if (connect(sd, (struct sockaddr *)&ipc->addr, sizeof(ipc->addr)) == -1) if (connect(sd, (struct sockaddr *)&ipc->addr, sizeof(ipc->addr)) == -1)
goto error; goto error;


if ((fp = fdopen(sd, "r+")) == NULL) if ((fp = fdopen(sd, "r+")) == NULL)
goto error; goto error;


*out = fp; *out = fp;
return 0; return 0;
@@ -78,23 +78,23 @@ ipc_response(FILE *fp, char **out, uint32_t *len)
char *buf; char *buf;


if (fread(&size, sizeof(size), 1, fp) != 1) { if (fread(&size, sizeof(size), 1, fp) != 1) {
if (ferror(fp)) if (ferror(fp))
return errno; return errno;
else else
return ECONNRESET; return ECONNRESET;
} }


if (size == 0) if (size == 0)
return EINVAL; return EINVAL;


if ((buf = malloc(size)) == NULL) if ((buf = malloc(size)) == NULL)
return ENOMEM; return ENOMEM;


if (fread(buf, 1, size, fp) != size) { if (fread(buf, 1, size, fp) != size) {
if (ferror(fp)) if (ferror(fp))
return errno; return errno;
else else
return ECONNRESET; return ECONNRESET;
} }


*out = buf; *out = buf;
@@ -104,25 +104,25 @@ ipc_response(FILE *fp, char **out, uint32_t *len)


static int static int
ipc_req_res(struct ipc *ipc, ipc_req_res(struct ipc *ipc,
const char *req, uint32_t qlen, const char *req, uint32_t qlen,
char **res, uint32_t *rlen) char **res, uint32_t *rlen)
{ {
FILE *fp; FILE *fp;
int error; int error;


if ((error = ipc_connect(ipc, &fp)) != 0) if ((error = ipc_connect(ipc, &fp)) != 0)
return error; return error;


if (fwrite(&qlen, sizeof(qlen), 1, fp) != 1) if (fwrite(&qlen, sizeof(qlen), 1, fp) != 1)
goto error; goto error;
if (fwrite(req, 1, qlen, fp) != qlen) if (fwrite(req, 1, qlen, fp) != qlen)
goto error; goto error;
if (fflush(fp) != 0) if (fflush(fp) != 0)
goto error; goto error;
if ((errno = ipc_response(fp, res, rlen)) != 0) if ((errno = ipc_response(fp, res, rlen)) != 0)
goto error; goto error;
if ((errno = benc_validate(*res, *rlen)) != 0) if ((errno = benc_validate(*res, *rlen)) != 0)
goto error; goto error;


fclose(fp); fclose(fp);
return 0; return 0;
@@ -142,14 +142,14 @@ btpd_die(struct ipc *ipc)
uint32_t rsiz; uint32_t rsiz;


if ((error = ipc_req_res(ipc, shutdown, size, &response, &rsiz)) != 0) if ((error = ipc_req_res(ipc, shutdown, size, &response, &rsiz)) != 0)
return error; return error;


error = benc_validate(response, rsiz); error = benc_validate(response, rsiz);


if (error == 0) { if (error == 0) {
int64_t tmp; int64_t tmp;
benc_dget_int64(response, "code", &tmp); benc_dget_int64(response, "code", &tmp);
error = tmp; error = tmp;
} }


free(response); free(response);
@@ -172,12 +172,12 @@ btpd_add(struct ipc *ipc, char **paths, unsigned npaths, char **out)
buf_write(&iob, paths[i], plen); buf_write(&iob, paths[i], plen);
} }
buf_print(&iob, "e"); buf_print(&iob, "e");
error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen); error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen);
free(iob.buf); free(iob.buf);
if (error == 0) if (error == 0)
*out = res; *out = res;
return error; return error;
} }


@@ -210,11 +210,11 @@ btpd_del(struct ipc *ipc, uint8_t (*hash)[20], unsigned nhashes, char **out)
buf_write(&iob, hash[i], 20); buf_write(&iob, hash[i], 20);
} }
buf_write(&iob, "e", 1); buf_write(&iob, "e", 1);
error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen); error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen);
free(iob.buf); free(iob.buf);
if (error != 0) if (error != 0)
return error; return error;


*out = res; *out = res;
return 0; return 0;


+ 1
- 1
cli/btpd_if.h Wyświetl plik

@@ -14,7 +14,7 @@ int ipc_close(struct ipc *ipc);


int btpd_add(struct ipc *ipc, char **path, unsigned npaths, char **out); int btpd_add(struct ipc *ipc, char **path, unsigned npaths, char **out);
int btpd_del(struct ipc *ipc, uint8_t (*hash)[20], int btpd_del(struct ipc *ipc, uint8_t (*hash)[20],
unsigned nhashes, char **out); unsigned nhashes, char **out);
int btpd_die(struct ipc *ipc); int btpd_die(struct ipc *ipc);
int btpd_stat(struct ipc *ipc, char **out); int btpd_stat(struct ipc *ipc, char **out);




+ 105
- 105
misc/benc.c Wyświetl plik

@@ -17,7 +17,7 @@ benc_validate(const char *p, size_t len)
const char *end = p + len - 1; const char *end = p + len - 1;


if (len <= 0) if (len <= 0)
return EINVAL; return EINVAL;


return benc_validate_aux(p, end) == end ? 0 : EINVAL; return benc_validate_aux(p, end) == end ? 0 : EINVAL;
} }
@@ -28,51 +28,51 @@ benc_validate_aux(const char *p, const char *end)
size_t d = 0; size_t d = 0;
switch (*p) { switch (*p) {
case 'd': case 'd':
d = 1; d = 1;
case 'l': case 'l':
for (p++; p <= end && *p != 'e'; p++) { for (p++; p <= end && *p != 'e'; p++) {
if (d != 0) { if (d != 0) {
if (d % 2 == 1 && !isdigit(*p)) if (d % 2 == 1 && !isdigit(*p))
return NULL; return NULL;
else else
d++; d++;
} }
if ((p = benc_validate_aux(p, end)) == NULL) if ((p = benc_validate_aux(p, end)) == NULL)
return NULL; return NULL;
} }
if (p > end || (d != 0 && d % 2 != 1)) if (p > end || (d != 0 && d % 2 != 1))
return NULL; return NULL;
break; break;
case 'i': case 'i':
p++; p++;
if (p > end) if (p > end)
return NULL; return NULL;
if (*p == '-') if (*p == '-')
p++; p++;
if (p > end || !isdigit(*p)) if (p > end || !isdigit(*p))
return NULL; return NULL;
p++; p++;
while (p <= end && isdigit(*p)) while (p <= end && isdigit(*p))
p++; p++;
if (p > end || *p != 'e') if (p > end || *p != 'e')
return NULL; return NULL;
break; break;
default: default:
if (isdigit(*p)) { if (isdigit(*p)) {
size_t len = 0; size_t len = 0;
while (p <= end && isdigit(*p)) { while (p <= end && isdigit(*p)) {
len *= 10; len *= 10;
len += *p - '0'; len += *p - '0';
p++; p++;
} }
if (p <= end && *p == ':' && p + len <= end) if (p <= end && *p == ':' && p + len <= end)
p += len; p += len;
else else
return NULL; return NULL;
} }
else else
return NULL; return NULL;
break; break;
} }
return p; return p;
} }
@@ -86,21 +86,21 @@ benc_length(const char *p)
switch (*p) { switch (*p) {
case 'd': case 'd':
case 'l': case 'l':
blen = 2; // [l|d]...e blen = 2; // [l|d]...e
next = benc_first(p); next = benc_first(p);
while (*next != 'e') { while (*next != 'e') {
size_t len = benc_length(next); size_t len = benc_length(next);
blen += len; blen += len;
next += len; next += len;
} }
return blen; return blen;
case 'i': case 'i':
for (next = p + 1; *next != 'e'; next++) for (next = p + 1; *next != 'e'; next++)
; ;
return next - p + 1; return next - p + 1;
default: default:
assert(benc_str(p, &next, &blen, NULL) == 0); assert(benc_str(p, &next, &blen, NULL) == 0);
return next - p + blen; return next - p + blen;
} }
} }


@@ -109,7 +109,7 @@ benc_nelems(const char *p)
{ {
size_t nelems = 0; size_t nelems = 0;
for (p = benc_first(p); p != NULL; p = benc_next(p)) for (p = benc_first(p); p != NULL; p = benc_next(p))
nelems++; nelems++;
return nelems; return nelems;
} }


@@ -135,9 +135,9 @@ benc_str(const char *p, const char **out, size_t *len, const char**next)
blen = *p - '0'; blen = *p - '0';
p++; p++;
while (isdigit(*p)) { while (isdigit(*p)) {
blen *= 10; blen *= 10;
blen += *p - '0'; blen += *p - '0';
p++; p++;
} }
assert(*p == ':'); assert(*p == ':');
benc_safeset(len, blen); benc_safeset(len, blen);
@@ -154,12 +154,12 @@ benc_strz(const char *p, char **out, size_t *len, const char **next)
const char *bstr; const char *bstr;


if ((err = benc_str(p, &bstr, &blen, next)) == 0) { if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
if ((*out = malloc(blen + 1)) != NULL) { if ((*out = malloc(blen + 1)) != NULL) {
memcpy(*out, bstr, blen); memcpy(*out, bstr, blen);
(*out)[blen] = '\0'; (*out)[blen] = '\0';
benc_safeset(len, blen); benc_safeset(len, blen);
} else } else
err = ENOMEM; err = ENOMEM;
} }
return err; return err;
} }
@@ -172,11 +172,11 @@ benc_stra(const char *p, char **out, size_t *len, const char **next)
const char *bstr; const char *bstr;


if ((err = benc_str(p, &bstr, &blen, next)) == 0) { if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
if ((*out = malloc(blen)) != NULL) { if ((*out = malloc(blen)) != NULL) {
memcpy(*out, bstr, blen); memcpy(*out, bstr, blen);
benc_safeset(len, blen); benc_safeset(len, blen);
} else } else
err = ENOMEM; err = ENOMEM;
} }
return err; return err;
} }
@@ -190,16 +190,16 @@ benc_int64(const char *p, int64_t *out, const char **next)
assert(*p == 'i'); assert(*p == 'i');
p++; p++;
if (*p == '-') { if (*p == '-') {
sign = -1; sign = -1;
p++; p++;
} }
assert(isdigit(*p)); assert(isdigit(*p));
res += sign * (*p - '0'); res += sign * (*p - '0');
p++; p++;
while (isdigit(*p)) { while (isdigit(*p)) {
res *= sign * 10; res *= sign * 10;
res += sign * (*p - '0'); res += sign * (*p - '0');
p++; p++;
} }
assert(*p == 'e'); assert(*p == 'e');
benc_safeset(out, res); benc_safeset(out, res);
@@ -214,10 +214,10 @@ benc_uint32(const char *p, uint32_t *out, const char **next)
int err; int err;
int64_t res; int64_t res;
if ((err = benc_int64(p, &res, next)) == 0) { if ((err = benc_int64(p, &res, next)) == 0) {
if (res >= 0 && res <= 0xffffffffUL) if (res >= 0 && res <= 0xffffffffUL)
*out = (uint32_t)res; *out = (uint32_t)res;
else else
err = EINVAL; err = EINVAL;
} }
return err; return err;
} }
@@ -235,17 +235,17 @@ benc_dget_any(const char *p, const char *key, const char **val)


p = benc_first(p); p = benc_first(p);
while (p != NULL) { while (p != NULL) {
if ((res = benc_str(p, &bstr, &blen, &p)) != 0) if ((res = benc_str(p, &bstr, &blen, &p)) != 0)
return res; return res;
res = strncmp(bstr, key, blen);
res = strncmp(bstr, key, blen); if (res == 0 && len == blen) {
if (res == 0 && len == blen) { *val = p;
*val = p; return 0;
return 0; } else if (res <= 0) {
} else if (res <= 0) { p = benc_next(p);
p = benc_next(p); } else
} else return ENOENT;
return ENOENT;
} }
return ENOENT; return ENOENT;
} }
@@ -255,8 +255,8 @@ benc_dget_lst(const char *p, const char *key, const char **val)
{ {
int err; int err;
if ((err = benc_dget_any(p, key, val)) == 0) if ((err = benc_dget_any(p, key, val)) == 0)
if (!benc_islst(*val)) if (!benc_islst(*val))
err = EINVAL; err = EINVAL;
return err; return err;
} }


@@ -265,8 +265,8 @@ benc_dget_dct(const char *p, const char *key, const char **val)
{ {
int err; int err;
if ((err = benc_dget_any(p, key, val)) == 0) if ((err = benc_dget_any(p, key, val)) == 0)
if (!benc_isdct(*val)) if (!benc_isdct(*val))
err = EINVAL; err = EINVAL;
return err; return err;
} }


@@ -276,8 +276,8 @@ benc_dget_str(const char *p, const char *key, const char **val, size_t *len)
int err; int err;
const char *sp; const char *sp;
if ((err = benc_dget_any(p, key, &sp)) == 0) if ((err = benc_dget_any(p, key, &sp)) == 0)
err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL; err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL;
return err; return err;
} }


int int
@@ -286,8 +286,8 @@ benc_dget_stra(const char *p, const char *key, char **val, size_t *len)
int err; int err;
const char *sp; const char *sp;
if ((err = benc_dget_any(p, key, &sp)) == 0) if ((err = benc_dget_any(p, key, &sp)) == 0)
err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL; err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL;
return err; return err;
} }


int int
@@ -296,8 +296,8 @@ benc_dget_strz(const char *p, const char *key, char **val, size_t *len)
int err; int err;
const char *sp; const char *sp;
if ((err = benc_dget_any(p, key, &sp)) == 0) if ((err = benc_dget_any(p, key, &sp)) == 0)
err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL; err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL;
return err; return err;
} }


int int
@@ -306,9 +306,9 @@ benc_dget_int64(const char *p, const char *key, int64_t *val)
int err; int err;
const char *ip; const char *ip;
if ((err = benc_dget_any(p, key, &ip)) == 0) if ((err = benc_dget_any(p, key, &ip)) == 0)
err = benc_isint(ip) ? benc_int64(ip, val, NULL) : EINVAL; err = benc_isint(ip) ? benc_int64(ip, val, NULL) : EINVAL;
return err; return err;
} }


int int
benc_dget_uint32(const char *p, const char *key, uint32_t *val) benc_dget_uint32(const char *p, const char *key, uint32_t *val)
@@ -316,9 +316,9 @@ benc_dget_uint32(const char *p, const char *key, uint32_t *val)
int err; int err;
const char *ip; const char *ip;
if ((err = benc_dget_any(p, key, &ip)) == 0) if ((err = benc_dget_any(p, key, &ip)) == 0)
err = benc_isint(ip) ? benc_uint32(ip, val, NULL) : EINVAL; err = benc_isint(ip) ? benc_uint32(ip, val, NULL) : EINVAL;
return err; return err;
} }


int int
benc_islst(const char *p) benc_islst(const char *p)


+ 1
- 1
misc/benc.h Wyświetl plik

@@ -21,7 +21,7 @@ int benc_dget_any(const char *p, const char *key, const char **val);
int benc_dget_lst(const char *p, const char *key, const char **val); int benc_dget_lst(const char *p, const char *key, const char **val);
int benc_dget_dct(const char *p, const char *key, const char **val); int benc_dget_dct(const char *p, const char *key, const char **val);
int benc_dget_str(const char *p, const char *key, int benc_dget_str(const char *p, const char *key,
const char **val, size_t *len); const char **val, size_t *len);
int benc_dget_stra(const char *p, const char *key, char **val, size_t *len); int benc_dget_stra(const char *p, const char *key, char **val, size_t *len);
int benc_dget_strz(const char *p, const char *key, char **val, size_t *len); int benc_dget_strz(const char *p, const char *key, char **val, size_t *len);
int benc_dget_int64(const char *p, const char *key, int64_t *val); int benc_dget_int64(const char *p, const char *key, int64_t *val);


+ 100
- 100
misc/metainfo.c Wyświetl plik

@@ -44,7 +44,7 @@ print_metainfo(struct metainfo *tp)


printf("Info hash: "); printf("Info hash: ");
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
printf("%.2x", tp->info_hash[i]); printf("%.2x", tp->info_hash[i]);
printf("\n"); printf("\n");
printf("Tracker URL: %s\n", tp->announce); printf("Tracker URL: %s\n", tp->announce);
printf("Piece length: %" PRId64 "\n", (int64_t)tp->piece_length); printf("Piece length: %" PRId64 "\n", (int64_t)tp->piece_length);
@@ -53,8 +53,8 @@ print_metainfo(struct metainfo *tp)
printf("Advisory name: %s\n", tp->name); printf("Advisory name: %s\n", tp->name);
printf("Files:\n"); printf("Files:\n");
for (i = 0; i < tp->nfiles; i++) { for (i = 0; i < tp->nfiles; i++) {
printf("%s (%" PRId64 ")\n", printf("%s (%" PRId64 ")\n",
tp->files[i].path, (int64_t)tp->files[i].length); tp->files[i].path, (int64_t)tp->files[i].length);
} }
printf("Total length: %" PRId64 "\n\n", (int64_t)tp->total_length); printf("Total length: %" PRId64 "\n\n", (int64_t)tp->total_length);
} }
@@ -63,13 +63,13 @@ static int
check_path(const char *path, size_t len) check_path(const char *path, size_t len)
{ {
if (len == 0) if (len == 0)
return 0; return 0;
else if (len == 1 && path[0] == '.') else if (len == 1 && path[0] == '.')
return 0; return 0;
else if (len == 2 && path[0] == '.' && path[1] == '.') else if (len == 2 && path[0] == '.' && path[1] == '.')
return 0; return 0;
else if (memchr(path, '/', len) != NULL) else if (memchr(path, '/', len) != NULL)
return 0; return 0;
return 1; return 1;
} }


@@ -81,27 +81,27 @@ fill_fileinfo(const char *fdct, struct fileinfo *tfp)
const char *plst, *iter, *str; const char *plst, *iter, *str;


if ((err = benc_dget_off(fdct, "length", &tfp->length)) != 0) if ((err = benc_dget_off(fdct, "length", &tfp->length)) != 0)
return err; return err;


if ((err = benc_dget_lst(fdct, "path", &plst)) != 0) if ((err = benc_dget_lst(fdct, "path", &plst)) != 0)
return err; return err;


npath = plen = 0; npath = plen = 0;
iter = benc_first(plst); iter = benc_first(plst);
while (iter != NULL) { while (iter != NULL) {
if (!benc_isstr(iter)) if (!benc_isstr(iter))
return EINVAL; return EINVAL;
benc_str(iter, &str, &len, &iter); benc_str(iter, &str, &len, &iter);
if (!check_path(str, len)) if (!check_path(str, len))
return EINVAL; return EINVAL;
npath++; npath++;
plen += len; plen += len;
} }
if (npath == 0) if (npath == 0)
return EINVAL; return EINVAL;


if ((tfp->path = malloc(plen + (npath - 1) + 1)) == NULL) if ((tfp->path = malloc(plen + (npath - 1) + 1)) == NULL)
return ENOMEM; return ENOMEM;


iter = benc_first(plst); iter = benc_first(plst);
benc_str(iter, &str, &len, &iter); benc_str(iter, &str, &len, &iter);
@@ -109,11 +109,11 @@ fill_fileinfo(const char *fdct, struct fileinfo *tfp)
plen = len; plen = len;
npath--; npath--;
while (npath > 0) { while (npath > 0) {
tfp->path[plen++] = '/'; tfp->path[plen++] = '/';
benc_str(iter, &str, &len, &iter); benc_str(iter, &str, &len, &iter);
memcpy(tfp->path + plen, str, len); memcpy(tfp->path + plen, str, len);
plen += len; plen += len;
npath--; npath--;
} }
tfp->path[plen] = '\0'; tfp->path[plen] = '\0';
return 0; return 0;
@@ -124,18 +124,18 @@ clear_metainfo(struct metainfo *mip)
{ {
int i; int i;
if (mip->piece_hash != NULL) if (mip->piece_hash != NULL)
free(mip->piece_hash); free(mip->piece_hash);
if (mip->announce != NULL) if (mip->announce != NULL)
free(mip->announce); free(mip->announce);
if (mip->files != NULL) { if (mip->files != NULL) {
for (i = 0; i < mip->nfiles; i++) { for (i = 0; i < mip->nfiles; i++) {
if (mip->files[i].path != NULL) if (mip->files[i].path != NULL)
free(mip->files[i].path); free(mip->files[i].path);
} }
free(mip->files); free(mip->files);
} }
if (mip->name != NULL) if (mip->name != NULL)
free(mip->name); free(mip->name);
} }


int int
@@ -147,91 +147,91 @@ fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes)
const char *hash_addr; const char *hash_addr;


if (!benc_isdct(bep)) if (!benc_isdct(bep))
return EINVAL; return EINVAL;


if ((err = benc_dget_strz(bep, "announce", &tp->announce, NULL)) != 0) if ((err = benc_dget_strz(bep, "announce", &tp->announce, NULL)) != 0)
goto out; goto out;


if ((err = benc_dget_dct(bep, "info", &bep)) != 0) if ((err = benc_dget_dct(bep, "info", &bep)) != 0)
goto out; goto out;


SHA1(bep, benc_length(bep), tp->info_hash); SHA1(bep, benc_length(bep), tp->info_hash);


if ((err = benc_dget_off(bep, "piece length", &tp->piece_length)) != 0) if ((err = benc_dget_off(bep, "piece length", &tp->piece_length)) != 0)
goto out; goto out;


if ((err = benc_dget_str(bep, "pieces", &hash_addr, &len)) != 0) if ((err = benc_dget_str(bep, "pieces", &hash_addr, &len)) != 0)
goto out; goto out;


if (len % 20 != 0) { if (len % 20 != 0) {
err = EINVAL; err = EINVAL;
goto out; goto out;
} }
tp->npieces = len / 20; tp->npieces = len / 20;


tp->pieces_off = hash_addr - base_addr; tp->pieces_off = hash_addr - base_addr;
if (mem_hashes) { if (mem_hashes) {
if ((tp->piece_hash = malloc(len)) == NULL) { if ((tp->piece_hash = malloc(len)) == NULL) {
err = ENOMEM; err = ENOMEM;
goto out; goto out;
} }
bcopy(hash_addr, tp->piece_hash, len); bcopy(hash_addr, tp->piece_hash, len);
} }


if ((err = benc_dget_strz(bep, "name", &tp->name, NULL)) != 0) if ((err = benc_dget_strz(bep, "name", &tp->name, NULL)) != 0)
goto out; goto out;


err = benc_dget_off(bep, "length", &tp->total_length); err = benc_dget_off(bep, "length", &tp->total_length);
if (err == 0) { if (err == 0) {
tp->nfiles = 1; tp->nfiles = 1;
tp->files = calloc(1, sizeof(struct fileinfo)); tp->files = calloc(1, sizeof(struct fileinfo));
if (tp->files != NULL) { if (tp->files != NULL) {
tp->files[0].length = tp->total_length; tp->files[0].length = tp->total_length;
tp->files[0].path = strdup(tp->name); tp->files[0].path = strdup(tp->name);
if (tp->files[0].path == NULL) { if (tp->files[0].path == NULL) {
err = ENOMEM; err = ENOMEM;
goto out; goto out;
} }
} else { } else {
err = ENOMEM; err = ENOMEM;
goto out; goto out;
} }
} }
else if (err == ENOENT) { else if (err == ENOENT) {
int i; int i;
const char *flst, *fdct; const char *flst, *fdct;
if ((err = benc_dget_lst(bep, "files", &flst)) != 0)
if ((err = benc_dget_lst(bep, "files", &flst)) != 0) goto out;
goto out; tp->nfiles = benc_nelems(flst);
if (tp->nfiles < 1) {
tp->nfiles = benc_nelems(flst); err = EINVAL;
if (tp->nfiles < 1) { goto out;
err = EINVAL; }
goto out; tp->files = calloc(tp->nfiles, sizeof(struct fileinfo));
} tp->total_length = 0;
tp->files = calloc(tp->nfiles, sizeof(struct fileinfo)); i = 0;
for (fdct = benc_first(flst); fdct != NULL; fdct = benc_next(fdct)) {
tp->total_length = 0; if (!benc_isdct(fdct)) {
i = 0; err = EINVAL;
for (fdct = benc_first(flst); fdct != NULL; fdct = benc_next(fdct)) { goto out;
if (!benc_isdct(fdct)) { }
err = EINVAL; if ((err = fill_fileinfo(fdct, &tp->files[i])) != 0)
goto out; goto out;
} tp->total_length += tp->files[i].length;
i++;
if ((err = fill_fileinfo(fdct, &tp->files[i])) != 0) }
goto out;
tp->total_length += tp->files[i].length;
i++;
}
} }
else else
goto out; goto out;
out: out:
if (err != 0) if (err != 0)
clear_metainfo(tp); clear_metainfo(tp);


return err; return err;
} }
@@ -244,31 +244,31 @@ load_metainfo(const char *path, off_t size, int mem_hashes,
int fd, err = 0; int fd, err = 0;


if ((fd = open(path, O_RDONLY)) == -1) if ((fd = open(path, O_RDONLY)) == -1)
return errno; return errno;


if (size <= 0) { if (size <= 0) {
struct stat sb; struct stat sb;
if (fstat(fd, &sb) == -1) { if (fstat(fd, &sb) == -1) {
close(fd); close(fd);
return errno; return errno;
} else } else
size = sb.st_size; size = sb.st_size;
} }


if ((buf = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) if ((buf = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
err = errno; err = errno;
close(fd); close(fd);


if (err == 0) if (err == 0)
err = benc_validate(buf, size); err = benc_validate(buf, size);


if (err == 0) if (err == 0)
if ((*res = calloc(1, sizeof(**res))) == NULL) if ((*res = calloc(1, sizeof(**res))) == NULL)
err = ENOMEM; err = ENOMEM;


if (err == 0) if (err == 0)
if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0) if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0)
free(*res); free(*res);


munmap(buf, size); munmap(buf, size);
return err; return err;


+ 80
- 80
misc/stream.c Wyświetl plik

@@ -16,7 +16,7 @@ bts_open_ro(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg)
{ {
struct bt_stream_ro *bts = malloc(sizeof(*bts)); struct bt_stream_ro *bts = malloc(sizeof(*bts));
if (bts == NULL) if (bts == NULL)
return NULL; return NULL;


bts->meta = meta; bts->meta = meta;
bts->fd_cb = fd_cb; bts->fd_cb = fd_cb;
@@ -37,16 +37,16 @@ bts_seek_ro(struct bt_stream_ro *bts, off_t off)
assert(off >= 0 && off <= bts->meta->total_length); assert(off >= 0 && off <= bts->meta->total_length);


if (bts->fd != -1) { if (bts->fd != -1) {
close(bts->fd); close(bts->fd);
bts->fd = -1; bts->fd = -1;
} }


bts->t_off = off; bts->t_off = off;
bts->index = 0; bts->index = 0;


while (off >= files[bts->index].length) { while (off >= files[bts->index].length) {
off -= files[bts->index].length; off -= files[bts->index].length;
bts->index++; bts->index++;
} }


bts->f_off = off; bts->f_off = off;
@@ -63,31 +63,31 @@ bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len)


boff = 0; boff = 0;
while (boff < len) { while (boff < len) {
if (bts->fd == -1) { if (bts->fd == -1) {
int err = int err =
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
if (err != 0) if (err != 0)
return err; return err;
if (bts->f_off != 0) if (bts->f_off != 0)
lseek(bts->fd, bts->f_off, SEEK_SET); lseek(bts->fd, bts->f_off, SEEK_SET);
} }
wantread = min(len - boff, files[bts->index].length - bts->f_off);
wantread = min(len - boff, files[bts->index].length - bts->f_off); didread = read(bts->fd, buf + boff, wantread);
didread = read(bts->fd, buf + boff, wantread); if (didread == -1)
if (didread == -1) return errno;
return errno; boff += didread;
bts->f_off += didread;
boff += didread; bts->t_off += didread;
bts->f_off += didread; if (bts->f_off == files[bts->index].length) {
bts->t_off += didread; close(bts->fd);
if (bts->f_off == files[bts->index].length) { bts->fd = -1;
close(bts->fd); bts->f_off = 0;
bts->fd = -1; bts->index++;
bts->f_off = 0; }
bts->index++; if (didread != wantread)
} return ENOENT;
if (didread != wantread)
return ENOENT;
} }
return 0; return 0;
} }
@@ -96,7 +96,7 @@ void
bts_close_ro(struct bt_stream_ro *bts) bts_close_ro(struct bt_stream_ro *bts)
{ {
if (bts->fd != -1) if (bts->fd != -1)
close(bts->fd); close(bts->fd);
free(bts); free(bts);
} }


@@ -112,11 +112,11 @@ bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash)


SHA1_Init(&ctx); SHA1_Init(&ctx);
while (length > 0) { while (length > 0) {
wantread = min(length, SHAFILEBUF); wantread = min(length, SHAFILEBUF);
if ((err = bts_read_ro(bts, buf, wantread)) != 0) if ((err = bts_read_ro(bts, buf, wantread)) != 0)
break; break;
length -= wantread; length -= wantread;
SHA1_Update(&ctx, buf, wantread); SHA1_Update(&ctx, buf, wantread);
} }
SHA1_Final(hash, &ctx); SHA1_Final(hash, &ctx);
return err; return err;
@@ -136,23 +136,23 @@ bts_hashes(struct metainfo *meta,
off_t llen = meta->total_length % plen; off_t llen = meta->total_length % plen;


if ((bts = bts_open_ro(meta, 0, fd_cb, arg)) == NULL) if ((bts = bts_open_ro(meta, 0, fd_cb, arg)) == NULL)
return ENOMEM; return ENOMEM;
for (piece = 0; piece < meta->npieces; piece++) {
for (piece = 0; piece < meta->npieces; piece++) {
if (piece < meta->npieces - 1) if (piece < meta->npieces - 1)
err = bts_sha(bts, plen, hash); err = bts_sha(bts, plen, hash);
else else
err = bts_sha(bts, llen, hash); err = bts_sha(bts, llen, hash);
if (err == 0)
if (err == 0) cb(piece, hash, arg);
cb(piece, hash, arg); else if (err == ENOENT) {
else if (err == ENOENT) { cb(piece, NULL, arg);
cb(piece, NULL, arg); if (piece < meta->npieces - 1)
if (piece < meta->npieces - 1) bts_seek_ro(bts, (piece + 1) * plen);
bts_seek_ro(bts, (piece + 1) * plen); err = 0;
err = 0; } else
} else break;
break;
} }
bts_close_ro(bts); bts_close_ro(bts);
return err; return err;
@@ -163,7 +163,7 @@ bts_open_wo(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg)
{ {
struct bt_stream_wo *bts = malloc(sizeof(*bts)); struct bt_stream_wo *bts = malloc(sizeof(*bts));
if (bts == NULL) if (bts == NULL)
return NULL; return NULL;


bts->meta = meta; bts->meta = meta;
bts->fd_cb = fd_cb; bts->fd_cb = fd_cb;
@@ -187,24 +187,24 @@ bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len)


boff = 0; boff = 0;
while (boff < len) { while (boff < len) {
if (bts->fd == -1) { if (bts->fd == -1) {
int err = int err =
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
if (err != 0) if (err != 0)
return err; return err;
if (bts->f_off != 0) if (bts->f_off != 0)
lseek(bts->fd, bts->f_off, SEEK_SET); lseek(bts->fd, bts->f_off, SEEK_SET);
} }
wantwrite = min(len - boff, files[bts->index].length - bts->f_off);
wantwrite = min(len - boff, files[bts->index].length - bts->f_off); didwrite = write(bts->fd, buf + boff, wantwrite);
didwrite = write(bts->fd, buf + boff, wantwrite); if (didwrite == -1)
if (didwrite == -1) return errno;
return errno; boff += didwrite;
bts->f_off += didwrite;
boff += didwrite; bts->t_off += didwrite;
bts->f_off += didwrite; if (bts->f_off == files[bts->index].length) {
bts->t_off += didwrite;
if (bts->f_off == files[bts->index].length) {
if (fsync(bts->fd) == -1) { if (fsync(bts->fd) == -1) {
int err = errno; int err = errno;
close(bts->fd); close(bts->fd);
@@ -212,10 +212,10 @@ bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len)
} }
if (close(bts->fd) == -1) if (close(bts->fd) == -1)
return errno; return errno;
bts->fd = -1; bts->fd = -1;
bts->f_off = 0; bts->f_off = 0;
bts->index++; bts->index++;
} }
} }
return 0; return 0;
} }
@@ -225,11 +225,11 @@ bts_close_wo(struct bt_stream_wo *bts)
{ {
int err = 0; int err = 0;
if (bts->fd != -1) { if (bts->fd != -1) {
if (fsync(bts->fd) == -1) { if (fsync(bts->fd) == -1) {
err = errno; err = errno;
close(bts->fd); close(bts->fd);
} else if (close(bts->fd) == -1) } else if (close(bts->fd) == -1)
err = errno; err = errno;
} }
free(bts); free(bts);
return err; return err;


+ 1
- 1
misc/stream.h Wyświetl plik

@@ -31,6 +31,6 @@ int bts_close_wo(struct bt_stream_wo *bts);


int bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash); int bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash);
int bts_hashes(struct metainfo *, F_fdcb fd_cb, int bts_hashes(struct metainfo *, F_fdcb fd_cb,
void (*cb)(uint32_t, uint8_t *, void *), void *arg); void (*cb)(uint32_t, uint8_t *, void *), void *arg);


#endif #endif

+ 35
- 35
misc/subr.c Wyświetl plik

@@ -34,9 +34,9 @@ set_nonblocking(int fd)
{ {
int oflags; int oflags;
if ((oflags = fcntl(fd, F_GETFL, 0)) == -1) if ((oflags = fcntl(fd, F_GETFL, 0)) == -1)
return errno; return errno;
if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
return errno; return errno;
return 0; return 0;
} }


@@ -45,9 +45,9 @@ set_blocking(int fd)
{ {
int oflags; int oflags;
if ((oflags = fcntl(fd, F_GETFL, 0)) == -1) if ((oflags = fcntl(fd, F_GETFL, 0)) == -1)
return errno; return errno;
if (fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) == -1)
return errno; return errno;
return 0; return 0;
} }


@@ -58,16 +58,16 @@ mkdirs(char *path)
char *spos = strchr(path + 1, '/'); // Must ignore the root char *spos = strchr(path + 1, '/'); // Must ignore the root


while (spos != NULL) { while (spos != NULL) {
*spos = '\0'; *spos = '\0';
err = mkdir(path, 0777); err = mkdir(path, 0777);
*spos = '/'; *spos = '/';
if (err != 0 && errno != EEXIST) {
if (err != 0 && errno != EEXIST) { err = errno;
err = errno; break;
break; }
} spos = strchr(spos + 1, '/');
spos = strchr(spos + 1, '/');
} }
return err; return err;
} }
@@ -81,8 +81,8 @@ vopen(int *res, int flags, const char *fmt, ...)


va_start(ap, fmt); va_start(ap, fmt);
if (vsnprintf(path, PATH_MAX, fmt, ap) >= PATH_MAX) { if (vsnprintf(path, PATH_MAX, fmt, ap) >= PATH_MAX) {
va_end(ap); va_end(ap);
return ENAMETOOLONG; return ENAMETOOLONG;
} }
va_end(ap); va_end(ap);


@@ -90,18 +90,18 @@ vopen(int *res, int flags, const char *fmt, ...)
again: again:
fd = open(path, flags, 0666); fd = open(path, flags, 0666);
if (fd < 0 && errno == ENOENT && (flags & O_CREAT) != 0 && !didmkdirs) { if (fd < 0 && errno == ENOENT && (flags & O_CREAT) != 0 && !didmkdirs) {
if (mkdirs(path) == 0) { if (mkdirs(path) == 0) {
didmkdirs = 1; didmkdirs = 1;
goto again; goto again;
} else } else
return errno; return errno;
} }


if (fd >= 0) { if (fd >= 0) {
*res = fd; *res = fd;
return 0; return 0;
} else } else
return errno; return errno;
} }


int int
@@ -110,22 +110,22 @@ canon_path(const char *path, char **res)
char rp[PATH_MAX]; char rp[PATH_MAX];


if (realpath(path, rp) == NULL) if (realpath(path, rp) == NULL)
return errno; return errno;
#if 0 #if 0
// This could be necessary on solaris. // This could be necessary on solaris.
if (rp[0] != '/') { if (rp[0] != '/') {
char wd[MAXPATHLEN]; char wd[MAXPATHLEN];
if (getcwd(wd, MAXPATHLEN) == NULL) if (getcwd(wd, MAXPATHLEN) == NULL)
return errno; return errno;
if (strlcat(wd, "/", MAXPATHLEN) >= MAXPATHLEN) if (strlcat(wd, "/", MAXPATHLEN) >= MAXPATHLEN)
return ENAMETOOLONG; return ENAMETOOLONG;
if (strlcat(wd, rp, MAXPATHLEN) >= MAXPATHLEN) if (strlcat(wd, rp, MAXPATHLEN) >= MAXPATHLEN)
return ENAMETOOLONG; return ENAMETOOLONG;
strcpy(rp, wd); strcpy(rp, wd);
} }
#endif #endif
if ((*res = strdup(rp)) == NULL) if ((*res = strdup(rp)) == NULL)
return ENOMEM; return ENOMEM;


return 0; return 0;
} }
@@ -136,6 +136,6 @@ round_to_page(size_t size)
size_t psize = getpagesize(); size_t psize = getpagesize();
size_t rem = size % psize; size_t rem = size % psize;
if (rem != 0) if (rem != 0)
size += psize - rem; size += psize - rem;
return size; return size;
} }

||||||
x
 
000:0
Ładowanie…
Anuluj
Zapisz