Tabs have been converted to spaces and trailing whitespace have been removed. I have fixed my emacs settings now :Pmaster
@@ -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(); | ||||
@@ -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); | ||||
@@ -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); | ||||
} | } |
@@ -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); | ||||
} | } | ||||
} | } |
@@ -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; | ||||
} | } | ||||
} | } |
@@ -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); | ||||
@@ -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); | ||||
@@ -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 }) | ||||
@@ -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 | ||||
@@ -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; | ||||
@@ -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; | ||||
} | } |
@@ -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; | ||||
@@ -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 |
@@ -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; | ||||
} | } | ||||
} | } | ||||
@@ -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); | ||||
@@ -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); | ||||
} | } |
@@ -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 | ||||
@@ -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); | ||||
} | } |
@@ -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; | ||||
} | } |
@@ -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; | ||||
@@ -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; | ||||
@@ -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); | ||||
@@ -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) | ||||
@@ -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); | ||||
@@ -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; | ||||
@@ -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; | ||||
@@ -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 |
@@ -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; | ||||
} | } |