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; | |||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | |||
if (WIFEXITED(status) || WIFSIGNALED(status)) { | |||
struct child *kid = BTPDQ_FIRST(&m_kids); | |||
while (kid != NULL && kid->pid != pid) | |||
kid = BTPDQ_NEXT(kid, entry); | |||
assert(kid != NULL); | |||
BTPDQ_REMOVE(&m_kids, kid, entry); | |||
kid->cb(kid->pid, kid->arg); | |||
free(kid); | |||
} | |||
if (WIFEXITED(status) || WIFSIGNALED(status)) { | |||
struct child *kid = BTPDQ_FIRST(&m_kids); | |||
while (kid != NULL && kid->pid != pid) | |||
kid = BTPDQ_NEXT(kid, entry); | |||
assert(kid != NULL); | |||
BTPDQ_REMOVE(&m_kids, kid, entry); | |||
kid->cb(kid->pid, kid->arg); | |||
free(kid); | |||
} | |||
} | |||
} | |||
@@ -102,7 +102,7 @@ btpd_add_torrent(struct torrent *tp) | |||
m_ntorrents++; | |||
} | |||
void | |||
void | |||
btpd_del_torrent(struct torrent *tp) | |||
{ | |||
BTPDQ_REMOVE(&m_torrents, tp, entry); | |||
@@ -126,7 +126,7 @@ btpd_get_torrent(const uint8_t *hash) | |||
{ | |||
struct torrent *tp = BTPDQ_FIRST(&m_torrents); | |||
while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0) | |||
tp = BTPDQ_NEXT(tp, entry); | |||
tp = BTPDQ_NEXT(tp, entry); | |||
return tp; | |||
} | |||
@@ -145,7 +145,7 @@ btpd_init(void) | |||
m_peer_id[sizeof(BTPD_VERSION) - 1] = '|'; | |||
srandom(time(NULL)); | |||
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(); | |||
ipc_init(); | |||
@@ -30,13 +30,13 @@ | |||
#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) | |||
#define BTPD_L_ALL 0xffffffff | |||
#define BTPD_L_ERROR 0x00000001 | |||
#define BTPD_L_TRACKER 0x00000002 | |||
#define BTPD_L_CONN 0x00000004 | |||
#define BTPD_L_MSG 0x00000008 | |||
#define BTPD_L_BTPD 0x00000010 | |||
#define BTPD_L_POL 0x00000020 | |||
#define BTPD_L_ALL 0xffffffff | |||
#define BTPD_L_ERROR 0x00000001 | |||
#define BTPD_L_TRACKER 0x00000002 | |||
#define BTPD_L_CONN 0x00000004 | |||
#define BTPD_L_MSG 0x00000008 | |||
#define BTPD_L_BTPD 0x00000010 | |||
#define BTPD_L_POL 0x00000020 | |||
void btpd_init(void); | |||
@@ -25,7 +25,7 @@ static void | |||
errdie(int error) | |||
{ | |||
if (error != 0) | |||
btpd_err("io_buf: %s.\n", strerror(error)); | |||
btpd_err("io_buf: %s.\n", strerror(error)); | |||
} | |||
static void | |||
@@ -34,7 +34,7 @@ cmd_stat(int argc, const char *args, FILE *fp) | |||
struct torrent *tp; | |||
struct io_buffer iob; | |||
errdie(buf_init(&iob, (1 << 14))); | |||
errdie(buf_swrite(&iob, "d")); | |||
errdie(buf_print(&iob, "6:npeersi%ue", net_npeers)); | |||
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++) | |||
if (tp->piece_count[i] > 0) | |||
seen_npieces++; | |||
errdie(buf_print(&iob, "d4:downi%" PRIu64 "e", tp->downloaded)); | |||
errdie(buf_swrite(&iob, "4:hash20:")); | |||
errdie(buf_write(&iob, tp->meta.info_hash, 20)); | |||
errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces)); | |||
errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers)); | |||
errdie(buf_print(&iob, "d4:downi%" PRIu64 "e", tp->downloaded)); | |||
errdie(buf_swrite(&iob, "4:hash20:")); | |||
errdie(buf_write(&iob, tp->meta.info_hash, 20)); | |||
errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces)); | |||
errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers)); | |||
errdie(buf_print(&iob, "7:npiecesi%ue", tp->meta.npieces)); | |||
errdie(buf_print(&iob, "4:path%d:%s", | |||
(int)strlen(tp->relpath), tp->relpath)); | |||
errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces)); | |||
errdie(buf_print(&iob, "2:upi%" PRIu64 "ee", tp->uploaded)); | |||
(int)strlen(tp->relpath), tp->relpath)); | |||
errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces)); | |||
errdie(buf_print(&iob, "2:upi%" PRIu64 "ee", tp->uploaded)); | |||
} | |||
errdie(buf_swrite(&iob, "ee")); | |||
@@ -71,33 +71,33 @@ cmd_add(int argc, const char *args, FILE *fp) | |||
errdie(buf_write(&iob, "l", 1)); | |||
while (args != NULL) { | |||
size_t plen; | |||
char path[PATH_MAX]; | |||
const char *pathp; | |||
if (!benc_isstr(args)) { | |||
free(iob.buf); | |||
return; | |||
} | |||
benc_str(args, &pathp, &plen, &args); | |||
if (plen >= PATH_MAX) { | |||
errdie(buf_print(&iob, "d4:codei%dee", ENAMETOOLONG)); | |||
continue; | |||
} | |||
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))); | |||
size_t plen; | |||
char path[PATH_MAX]; | |||
const char *pathp; | |||
if (!benc_isstr(args)) { | |||
free(iob.buf); | |||
return; | |||
} | |||
benc_str(args, &pathp, &plen, &args); | |||
if (plen >= PATH_MAX) { | |||
errdie(buf_print(&iob, "d4:codei%dee", ENAMETOOLONG)); | |||
continue; | |||
} | |||
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)); | |||
uint32_t len = iob.buf_off; | |||
fwrite(&len, sizeof(len), 1, fp); | |||
fwrite(iob.buf, 1, iob.buf_off, fp); | |||
free(iob.buf); | |||
free(iob.buf); | |||
} | |||
static void | |||
@@ -105,7 +105,7 @@ cmd_del(int argc, const char *args, FILE *fp) | |||
{ | |||
struct io_buffer iob; | |||
errdie(buf_init(&iob, (1 << 10))); | |||
errdie(buf_swrite(&iob, "l")); | |||
while (args != NULL) { | |||
@@ -114,18 +114,18 @@ cmd_del(int argc, const char *args, FILE *fp) | |||
struct torrent *tp; | |||
if (!benc_isstr(args) || | |||
benc_str(args, &hash, &len, &args) != 0 || len != 20) { | |||
free(iob.buf); | |||
benc_str(args, &hash, &len, &args) != 0 || len != 20) { | |||
free(iob.buf); | |||
return; | |||
} | |||
tp = btpd_get_torrent(hash); | |||
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); | |||
errdie(buf_swrite(&iob, "d4:codei0ee")); | |||
} 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)); | |||
} | |||
} | |||
@@ -154,10 +154,10 @@ static struct { | |||
int nlen; | |||
void (*fun)(int, const char *, FILE *); | |||
} cmd_table[] = { | |||
{ "add", 3, cmd_add }, | |||
{ "del", 3, cmd_del }, | |||
{ "die", 3, cmd_die }, | |||
{ "stat", 4, cmd_stat } | |||
{ "add", 3, cmd_add }, | |||
{ "del", 3, cmd_del }, | |||
{ "die", 3, cmd_die }, | |||
{ "stat", 4, cmd_stat } | |||
}; | |||
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; | |||
if ((nsd = accept(sd, NULL, NULL)) < 0) { | |||
if (errno == EWOULDBLOCK || errno == ECONNABORTED) | |||
return; | |||
else | |||
if (errno == EWOULDBLOCK || errno == ECONNABORTED) | |||
return; | |||
else | |||
btpd_err("client accept: %s\n", strerror(errno)); | |||
} | |||
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) { | |||
close(nsd); | |||
return; | |||
close(nsd); | |||
return; | |||
} | |||
do_ipc(fp); | |||
fclose(fp); | |||
@@ -236,25 +236,25 @@ ipc_init(void) | |||
addr.sun_family = PF_UNIX; | |||
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) | |||
btpd_err("sock: %s\n", strerror(errno)); | |||
btpd_err("sock: %s\n", strerror(errno)); | |||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { | |||
if (errno == EADDRINUSE) { | |||
unlink(addr.sun_path); | |||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) | |||
btpd_err("bind: %s\n", strerror(errno)); | |||
} else | |||
btpd_err("bind: %s\n", strerror(errno)); | |||
if (errno == EADDRINUSE) { | |||
unlink(addr.sun_path); | |||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) | |||
btpd_err("bind: %s\n", strerror(errno)); | |||
} else | |||
btpd_err("bind: %s\n", strerror(errno)); | |||
} | |||
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); | |||
set_nonblocking(sd); | |||
event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST, | |||
client_connection_cb, NULL); | |||
client_connection_cb, NULL); | |||
event_add(&m_cli_incoming, NULL); | |||
} |
@@ -18,14 +18,14 @@ dl_stop(struct torrent *tp) | |||
peer = BTPDQ_FIRST(&tp->peers); | |||
while (peer != NULL) { | |||
struct peer *next = BTPDQ_NEXT(peer, p_entry); | |||
BTPDQ_REMOVE(&tp->peers, peer, p_entry); | |||
BTPDQ_INSERT_TAIL(&net_unattached, peer, p_entry); | |||
BTPDQ_REMOVE(&tp->peers, peer, p_entry); | |||
BTPDQ_INSERT_TAIL(&net_unattached, peer, p_entry); | |||
peer->flags &= ~PF_ATTACHED; | |||
peer = next; | |||
} | |||
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; | |||
tp->piece_count[index]++; | |||
if (has_bit(tp->piece_field, index)) | |||
return; | |||
return; | |||
struct piece *pc = dl_find_piece(tp, index); | |||
if (tp->endgame) { | |||
assert(pc != NULL); | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
assert(pc != NULL); | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
} else if (pc == NULL) { | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) { | |||
pc = dl_new_piece(tp, index); | |||
if (pc != NULL) | |||
dl_piece_assign_requests(pc, p); | |||
} | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) { | |||
pc = dl_new_piece(tp, index); | |||
if (pc != NULL) | |||
dl_piece_assign_requests(pc, p); | |||
} | |||
} else if (!piece_full(pc)) { | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) | |||
dl_piece_assign_requests(pc, p); | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) | |||
dl_piece_assign_requests(pc, p); | |||
} | |||
} | |||
@@ -67,11 +67,11 @@ dl_on_download(struct peer *p) | |||
assert(peer_wanted(p)); | |||
struct torrent *tp = p->tp; | |||
if (tp->endgame) { | |||
dl_assign_requests_eg(p); | |||
dl_assign_requests_eg(p); | |||
} else { | |||
unsigned count = dl_assign_requests(p); | |||
if (count == 0 && !p->tp->endgame) // We may have entered end game. | |||
assert(!peer_wanted(p) || peer_laden(p)); | |||
unsigned count = dl_assign_requests(p); | |||
if (count == 0 && !p->tp->endgame) // We may have entered end game. | |||
assert(!peer_wanted(p) || peer_laden(p)); | |||
} | |||
} | |||
@@ -79,23 +79,23 @@ void | |||
dl_on_unchoke(struct peer *p) | |||
{ | |||
if (peer_wanted(p)) | |||
dl_on_download(p); | |||
dl_on_download(p); | |||
} | |||
void | |||
dl_on_undownload(struct peer *p) | |||
{ | |||
if (!p->tp->endgame) | |||
dl_unassign_requests(p); | |||
dl_unassign_requests(p); | |||
else | |||
dl_unassign_requests_eg(p); | |||
dl_unassign_requests_eg(p); | |||
} | |||
void | |||
dl_on_choke(struct peer *p) | |||
{ | |||
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); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
peer_send(p, have); | |||
peer_send(p, have); | |||
if (tp->endgame) | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
if (peer_has(p, pc->index)) | |||
peer_unwant(p, pc->index); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
if (peer_has(p, pc->index)) | |||
peer_unwant(p, pc->index); | |||
assert(pc->nreqs == 0); | |||
piece_free(pc); | |||
if (torrent_has_all(tp)) { | |||
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath); | |||
tracker_req(tp, TR_COMPLETED); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
assert(p->nwant == 0); | |||
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath); | |||
tracker_req(tp, TR_COMPLETED); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
assert(p->nwant == 0); | |||
} | |||
} | |||
@@ -145,21 +145,21 @@ dl_on_bad_piece(struct piece *pc) | |||
pc->index, tp->relpath); | |||
for (uint32_t i = 0; i < pc->nblocks; i++) { | |||
clear_bit(pc->down_field, i); | |||
clear_bit(pc->have_field, i); | |||
clear_bit(pc->down_field, i); | |||
clear_bit(pc->have_field, i); | |||
} | |||
pc->ngot = 0; | |||
pc->nbusy = 0; | |||
msync(tp->imem, tp->isiz, MS_ASYNC); | |||
if (tp->endgame) { | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
} | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
} | |||
} else | |||
dl_on_piece_unfull(pc); // XXX: May get bad data again. | |||
dl_on_piece_unfull(pc); // XXX: May get bad data again. | |||
} | |||
void | |||
@@ -186,14 +186,14 @@ dl_on_lost_peer(struct peer *p) | |||
tp->piece_count[i]--; | |||
if (p->nreqs_out > 0) | |||
dl_on_undownload(p); | |||
dl_on_undownload(p); | |||
#if 0 | |||
struct piece *pc = BTPDQ_FIRST(&tp->getlst); | |||
while (pc != NULL) { | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
if (peer_has(p, pc->index) && tp->piece_count[pc->index] == 0) | |||
dl_on_peerless_piece(pc); | |||
pc = next; | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
if (peer_has(p, pc->index) && tp->piece_count[pc->index] == 0) | |||
dl_on_peerless_piece(pc); | |||
pc = next; | |||
} | |||
#endif | |||
} | |||
@@ -238,12 +238,12 @@ dl_on_block(struct peer *p, struct block_request *req, | |||
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); | |||
free(req); | |||
pc->nreqs--; | |||
// XXX: Needs to be looked at if we introduce snubbing. | |||
clear_bit(pc->down_field, begin / PIECE_BLOCKLEN); | |||
pc->nbusy--; | |||
if (pc->ngot == pc->nblocks) | |||
dl_on_piece(pc); | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests(p); | |||
// XXX: Needs to be looked at if we introduce snubbing. | |||
clear_bit(pc->down_field, begin / PIECE_BLOCKLEN); | |||
pc->nbusy--; | |||
if (pc->ngot == pc->nblocks) | |||
dl_on_piece(pc); | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests(p); | |||
} | |||
} |
@@ -33,7 +33,7 @@ static struct piece * | |||
piece_alloc(struct torrent *tp, uint32_t index) | |||
{ | |||
assert(!has_bit(tp->busy_field, index) | |||
&& tp->npcs_busy < tp->meta.npieces); | |||
&& tp->npcs_busy < tp->meta.npieces); | |||
struct piece *pc; | |||
size_t mem, field, blocks; | |||
unsigned nblocks; | |||
@@ -48,8 +48,8 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
pc->tp = tp; | |||
pc->down_field = (uint8_t *)(pc + 1); | |||
pc->have_field = | |||
tp->block_field + | |||
index * (size_t)ceil(tp->meta.piece_length / (double)(1 << 17)); | |||
tp->block_field + | |||
index * (size_t)ceil(tp->meta.piece_length / (double)(1 << 17)); | |||
pc->index = index; | |||
pc->nblocks = nblocks; | |||
@@ -58,19 +58,19 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
pc->next_block = 0; | |||
for (unsigned i = 0; i < nblocks; i++) | |||
if (has_bit(pc->have_field, i)) | |||
pc->ngot++; | |||
if (has_bit(pc->have_field, i)) | |||
pc->ngot++; | |||
pc->blocks = (struct block *)(pc->down_field + field); | |||
for (unsigned i = 0; i < nblocks; i++) { | |||
uint32_t start = i * PIECE_BLOCKLEN; | |||
uint32_t len = torrent_block_size(pc, i); | |||
struct block *blk = &pc->blocks[i]; | |||
blk->pc = pc; | |||
BTPDQ_INIT(&blk->reqs); | |||
blk->msg = nb_create_request(index, start, len); | |||
nb_hold(blk->msg); | |||
} | |||
uint32_t start = i * PIECE_BLOCKLEN; | |||
uint32_t len = torrent_block_size(pc, i); | |||
struct block *blk = &pc->blocks[i]; | |||
blk->pc = pc; | |||
BTPDQ_INIT(&blk->reqs); | |||
blk->msg = nb_create_request(index, start, len); | |||
nb_hold(blk->msg); | |||
} | |||
tp->npcs_busy++; | |||
set_bit(tp->busy_field, index); | |||
@@ -87,13 +87,13 @@ piece_free(struct piece *pc) | |||
clear_bit(tp->busy_field, pc->index); | |||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||
for (unsigned i = 0; i < pc->nblocks; i++) { | |||
struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); | |||
while (req != NULL) { | |||
struct block_request *next = BTPDQ_NEXT(req, blk_entry); | |||
free(req); | |||
req = next; | |||
} | |||
nb_drop(pc->blocks[i].msg); | |||
struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); | |||
while (req != NULL) { | |||
struct block_request *next = BTPDQ_NEXT(req, blk_entry); | |||
free(req); | |||
req = next; | |||
} | |||
nb_drop(pc->blocks[i].msg); | |||
} | |||
free(pc); | |||
} | |||
@@ -109,16 +109,16 @@ dl_should_enter_endgame(struct torrent *tp) | |||
{ | |||
int should; | |||
if (tp->have_npieces + tp->npcs_busy == tp->meta.npieces) { | |||
should = 1; | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
if (!piece_full(pc)) { | |||
should = 0; | |||
break; | |||
} | |||
} | |||
should = 1; | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
if (!piece_full(pc)) { | |||
should = 0; | |||
break; | |||
} | |||
} | |||
} else | |||
should = 0; | |||
should = 0; | |||
return should; | |||
} | |||
@@ -127,19 +127,19 @@ dl_piece_insert_eg(struct piece *pc) | |||
{ | |||
struct piece_tq *getlst = &pc->tp->getlst; | |||
if (pc->nblocks == pc->ngot) | |||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | |||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | |||
else { | |||
unsigned r = pc->nreqs / (pc->nblocks - pc->ngot); | |||
struct piece *it; | |||
BTPDQ_FOREACH(it, getlst, entry) { | |||
if ((it->nblocks == it->ngot | |||
|| r < it->nreqs / (it->nblocks - it->ngot))) { | |||
BTPDQ_INSERT_BEFORE(it, pc, entry); | |||
break; | |||
} | |||
} | |||
if (it == NULL) | |||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | |||
unsigned r = pc->nreqs / (pc->nblocks - pc->ngot); | |||
struct piece *it; | |||
BTPDQ_FOREACH(it, getlst, entry) { | |||
if ((it->nblocks == it->ngot | |||
|| r < it->nreqs / (it->nblocks - it->ngot))) { | |||
BTPDQ_INSERT_BEFORE(it, pc, entry); | |||
break; | |||
} | |||
} | |||
if (it == NULL) | |||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | |||
} | |||
} | |||
@@ -163,25 +163,25 @@ dl_enter_endgame(struct torrent *tp) | |||
pi = 0; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
for (unsigned i = 0; i < pc->nblocks; i++) | |||
clear_bit(pc->down_field, i); | |||
pc->nbusy = 0; | |||
pcs[pi] = pc; | |||
pi++; | |||
for (unsigned i = 0; i < pc->nblocks; i++) | |||
clear_bit(pc->down_field, i); | |||
pc->nbusy = 0; | |||
pcs[pi] = pc; | |||
pi++; | |||
} | |||
BTPDQ_INIT(&tp->getlst); | |||
while (pi > 0) { | |||
pi--; | |||
dl_piece_insert_eg(pcs[pi]); | |||
pi--; | |||
dl_piece_insert_eg(pcs[pi]); | |||
} | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
assert(p->nwant == 0); | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
if (peer_has(p, pc->index)) | |||
peer_want(p, pc->index); | |||
} | |||
if (p->nwant > 0 && peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
assert(p->nwant == 0); | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
if (peer_has(p, pc->index)) | |||
peer_want(p, pc->index); | |||
} | |||
if (p->nwant > 0 && peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests_eg(p); | |||
} | |||
} | |||
@@ -190,8 +190,8 @@ dl_find_piece(struct torrent *tp, uint32_t index) | |||
{ | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) | |||
if (pc->index == index) | |||
break; | |||
if (pc->index == index) | |||
break; | |||
return pc; | |||
} | |||
@@ -199,31 +199,31 @@ static int | |||
test_hash(struct torrent *tp, uint8_t *hash, unsigned long index) | |||
{ | |||
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 { | |||
char piece_hash[SHA_DIGEST_LENGTH]; | |||
int fd; | |||
int bufi; | |||
int err; | |||
err = vopen(&fd, O_RDONLY, "%s/torrent", tp->relpath); | |||
if (err != 0) | |||
btpd_err("test_hash: %s\n", strerror(err)); | |||
err = lseek(fd, tp->meta.pieces_off + index * SHA_DIGEST_LENGTH, | |||
SEEK_SET); | |||
if (err < 0) | |||
btpd_err("test_hash: %s\n", strerror(errno)); | |||
bufi = 0; | |||
while (bufi < SHA_DIGEST_LENGTH) { | |||
ssize_t nread = | |||
read(fd, piece_hash + bufi, SHA_DIGEST_LENGTH - bufi); | |||
bufi += nread; | |||
} | |||
close(fd); | |||
return memcmp(hash, piece_hash, SHA_DIGEST_LENGTH); | |||
char piece_hash[SHA_DIGEST_LENGTH]; | |||
int fd; | |||
int bufi; | |||
int err; | |||
err = vopen(&fd, O_RDONLY, "%s/torrent", tp->relpath); | |||
if (err != 0) | |||
btpd_err("test_hash: %s\n", strerror(err)); | |||
err = lseek(fd, tp->meta.pieces_off + index * SHA_DIGEST_LENGTH, | |||
SEEK_SET); | |||
if (err < 0) | |||
btpd_err("test_hash: %s\n", strerror(errno)); | |||
bufi = 0; | |||
while (bufi < SHA_DIGEST_LENGTH) { | |||
ssize_t nread = | |||
read(fd, piece_hash + bufi, SHA_DIGEST_LENGTH - bufi); | |||
bufi += nread; | |||
} | |||
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); | |||
if ((bts = bts_open_ro(&tp->meta, pc->index * tp->meta.piece_length, | |||
ro_fd_cb, tp)) == NULL) | |||
btpd_err("Out of memory.\n"); | |||
ro_fd_cb, tp)) == NULL) | |||
btpd_err("Out of memory.\n"); | |||
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); | |||
if (test_hash(tp, hash, pc->index) == 0) | |||
dl_on_ok_piece(pc); | |||
dl_on_ok_piece(pc); | |||
else | |||
dl_on_bad_piece(pc); | |||
dl_on_bad_piece(pc); | |||
} | |||
void | |||
@@ -268,7 +268,7 @@ static int | |||
dl_piece_startable(struct peer *p, uint32_t 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); | |||
for (i = 0; i < tp->meta.npieces && !dl_piece_startable(p, i); i++) | |||
; | |||
; | |||
if (i == tp->meta.npieces) | |||
return ENOENT; | |||
return ENOENT; | |||
uint32_t min_i = i; | |||
uint32_t min_c = 1; | |||
for(i++; i < tp->meta.npieces; i++) { | |||
if (dl_piece_startable(p, i)) { | |||
if (tp->piece_count[i] == tp->piece_count[min_i]) | |||
min_c++; | |||
else if (tp->piece_count[i] < tp->piece_count[min_i]) { | |||
min_i = i; | |||
min_c = 1; | |||
} | |||
} | |||
if (dl_piece_startable(p, i)) { | |||
if (tp->piece_count[i] == tp->piece_count[min_i]) | |||
min_c++; | |||
else if (tp->piece_count[i] < tp->piece_count[min_i]) { | |||
min_i = i; | |||
min_c = 1; | |||
} | |||
} | |||
} | |||
if (min_c > 1) { | |||
min_c = 1 + rint((double)random() * (min_c - 1) / RAND_MAX); | |||
for (i = min_i; min_c > 0; i++) { | |||
if (dl_piece_startable(p, i) | |||
&& tp->piece_count[i] == tp->piece_count[min_i]) { | |||
min_c--; | |||
min_i = i; | |||
} | |||
} | |||
min_c = 1 + rint((double)random() * (min_c - 1) / RAND_MAX); | |||
for (i = min_i; min_c > 0; i++) { | |||
if (dl_piece_startable(p, i) | |||
&& tp->piece_count[i] == tp->piece_count[min_i]) { | |||
min_c--; | |||
min_i = i; | |||
} | |||
} | |||
} | |||
*res = min_i; | |||
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 | |||
* that has this piece will be decreased. This function is | |||
* the only one that may trigger end game. | |||
@@ -329,11 +329,11 @@ dl_on_piece_full(struct piece *pc) | |||
{ | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &pc->tp->peers, p_entry) { | |||
if (peer_has(p, pc->index)) | |||
peer_unwant(p, pc->index); | |||
if (peer_has(p, pc->index)) | |||
peer_unwant(p, pc->index); | |||
} | |||
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); | |||
struct piece *pc = piece_alloc(tp, index); | |||
if (pc->ngot == pc->nblocks) { | |||
dl_on_piece_full(pc); | |||
dl_on_piece(pc); | |||
if (dl_should_enter_endgame(tp)) | |||
dl_enter_endgame(tp); | |||
return NULL; | |||
dl_on_piece_full(pc); | |||
dl_on_piece(pc); | |||
if (dl_should_enter_endgame(tp)) | |||
dl_enter_endgame(tp); | |||
return NULL; | |||
} else | |||
return pc; | |||
return pc; | |||
} | |||
/* | |||
@@ -374,13 +374,13 @@ dl_on_piece_unfull(struct piece *pc) | |||
struct peer *p; | |||
assert(!piece_full(pc) && tp->endgame == 0); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
if (peer_has(p, pc->index)) | |||
peer_want(p, pc->index); | |||
if (peer_has(p, pc->index)) | |||
peer_want(p, pc->index); | |||
p = BTPDQ_FIRST(&tp->peers); | |||
while (p != NULL && !piece_full(pc)) { | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
dl_piece_assign_requests(pc, p); // Cannot provoke end game here. | |||
p = BTPDQ_NEXT(p, p_entry); | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
dl_piece_assign_requests(pc, p); // Cannot provoke end game here. | |||
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)); | |||
unsigned count = 0; | |||
do { | |||
while ((has_bit(pc->have_field, pc->next_block) | |||
|| has_bit(pc->down_field, pc->next_block))) | |||
INCNEXTBLOCK(pc); | |||
struct block *blk = &pc->blocks[pc->next_block]; | |||
struct block_request *req = btpd_malloc(sizeof(*req)); | |||
req->p = p; | |||
req->blk = blk; | |||
BTPDQ_INSERT_TAIL(&blk->reqs, req, blk_entry); | |||
peer_request(p, req); | |||
set_bit(pc->down_field, pc->next_block); | |||
pc->nbusy++; | |||
pc->nreqs++; | |||
count++; | |||
INCNEXTBLOCK(pc); | |||
while ((has_bit(pc->have_field, pc->next_block) | |||
|| has_bit(pc->down_field, pc->next_block))) | |||
INCNEXTBLOCK(pc); | |||
struct block *blk = &pc->blocks[pc->next_block]; | |||
struct block_request *req = btpd_malloc(sizeof(*req)); | |||
req->p = p; | |||
req->blk = blk; | |||
BTPDQ_INSERT_TAIL(&blk->reqs, req, blk_entry); | |||
peer_request(p, req); | |||
set_bit(pc->down_field, pc->next_block); | |||
pc->nbusy++; | |||
pc->nreqs++; | |||
count++; | |||
INCNEXTBLOCK(pc); | |||
} while (!piece_full(pc) && !peer_laden(p)); | |||
if (piece_full(pc)) | |||
dl_on_piece_full(pc); | |||
dl_on_piece_full(pc); | |||
return count; | |||
} | |||
@@ -444,24 +444,24 @@ dl_assign_requests(struct peer *p) | |||
struct torrent *tp = p->tp; | |||
unsigned count = 0; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
if (piece_full(pc) || !peer_has(p, pc->index)) | |||
continue; | |||
count += dl_piece_assign_requests(pc, p); | |||
if (tp->endgame) | |||
break; | |||
if (!piece_full(pc)) | |||
assert(peer_laden(p)); | |||
if (peer_laden(p)) | |||
break; | |||
if (piece_full(pc) || !peer_has(p, pc->index)) | |||
continue; | |||
count += dl_piece_assign_requests(pc, p); | |||
if (tp->endgame) | |||
break; | |||
if (!piece_full(pc)) | |||
assert(peer_laden(p)); | |||
if (peer_laden(p)) | |||
break; | |||
} | |||
while (!peer_laden(p) && !tp->endgame) { | |||
uint32_t index; | |||
if (dl_choose_rarest(p, &index) == 0) { | |||
pc = dl_new_piece(tp, index); | |||
if (pc != NULL) | |||
count += dl_piece_assign_requests(pc, p); | |||
} else | |||
break; | |||
uint32_t index; | |||
if (dl_choose_rarest(p, &index) == 0) { | |||
pc = dl_new_piece(tp, index); | |||
if (pc != NULL) | |||
count += dl_piece_assign_requests(pc, p); | |||
} else | |||
break; | |||
} | |||
return count; | |||
} | |||
@@ -470,32 +470,32 @@ void | |||
dl_unassign_requests(struct peer *p) | |||
{ | |||
while (p->nreqs_out > 0) { | |||
struct block_request *req = BTPDQ_FIRST(&p->my_reqs); | |||
struct piece *pc = req->blk->pc; | |||
int was_full = piece_full(pc); | |||
while (req != NULL) { | |||
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; | |||
// XXX: Needs to be looked at if we introduce snubbing. | |||
assert(has_bit(pc->down_field, blki)); | |||
clear_bit(pc->down_field, blki); | |||
pc->nbusy--; | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); | |||
free(req); | |||
pc->nreqs--; | |||
while (next != NULL && next->blk->pc != pc) | |||
next = BTPDQ_NEXT(next, p_entry); | |||
req = next; | |||
} | |||
if (was_full && !piece_full(pc)) | |||
dl_on_piece_unfull(pc); | |||
struct block_request *req = BTPDQ_FIRST(&p->my_reqs); | |||
struct piece *pc = req->blk->pc; | |||
int was_full = piece_full(pc); | |||
while (req != NULL) { | |||
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; | |||
// XXX: Needs to be looked at if we introduce snubbing. | |||
assert(has_bit(pc->down_field, blki)); | |||
clear_bit(pc->down_field, blki); | |||
pc->nbusy--; | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); | |||
free(req); | |||
pc->nreqs--; | |||
while (next != NULL && next->blk->pc != pc) | |||
next = BTPDQ_NEXT(next, p_entry); | |||
req = next; | |||
} | |||
if (was_full && !piece_full(pc)) | |||
dl_on_piece_unfull(pc); | |||
} | |||
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; | |||
do { | |||
if ((has_bit(pc->have_field, pc->next_block) | |||
|| peer_requested(p, &pc->blocks[pc->next_block]))) { | |||
INCNEXTBLOCK(pc); | |||
continue; | |||
} | |||
struct block_request *req = btpd_calloc(1, sizeof(*req)); | |||
req->blk = &pc->blocks[pc->next_block]; | |||
req->p = p; | |||
BTPDQ_INSERT_TAIL(&pc->blocks[pc->next_block].reqs, req, blk_entry); | |||
pc->nreqs++; | |||
INCNEXTBLOCK(pc); | |||
peer_request(p, req); | |||
if ((has_bit(pc->have_field, pc->next_block) | |||
|| peer_requested(p, &pc->blocks[pc->next_block]))) { | |||
INCNEXTBLOCK(pc); | |||
continue; | |||
} | |||
struct block_request *req = btpd_calloc(1, sizeof(*req)); | |||
req->blk = &pc->blocks[pc->next_block]; | |||
req->p = p; | |||
BTPDQ_INSERT_TAIL(&pc->blocks[pc->next_block].reqs, req, blk_entry); | |||
pc->nreqs++; | |||
INCNEXTBLOCK(pc); | |||
peer_request(p, req); | |||
} 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); | |||
while (!peer_laden(p) && pc != NULL) { | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { | |||
dl_piece_assign_requests_eg(pc, p); | |||
BTPDQ_REMOVE(&tp->getlst, pc, entry); | |||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | |||
} | |||
pc = next; | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { | |||
dl_piece_assign_requests_eg(pc, p); | |||
BTPDQ_REMOVE(&tp->getlst, pc, entry); | |||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | |||
} | |||
pc = next; | |||
} | |||
pc = BTPDQ_FIRST(&tmp); | |||
while (pc != NULL) { | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
dl_piece_insert_eg(pc); | |||
pc = next; | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
dl_piece_insert_eg(pc); | |||
pc = next; | |||
} | |||
} | |||
@@ -556,31 +556,31 @@ dl_unassign_requests_eg(struct peer *p) | |||
BTPDQ_INIT(&tmp); | |||
while (p->nreqs_out > 0) { | |||
req = BTPDQ_FIRST(&p->my_reqs); | |||
pc = req->blk->pc; | |||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | |||
while (req != NULL) { | |||
struct block_request *next = BTPDQ_NEXT(req, p_entry); | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&req->blk->reqs, req, blk_entry); | |||
free(req); | |||
pc->nreqs--; | |||
while (next != NULL && next->blk->pc != pc) | |||
next = BTPDQ_NEXT(next, p_entry); | |||
req = next; | |||
} | |||
req = BTPDQ_FIRST(&p->my_reqs); | |||
pc = req->blk->pc; | |||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | |||
while (req != NULL) { | |||
struct block_request *next = BTPDQ_NEXT(req, p_entry); | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&req->blk->reqs, req, blk_entry); | |||
free(req); | |||
pc->nreqs--; | |||
while (next != NULL && next->blk->pc != pc) | |||
next = BTPDQ_NEXT(next, p_entry); | |||
req = next; | |||
} | |||
} | |||
assert(BTPDQ_EMPTY(&p->my_reqs)); | |||
pc = BTPDQ_FIRST(&tmp); | |||
while (pc != NULL) { | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
dl_piece_insert_eg(pc); | |||
pc = next; | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
dl_piece_insert_eg(pc); | |||
pc = next; | |||
} | |||
} |
@@ -28,15 +28,15 @@ find_homedir(void) | |||
{ | |||
char *res = getenv("BTPD_HOME"); | |||
if (res == NULL) { | |||
char *home = getenv("HOME"); | |||
if (home == NULL) { | |||
struct passwd *pwent = getpwuid(getuid()); | |||
if (pwent == NULL) | |||
errx(1, "Can't find my home directory.\n"); | |||
home = pwent->pw_dir; | |||
endpwent(); | |||
} | |||
asprintf(&res, "%s/.btpd", home); | |||
char *home = getenv("HOME"); | |||
if (home == NULL) { | |||
struct passwd *pwent = getpwuid(getuid()); | |||
if (pwent == NULL) | |||
errx(1, "Can't find my home directory.\n"); | |||
home = pwent->pw_dir; | |||
endpwent(); | |||
} | |||
asprintf(&res, "%s/.btpd", home); | |||
} | |||
return res; | |||
} | |||
@@ -47,7 +47,7 @@ setup_daemon(const char *dir) | |||
int pidfd; | |||
if (dir == NULL) | |||
dir = find_homedir(); | |||
dir = find_homedir(); | |||
btpd_dir = dir; | |||
@@ -79,49 +79,49 @@ static void | |||
usage(void) | |||
{ | |||
printf("Usage: btpd [options]\n" | |||
"\n" | |||
"Options:\n" | |||
"\n" | |||
"--bw-hz n\n" | |||
"\tRun the bandwidth limiter at n hz.\n" | |||
"\tDefault is 8 hz.\n" | |||
"\n" | |||
"--bw-in n\n" | |||
"\tLimit incoming BitTorrent traffic to n kB/s.\n" | |||
"\tDefault is 0 which means unlimited.\n" | |||
"\n" | |||
"--bw-out n\n" | |||
"\tLimit outgoing BitTorrent traffic to n kB/s.\n" | |||
"\tDefault is 0 which means unlimited.\n" | |||
"\n" | |||
"-d\n" | |||
"\tKeep the btpd process in the foregorund and log to std{out,err}.\n" | |||
"\tThis option is intended for debugging purposes.\n" | |||
"\n" | |||
"--ipc key\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" | |||
"\n" | |||
"--logfile file\n" | |||
"\tLog to the given file. By default btpd logs to ./btpd.log.\n" | |||
"\n" | |||
"-p n, --port n\n" | |||
"\tListen at port n. Default is 6881.\n" | |||
"\n" | |||
"--help\n" | |||
"\tShow this help.\n" | |||
"\n"); | |||
"\n" | |||
"Options:\n" | |||
"\n" | |||
"--bw-hz n\n" | |||
"\tRun the bandwidth limiter at n hz.\n" | |||
"\tDefault is 8 hz.\n" | |||
"\n" | |||
"--bw-in n\n" | |||
"\tLimit incoming BitTorrent traffic to n kB/s.\n" | |||
"\tDefault is 0 which means unlimited.\n" | |||
"\n" | |||
"--bw-out n\n" | |||
"\tLimit outgoing BitTorrent traffic to n kB/s.\n" | |||
"\tDefault is 0 which means unlimited.\n" | |||
"\n" | |||
"-d\n" | |||
"\tKeep the btpd process in the foregorund and log to std{out,err}.\n" | |||
"\tThis option is intended for debugging purposes.\n" | |||
"\n" | |||
"--ipc key\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" | |||
"\n" | |||
"--logfile file\n" | |||
"\tLog to the given file. By default btpd logs to ./btpd.log.\n" | |||
"\n" | |||
"-p n, --port n\n" | |||
"\tListen at port n. Default is 6881.\n" | |||
"\n" | |||
"--help\n" | |||
"\tShow this help.\n" | |||
"\n"); | |||
exit(1); | |||
} | |||
static int longval = 0; | |||
static struct option longopts[] = { | |||
{ "port", required_argument, NULL, 'p' }, | |||
{ "bw-in", required_argument, &longval, 1 }, | |||
{ "bw-out", required_argument, &longval, 2 }, | |||
{ "help", no_argument, &longval, 5 }, | |||
{ NULL, 0, NULL, 0 } | |||
{ "port", required_argument, NULL, 'p' }, | |||
{ "bw-in", required_argument, &longval, 1 }, | |||
{ "bw-out", required_argument, &longval, 2 }, | |||
{ "help", no_argument, &longval, 5 }, | |||
{ NULL, 0, NULL, 0 } | |||
}; | |||
int | |||
@@ -132,38 +132,38 @@ main(int argc, char **argv) | |||
setlocale(LC_ALL, ""); | |||
for (;;) { | |||
switch (getopt_long(argc, argv, "dp:", longopts, NULL)) { | |||
case -1: | |||
goto args_done; | |||
case 'd': | |||
btpd_daemon = 0; | |||
break; | |||
case 'p': | |||
net_port = atoi(optarg); | |||
break; | |||
case 0: | |||
switch (longval) { | |||
case 1: | |||
net_bw_limit_in = atoi(optarg) * 1024; | |||
break; | |||
case 2: | |||
net_bw_limit_out = atoi(optarg) * 1024; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
break; | |||
case '?': | |||
default: | |||
usage(); | |||
} | |||
switch (getopt_long(argc, argv, "dp:", longopts, NULL)) { | |||
case -1: | |||
goto args_done; | |||
case 'd': | |||
btpd_daemon = 0; | |||
break; | |||
case 'p': | |||
net_port = atoi(optarg); | |||
break; | |||
case 0: | |||
switch (longval) { | |||
case 1: | |||
net_bw_limit_in = atoi(optarg) * 1024; | |||
break; | |||
case 2: | |||
net_bw_limit_out = atoi(optarg) * 1024; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
break; | |||
case '?': | |||
default: | |||
usage(); | |||
} | |||
} | |||
args_done: | |||
argc -= optind; | |||
argv += optind; | |||
if (argc != 0) | |||
usage(); | |||
usage(); | |||
setup_daemon(dir); | |||
@@ -55,10 +55,10 @@ net_del_torrent(struct torrent *tp) | |||
struct peer *p = BTPDQ_FIRST(&net_unattached); | |||
while (p != NULL) { | |||
struct peer *next = BTPDQ_NEXT(p, p_entry); | |||
if (p->tp == tp) | |||
peer_kill(p); | |||
p = next; | |||
struct peer *next = BTPDQ_NEXT(p, p_entry); | |||
if (p->tp == tp) | |||
peer_kill(p); | |||
p = next; | |||
} | |||
} | |||
@@ -89,67 +89,67 @@ net_write(struct peer *p, unsigned long wmax) | |||
niov = 0; | |||
assert((nl = BTPDQ_FIRST(&p->outq)) != NULL); | |||
while ((niov < IOV_MAX && nl != NULL | |||
&& (!limited || (limited && wmax > 0)))) { | |||
if (niov > 0) { | |||
iov[niov].iov_base = nl->nb->buf; | |||
iov[niov].iov_len = nl->nb->len; | |||
} else { | |||
iov[niov].iov_base = nl->nb->buf + p->outq_off; | |||
iov[niov].iov_len = nl->nb->len - p->outq_off; | |||
} | |||
if (limited) { | |||
if (iov[niov].iov_len > wmax) | |||
iov[niov].iov_len = wmax; | |||
wmax -= iov[niov].iov_len; | |||
} | |||
niov++; | |||
nl = BTPDQ_NEXT(nl, entry); | |||
&& (!limited || (limited && wmax > 0)))) { | |||
if (niov > 0) { | |||
iov[niov].iov_base = nl->nb->buf; | |||
iov[niov].iov_len = nl->nb->len; | |||
} else { | |||
iov[niov].iov_base = nl->nb->buf + p->outq_off; | |||
iov[niov].iov_len = nl->nb->len - p->outq_off; | |||
} | |||
if (limited) { | |||
if (iov[niov].iov_len > wmax) | |||
iov[niov].iov_len = wmax; | |||
wmax -= iov[niov].iov_len; | |||
} | |||
niov++; | |||
nl = BTPDQ_NEXT(nl, entry); | |||
} | |||
nwritten = writev(p->sd, iov, niov); | |||
if (nwritten < 0) { | |||
if (errno == EAGAIN) { | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
return 0; | |||
} else { | |||
btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno)); | |||
peer_kill(p); | |||
return 0; | |||
} | |||
if (errno == EAGAIN) { | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
return 0; | |||
} else { | |||
btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno)); | |||
peer_kill(p); | |||
return 0; | |||
} | |||
} else if (nwritten == 0) { | |||
btpd_log(BTPD_L_CONN, "connection closed by peer.\n"); | |||
peer_kill(p); | |||
return 0; | |||
btpd_log(BTPD_L_CONN, "connection closed by peer.\n"); | |||
peer_kill(p); | |||
return 0; | |||
} | |||
bcount = nwritten; | |||
nl = BTPDQ_FIRST(&p->outq); | |||
while (bcount > 0) { | |||
unsigned long bufdelta = nl->nb->len - p->outq_off; | |||
if (bcount >= bufdelta) { | |||
peer_sent(p, nl->nb); | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bufdelta; | |||
p->count_up += bufdelta; | |||
} | |||
bcount -= bufdelta; | |||
BTPDQ_REMOVE(&p->outq, nl, entry); | |||
nb_drop(nl->nb); | |||
free(nl); | |||
p->outq_off = 0; | |||
nl = BTPDQ_FIRST(&p->outq); | |||
} else { | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bcount; | |||
p->count_up += bcount; | |||
} | |||
p->outq_off += bcount; | |||
bcount = 0; | |||
} | |||
unsigned long bufdelta = nl->nb->len - p->outq_off; | |||
if (bcount >= bufdelta) { | |||
peer_sent(p, nl->nb); | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bufdelta; | |||
p->count_up += bufdelta; | |||
} | |||
bcount -= bufdelta; | |||
BTPDQ_REMOVE(&p->outq, nl, entry); | |||
nb_drop(nl->nb); | |||
free(nl); | |||
p->outq_off = 0; | |||
nl = BTPDQ_FIRST(&p->outq); | |||
} else { | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bcount; | |||
p->count_up += bcount; | |||
} | |||
p->outq_off += bcount; | |||
bcount = 0; | |||
} | |||
} | |||
if (!BTPDQ_EMPTY(&p->outq)) | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
return nwritten; | |||
} | |||
@@ -169,55 +169,55 @@ net_dispatch_msg(struct peer *p, const char *buf) | |||
switch (p->net.msg_num) { | |||
case MSG_CHOKE: | |||
peer_on_choke(p); | |||
break; | |||
peer_on_choke(p); | |||
break; | |||
case MSG_UNCHOKE: | |||
peer_on_unchoke(p); | |||
break; | |||
peer_on_unchoke(p); | |||
break; | |||
case MSG_INTEREST: | |||
peer_on_interest(p); | |||
break; | |||
peer_on_interest(p); | |||
break; | |||
case MSG_UNINTEREST: | |||
peer_on_uninterest(p); | |||
break; | |||
peer_on_uninterest(p); | |||
break; | |||
case MSG_HAVE: | |||
peer_on_have(p, net_read32(buf)); | |||
break; | |||
peer_on_have(p, net_read32(buf)); | |||
break; | |||
case MSG_BITFIELD: | |||
if (p->npieces == 0) | |||
peer_on_bitfield(p, buf); | |||
else | |||
res = 1; | |||
break; | |||
break; | |||
case MSG_REQUEST: | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) { | |||
index = net_read32(buf); | |||
begin = net_read32(buf + 4); | |||
length = net_read32(buf + 8); | |||
if ((length > PIECE_BLOCKLEN | |||
|| index >= p->tp->meta.npieces | |||
|| !has_bit(p->tp->piece_field, index) | |||
|| begin + length > torrent_piece_size(p->tp, index))) { | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) { | |||
index = net_read32(buf); | |||
begin = net_read32(buf + 4); | |||
length = net_read32(buf + 8); | |||
if ((length > PIECE_BLOCKLEN | |||
|| index >= p->tp->meta.npieces | |||
|| !has_bit(p->tp->piece_field, index) | |||
|| begin + length > torrent_piece_size(p->tp, index))) { | |||
btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n", | |||
index, begin, length, p); | |||
res = 1; | |||
break; | |||
} | |||
peer_on_request(p, index, begin, length); | |||
} | |||
break; | |||
res = 1; | |||
break; | |||
} | |||
peer_on_request(p, index, begin, length); | |||
} | |||
break; | |||
case MSG_CANCEL: | |||
index = net_read32(buf); | |||
begin = net_read32(buf + 4); | |||
length = net_read32(buf + 8); | |||
peer_on_cancel(p, index, begin, length); | |||
break; | |||
index = net_read32(buf); | |||
begin = net_read32(buf + 4); | |||
length = net_read32(buf + 8); | |||
peer_on_cancel(p, index, begin, length); | |||
break; | |||
case MSG_PIECE: | |||
length = p->net.msg_len - 9; | |||
peer_on_piece(p, p->net.pc_index, p->net.pc_begin, length, buf); | |||
break; | |||
length = p->net.msg_len - 9; | |||
peer_on_piece(p, p->net.pc_index, p->net.pc_begin, length, buf); | |||
break; | |||
default: | |||
abort(); | |||
abort(); | |||
} | |||
return res; | |||
} | |||
@@ -231,18 +231,18 @@ net_mh_ok(struct peer *p) | |||
case MSG_UNCHOKE: | |||
case MSG_INTEREST: | |||
case MSG_UNINTEREST: | |||
return mlen == 1; | |||
return mlen == 1; | |||
case MSG_HAVE: | |||
return mlen == 5; | |||
return mlen == 5; | |||
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_CANCEL: | |||
return mlen == 13; | |||
return mlen == 13; | |||
case MSG_PIECE: | |||
return mlen <= PIECE_BLOCKLEN + 9; | |||
return mlen <= PIECE_BLOCKLEN + 9; | |||
default: | |||
return 0; | |||
return 0; | |||
} | |||
} | |||
@@ -250,8 +250,8 @@ static void | |||
net_progress(struct peer *p, size_t length) | |||
{ | |||
if (p->net.state == BTP_MSGBODY && p->net.msg_num == MSG_PIECE) { | |||
p->tp->downloaded += length; | |||
p->count_dwn += length; | |||
p->tp->downloaded += length; | |||
p->count_dwn += length; | |||
} | |||
} | |||
@@ -261,63 +261,63 @@ net_state(struct peer *p, const char *buf) | |||
switch (p->net.state) { | |||
case SHAKE_PSTR: | |||
if (bcmp(buf, "\x13""BitTorrent protocol", 20) != 0) | |||
goto bad; | |||
net_set_state(p, SHAKE_INFO, 20); | |||
goto bad; | |||
net_set_state(p, SHAKE_INFO, 20); | |||
break; | |||
case SHAKE_INFO: | |||
if (p->flags & PF_INCOMING) { | |||
struct torrent *tp; | |||
if (p->flags & PF_INCOMING) { | |||
struct torrent *tp; | |||
BTPDQ_FOREACH(tp, &m_torrents, net_entry) | |||
if (bcmp(buf, tp->meta.info_hash, 20) == 0) | |||
break; | |||
if (tp == NULL) | |||
goto bad; | |||
p->tp = tp; | |||
peer_send(p, nb_create_shake(p->tp)); | |||
} else if (bcmp(buf, p->tp->meta.info_hash, 20) != 0) | |||
goto bad; | |||
net_set_state(p, SHAKE_ID, 20); | |||
if (tp == NULL) | |||
goto bad; | |||
p->tp = tp; | |||
peer_send(p, nb_create_shake(p->tp)); | |||
} else if (bcmp(buf, p->tp->meta.info_hash, 20) != 0) | |||
goto bad; | |||
net_set_state(p, SHAKE_ID, 20); | |||
break; | |||
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)) | |||
goto bad; | |||
bcopy(buf, p->id, 20); | |||
goto bad; | |||
bcopy(buf, p->id, 20); | |||
peer_on_shake(p); | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
break; | |||
case BTP_MSGSIZE: | |||
p->net.msg_len = net_read32(buf); | |||
if (p->net.msg_len == 0) | |||
peer_on_keepalive(p); | |||
else | |||
net_set_state(p, BTP_MSGHEAD, 1); | |||
p->net.msg_len = net_read32(buf); | |||
if (p->net.msg_len == 0) | |||
peer_on_keepalive(p); | |||
else | |||
net_set_state(p, BTP_MSGHEAD, 1); | |||
break; | |||
case BTP_MSGHEAD: | |||
p->net.msg_num = buf[0]; | |||
if (!net_mh_ok(p)) | |||
goto bad; | |||
else if (p->net.msg_len == 1) { | |||
if (net_dispatch_msg(p, buf) != 0) | |||
goto bad; | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
} else if (p->net.msg_num == MSG_PIECE) | |||
net_set_state(p, BTP_PIECEMETA, 8); | |||
else | |||
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 1); | |||
p->net.msg_num = buf[0]; | |||
if (!net_mh_ok(p)) | |||
goto bad; | |||
else if (p->net.msg_len == 1) { | |||
if (net_dispatch_msg(p, buf) != 0) | |||
goto bad; | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
} else if (p->net.msg_num == MSG_PIECE) | |||
net_set_state(p, BTP_PIECEMETA, 8); | |||
else | |||
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 1); | |||
break; | |||
case BTP_PIECEMETA: | |||
p->net.pc_index = net_read32(buf); | |||
p->net.pc_begin = net_read32(buf + 4); | |||
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 9); | |||
break; | |||
p->net.pc_index = net_read32(buf); | |||
p->net.pc_begin = net_read32(buf + 4); | |||
net_set_state(p, BTP_MSGBODY, p->net.msg_len - 9); | |||
break; | |||
case BTP_MSGBODY: | |||
if (net_dispatch_msg(p, buf) != 0) | |||
goto bad; | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
if (net_dispatch_msg(p, buf) != 0) | |||
goto bad; | |||
net_set_state(p, BTP_MSGSIZE, 4); | |||
break; | |||
default: | |||
abort(); | |||
abort(); | |||
} | |||
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; | |||
char buf[GRBUFLEN]; | |||
struct iovec iov[2] = { | |||
{ | |||
p->net.buf + p->net.off, | |||
rest | |||
}, { | |||
buf, | |||
sizeof(buf) | |||
} | |||
{ | |||
p->net.buf + p->net.off, | |||
rest | |||
}, { | |||
buf, | |||
sizeof(buf) | |||
} | |||
}; | |||
if (rmax > 0) { | |||
if (iov[0].iov_len > rmax) | |||
iov[0].iov_len = rmax; | |||
iov[1].iov_len = min(rmax - iov[0].iov_len, iov[1].iov_len); | |||
if (iov[0].iov_len > rmax) | |||
iov[0].iov_len = rmax; | |||
iov[1].iov_len = min(rmax - iov[0].iov_len, iov[1].iov_len); | |||
} | |||
ssize_t nread = readv(p->sd, iov, 2); | |||
if (nread < 0 && errno == EAGAIN) | |||
goto out; | |||
goto out; | |||
else if (nread < 0) { | |||
btpd_log(BTPD_L_CONN, "Read error (%s) on %p.\n", strerror(errno), p); | |||
peer_kill(p); | |||
return 0; | |||
btpd_log(BTPD_L_CONN, "Read error (%s) on %p.\n", strerror(errno), p); | |||
peer_kill(p); | |||
return 0; | |||
} else if (nread == 0) { | |||
btpd_log(BTPD_L_CONN, "Connection closed by %p.\n", p); | |||
peer_kill(p); | |||
return 0; | |||
btpd_log(BTPD_L_CONN, "Connection closed by %p.\n", p); | |||
peer_kill(p); | |||
return 0; | |||
} | |||
if (rest > 0) { | |||
if (nread < rest) { | |||
p->net.off += nread; | |||
net_progress(p, nread); | |||
goto out; | |||
} | |||
net_progress(p, rest); | |||
if (net_state(p, p->net.buf) != 0) | |||
return nread; | |||
free(p->net.buf); | |||
if (nread < rest) { | |||
p->net.off += nread; | |||
net_progress(p, nread); | |||
goto out; | |||
} | |||
net_progress(p, rest); | |||
if (net_state(p, p->net.buf) != 0) | |||
return nread; | |||
free(p->net.buf); | |||
p->net.buf = NULL; | |||
p->net.off = 0; | |||
} | |||
@@ -381,18 +381,18 @@ net_read(struct peer *p, unsigned long rmax) | |||
iov[1].iov_len = nread - rest; | |||
while (p->net.st_bytes <= iov[1].iov_len) { | |||
size_t consumed = p->net.st_bytes; | |||
net_progress(p, consumed); | |||
if (net_state(p, iov[1].iov_base) != 0) | |||
return nread; | |||
iov[1].iov_base += consumed; | |||
iov[1].iov_len -= consumed; | |||
net_progress(p, consumed); | |||
if (net_state(p, iov[1].iov_base) != 0) | |||
return nread; | |||
iov[1].iov_base += consumed; | |||
iov[1].iov_len -= consumed; | |||
} | |||
if (iov[1].iov_len > 0) { | |||
net_progress(p, iov[1].iov_len); | |||
p->net.off = iov[1].iov_len; | |||
p->net.buf = btpd_malloc(p->net.st_bytes); | |||
bcopy(iov[1].iov_base, p->net.buf, iov[1].iov_len); | |||
net_progress(p, iov[1].iov_len); | |||
p->net.off = iov[1].iov_len; | |||
p->net.buf = btpd_malloc(p->net.st_bytes); | |||
bcopy(iov[1].iov_base, p->net.buf, iov[1].iov_len); | |||
} | |||
out: | |||
@@ -403,15 +403,15 @@ out: | |||
int | |||
net_connect2(struct sockaddr *sa, socklen_t salen, int *sd) | |||
{ | |||
if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) | |||
return errno; | |||
if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) | |||
return errno; | |||
set_nonblocking(*sd); | |||
if (connect(*sd, sa, salen) == -1 && errno != EINPROGRESS) { | |||
btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno)); | |||
close(*sd); | |||
return errno; | |||
btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno)); | |||
close(*sd); | |||
return errno; | |||
} | |||
return 0; | |||
@@ -422,17 +422,17 @@ net_connect(const char *ip, int port, int *sd) | |||
{ | |||
struct addrinfo hints, *res; | |||
char portstr[6]; | |||
assert(net_npeers < net_max_peers); | |||
if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) | |||
return EINVAL; | |||
return EINVAL; | |||
bzero(&hints, sizeof(hints)); | |||
hints.ai_family = AF_UNSPEC; | |||
hints.ai_flags = AI_NUMERICHOST; | |||
hints.ai_socktype = SOCK_STREAM; | |||
if (getaddrinfo(ip, portstr, &hints, &res) != 0) | |||
return errno; | |||
return errno; | |||
int error = net_connect2(res->ai_addr, res->ai_addrlen, sd); | |||
freeaddrinfo(res); | |||
@@ -446,21 +446,21 @@ net_connection_cb(int sd, short type, void *arg) | |||
nsd = accept(sd, NULL, NULL); | |||
if (nsd < 0) { | |||
if (errno == EWOULDBLOCK || errno == ECONNABORTED) | |||
return; | |||
else | |||
btpd_err("accept4: %s\n", strerror(errno)); | |||
if (errno == EWOULDBLOCK || errno == ECONNABORTED) | |||
return; | |||
else | |||
btpd_err("accept4: %s\n", strerror(errno)); | |||
} | |||
if (set_nonblocking(nsd) != 0) { | |||
close(nsd); | |||
return; | |||
close(nsd); | |||
return; | |||
} | |||
assert(net_npeers <= net_max_peers); | |||
if (net_npeers == net_max_peers) { | |||
close(nsd); | |||
return; | |||
close(nsd); | |||
return; | |||
} | |||
peer_create_in(nsd); | |||
@@ -474,35 +474,35 @@ long | |||
compute_rate_sub(long rate) | |||
{ | |||
if (rate > 256 * RATEHISTORY) | |||
return rate / RATEHISTORY; | |||
return rate / RATEHISTORY; | |||
else | |||
return 256; | |||
return 256; | |||
} | |||
static void | |||
compute_peer_rates(void) { | |||
struct torrent *tp; | |||
BTPDQ_FOREACH(tp, &m_torrents, net_entry) { | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
if (p->count_up > 0 || peer_active_up(p)) { | |||
p->rate_up += p->count_up - compute_rate_sub(p->rate_up); | |||
if (p->rate_up < 0) | |||
p->rate_up = 0; | |||
p->count_up = 0; | |||
} | |||
if (p->count_dwn > 0 || peer_active_down(p)) { | |||
p->rate_dwn += p->count_dwn - compute_rate_sub(p->rate_dwn); | |||
if (p->rate_dwn < 0) | |||
p->rate_dwn = 0; | |||
p->count_dwn = 0; | |||
} | |||
} | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
if (p->count_up > 0 || peer_active_up(p)) { | |||
p->rate_up += p->count_up - compute_rate_sub(p->rate_up); | |||
if (p->rate_up < 0) | |||
p->rate_up = 0; | |||
p->count_up = 0; | |||
} | |||
if (p->count_dwn > 0 || peer_active_down(p)) { | |||
p->rate_dwn += p->count_dwn - compute_rate_sub(p->rate_dwn); | |||
if (p->rate_dwn < 0) | |||
p->rate_dwn = 0; | |||
p->count_dwn = 0; | |||
} | |||
} | |||
} | |||
} | |||
void | |||
net_bw_cb(int sd, short type, void *arg) | |||
net_bw_cb(int sd, short type, void *arg) | |||
{ | |||
struct peer *p; | |||
@@ -514,31 +514,31 @@ net_bw_cb(int sd, short type, void *arg) | |||
m_bw_bytes_in = net_bw_limit_in; | |||
if (net_bw_limit_in > 0) { | |||
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) { | |||
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | |||
p->flags &= ~PF_ON_READQ; | |||
m_bw_bytes_in -= net_read(p, m_bw_bytes_in); | |||
} | |||
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) { | |||
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | |||
p->flags &= ~PF_ON_READQ; | |||
m_bw_bytes_in -= net_read(p, m_bw_bytes_in); | |||
} | |||
} else { | |||
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) { | |||
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | |||
p->flags &= ~PF_ON_READQ; | |||
net_read(p, 0); | |||
} | |||
while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) { | |||
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | |||
p->flags &= ~PF_ON_READQ; | |||
net_read(p, 0); | |||
} | |||
} | |||
if (net_bw_limit_out) { | |||
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | |||
} | |||
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | |||
} | |||
} else { | |||
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
net_write(p, 0); | |||
} | |||
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
net_write(p, 0); | |||
} | |||
} | |||
} | |||
@@ -547,12 +547,12 @@ net_read_cb(int sd, short type, void *arg) | |||
{ | |||
struct peer *p = (struct peer *)arg; | |||
if (net_bw_limit_in == 0) | |||
net_read(p, 0); | |||
net_read(p, 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 { | |||
p->flags |= PF_ON_READQ; | |||
BTPDQ_INSERT_TAIL(&net_bw_readq, p, rq_entry); | |||
p->flags |= PF_ON_READQ; | |||
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; | |||
if (type == EV_TIMEOUT) { | |||
btpd_log(BTPD_L_CONN, "Write attempt timed out.\n"); | |||
peer_kill(p); | |||
return; | |||
btpd_log(BTPD_L_CONN, "Write attempt timed out.\n"); | |||
peer_kill(p); | |||
return; | |||
} | |||
if (net_bw_limit_out == 0) { | |||
net_write(p, 0); | |||
net_write(p, 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 { | |||
p->flags |= PF_ON_WRITEQ; | |||
BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); | |||
p->flags |= PF_ON_WRITEQ; | |||
BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); | |||
} | |||
} | |||
@@ -583,13 +583,13 @@ net_init(void) | |||
int nfiles = getdtablesize(); | |||
if (nfiles <= 20) | |||
btpd_err("Too few open files allowed (%d). " | |||
"Check \"ulimit -n\"\n", nfiles); | |||
btpd_err("Too few open files allowed (%d). " | |||
"Check \"ulimit -n\"\n", nfiles); | |||
else if (nfiles < 64) | |||
btpd_log(BTPD_L_BTPD, | |||
"You have restricted the number of open files to %d. " | |||
"More could be beneficial to the download performance.\n", | |||
nfiles); | |||
btpd_log(BTPD_L_BTPD, | |||
"You have restricted the number of open files to %d. " | |||
"More could be beneficial to the download performance.\n", | |||
nfiles); | |||
net_max_peers = nfiles - 20; | |||
int sd; | |||
@@ -600,10 +600,10 @@ net_init(void) | |||
addr.sin_port = htons(net_port); | |||
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)); | |||
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); | |||
set_nonblocking(sd); | |||
@@ -1,15 +1,15 @@ | |||
#ifndef BTPD_NET_H | |||
#define BTPD_NET_H | |||
#define MSG_CHOKE 0 | |||
#define MSG_UNCHOKE 1 | |||
#define MSG_INTEREST 2 | |||
#define MSG_UNINTEREST 3 | |||
#define MSG_HAVE 4 | |||
#define MSG_BITFIELD 5 | |||
#define MSG_REQUEST 6 | |||
#define MSG_PIECE 7 | |||
#define MSG_CANCEL 8 | |||
#define MSG_CHOKE 0 | |||
#define MSG_UNCHOKE 1 | |||
#define MSG_INTEREST 2 | |||
#define MSG_UNINTEREST 3 | |||
#define MSG_HAVE 4 | |||
#define MSG_BITFIELD 5 | |||
#define MSG_REQUEST 6 | |||
#define MSG_PIECE 7 | |||
#define MSG_CANCEL 8 | |||
#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); | |||
for (uint32_t i = 0, count = 0; count < tp->have_npieces; i++) { | |||
if (has_bit(tp->piece_field, i)) { | |||
net_write32(out->buf + count * 9, 5); | |||
out->buf[count * 9 + 4] = MSG_HAVE; | |||
net_write32(out->buf + count * 9 + 5, i); | |||
count++; | |||
} | |||
if (has_bit(tp->piece_field, i)) { | |||
net_write32(out->buf + count * 9, 5); | |||
out->buf[count * 9 + 4] = MSG_HAVE; | |||
net_write32(out->buf + count * 9 + 5, i); | |||
count++; | |||
} | |||
} | |||
return out; | |||
} | |||
@@ -137,7 +137,7 @@ struct net_buf * | |||
nb_create_unchoke(void) | |||
{ | |||
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; | |||
} | |||
@@ -145,7 +145,7 @@ struct net_buf * | |||
nb_create_choke(void) | |||
{ | |||
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; | |||
} | |||
@@ -153,8 +153,8 @@ struct net_buf * | |||
nb_create_uninterest(void) | |||
{ | |||
if (m_uninterest == NULL) | |||
m_uninterest = | |||
nb_singleton(nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST)); | |||
m_uninterest = | |||
nb_singleton(nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST)); | |||
return m_uninterest; | |||
} | |||
@@ -162,8 +162,8 @@ struct net_buf * | |||
nb_create_interest(void) | |||
{ | |||
if (m_interest == NULL) | |||
m_interest = | |||
nb_singleton(nb_create_onesized(MSG_INTEREST, NB_INTEREST)); | |||
m_interest = | |||
nb_singleton(nb_create_onesized(MSG_INTEREST, NB_INTEREST)); | |||
return m_interest; | |||
} | |||
@@ -183,7 +183,7 @@ nb_create_bitdata(struct torrent *tp) | |||
{ | |||
uint32_t plen = ceil(tp->meta.npieces / 8.0); | |||
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; | |||
} | |||
@@ -205,9 +205,9 @@ nb_get_index(struct net_buf *nb) | |||
case NB_HAVE: | |||
case NB_PIECE: | |||
case NB_REQUEST: | |||
return net_read32(nb->buf + 5); | |||
return net_read32(nb->buf + 5); | |||
default: | |||
abort(); | |||
abort(); | |||
} | |||
} | |||
@@ -218,9 +218,9 @@ nb_get_begin(struct net_buf *nb) | |||
case NB_CANCEL: | |||
case NB_PIECE: | |||
case NB_REQUEST: | |||
return net_read32(nb->buf + 9); | |||
return net_read32(nb->buf + 9); | |||
default: | |||
abort(); | |||
abort(); | |||
} | |||
} | |||
@@ -230,11 +230,11 @@ nb_get_length(struct net_buf *nb) | |||
switch (nb->type) { | |||
case NB_CANCEL: | |||
case NB_REQUEST: | |||
return net_read32(nb->buf + 13); | |||
return net_read32(nb->buf + 13); | |||
case NB_PIECE: | |||
return net_read32(nb->buf) - 9; | |||
return net_read32(nb->buf) - 9; | |||
default: | |||
abort(); | |||
abort(); | |||
} | |||
} | |||
@@ -244,11 +244,11 @@ nb_drop(struct net_buf *nb) | |||
assert(nb->refs > 0); | |||
nb->refs--; | |||
if (nb->refs == 0) { | |||
nb->kill_buf(nb->buf, nb->len); | |||
free(nb); | |||
return 1; | |||
nb->kill_buf(nb->buf, nb->len); | |||
free(nb); | |||
return 1; | |||
} else | |||
return 0; | |||
return 0; | |||
} | |||
void | |||
@@ -1,19 +1,19 @@ | |||
#ifndef BTPD_NET_BUF_H | |||
#define BTPD_NET_BUF_H | |||
#define NB_CHOKE 0 | |||
#define NB_UNCHOKE 1 | |||
#define NB_INTEREST 2 | |||
#define NB_UNINTEREST 3 | |||
#define NB_HAVE 4 | |||
#define NB_BITFIELD 5 | |||
#define NB_REQUEST 6 | |||
#define NB_PIECE 7 | |||
#define NB_CANCEL 8 | |||
#define NB_TORRENTDATA 10 | |||
#define NB_MULTIHAVE 11 | |||
#define NB_BITDATA 12 | |||
#define NB_SHAKE 13 | |||
#define NB_CHOKE 0 | |||
#define NB_UNCHOKE 1 | |||
#define NB_INTEREST 2 | |||
#define NB_UNINTEREST 3 | |||
#define NB_HAVE 4 | |||
#define NB_BITFIELD 5 | |||
#define NB_REQUEST 6 | |||
#define NB_PIECE 7 | |||
#define NB_CANCEL 8 | |||
#define NB_TORRENTDATA 10 | |||
#define NB_MULTIHAVE 11 | |||
#define NB_BITDATA 12 | |||
#define NB_SHAKE 13 | |||
struct net_buf { | |||
short type; | |||
@@ -18,13 +18,13 @@ peer_kill(struct peer *p) | |||
if (p->flags & PF_ATTACHED) { | |||
ul_on_lost_peer(p); | |||
dl_on_lost_peer(p); | |||
dl_on_lost_peer(p); | |||
} else | |||
BTPDQ_REMOVE(&net_unattached, p, p_entry); | |||
BTPDQ_REMOVE(&net_unattached, p, p_entry); | |||
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) | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
close(p->sd); | |||
event_del(&p->in_ev); | |||
@@ -32,14 +32,14 @@ peer_kill(struct peer *p) | |||
nl = BTPDQ_FIRST(&p->outq); | |||
while (nl != NULL) { | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
nb_drop(nl->nb); | |||
free(nl); | |||
nl = next; | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
nb_drop(nl->nb); | |||
free(nl); | |||
nl = next; | |||
} | |||
if (p->net.buf != NULL) | |||
free(p->net.buf); | |||
free(p->net.buf); | |||
if (p->piece_field != NULL) | |||
free(p->piece_field); | |||
free(p); | |||
@@ -54,8 +54,8 @@ peer_send(struct peer *p, struct net_buf *nb) | |||
nb_hold(nb); | |||
if (BTPDQ_EMPTY(&p->outq)) { | |||
assert(p->outq_off == 0); | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
assert(p->outq_off == 0); | |||
event_add(&p->out_ev, WRITE_TIMEOUT); | |||
} | |||
BTPDQ_INSERT_TAIL(&p->outq, nl, entry); | |||
} | |||
@@ -71,23 +71,23 @@ int | |||
peer_unsend(struct peer *p, struct nb_link *nl) | |||
{ | |||
if (!(nl == BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) { | |||
BTPDQ_REMOVE(&p->outq, nl, entry); | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
assert(p->npiece_msgs > 0); | |||
p->npiece_msgs--; | |||
} | |||
nb_drop(nl->nb); | |||
free(nl); | |||
if (BTPDQ_EMPTY(&p->outq)) { | |||
if (p->flags & PF_ON_WRITEQ) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
} else | |||
event_del(&p->out_ev); | |||
} | |||
return 1; | |||
BTPDQ_REMOVE(&p->outq, nl, entry); | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
assert(p->npiece_msgs > 0); | |||
p->npiece_msgs--; | |||
} | |||
nb_drop(nl->nb); | |||
free(nl); | |||
if (BTPDQ_EMPTY(&p->outq)) { | |||
if (p->flags & PF_ON_WRITEQ) { | |||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | |||
p->flags &= ~PF_ON_WRITEQ; | |||
} else | |||
event_del(&p->out_ev); | |||
} | |||
return 1; | |||
} else | |||
return 0; | |||
return 0; | |||
} | |||
void | |||
@@ -95,51 +95,51 @@ peer_sent(struct peer *p, struct net_buf *nb) | |||
{ | |||
switch (nb->type) { | |||
case NB_CHOKE: | |||
btpd_log(BTPD_L_MSG, "sent choke to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent choke to %p\n", p); | |||
break; | |||
case NB_UNCHOKE: | |||
btpd_log(BTPD_L_MSG, "sent unchoke to %p\n", p); | |||
p->flags &= ~PF_NO_REQUESTS; | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent unchoke to %p\n", p); | |||
p->flags &= ~PF_NO_REQUESTS; | |||
break; | |||
case NB_INTEREST: | |||
btpd_log(BTPD_L_MSG, "sent interest to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent interest to %p\n", p); | |||
break; | |||
case NB_UNINTEREST: | |||
btpd_log(BTPD_L_MSG, "sent uninterest to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent uninterest to %p\n", p); | |||
break; | |||
case NB_HAVE: | |||
btpd_log(BTPD_L_MSG, "sent have(%u) to %p\n", | |||
nb_get_index(nb), p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent have(%u) to %p\n", | |||
nb_get_index(nb), p); | |||
break; | |||
case NB_BITFIELD: | |||
btpd_log(BTPD_L_MSG, "sent bitfield to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent bitfield to %p\n", p); | |||
break; | |||
case NB_REQUEST: | |||
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); | |||
break; | |||
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); | |||
break; | |||
case NB_PIECE: | |||
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); | |||
break; | |||
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); | |||
break; | |||
case NB_CANCEL: | |||
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); | |||
break; | |||
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); | |||
break; | |||
case NB_TORRENTDATA: | |||
btpd_log(BTPD_L_MSG, "sent data to %p\n", p); | |||
assert(p->npiece_msgs > 0); | |||
p->npiece_msgs--; | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent data to %p\n", p); | |||
assert(p->npiece_msgs > 0); | |||
p->npiece_msgs--; | |||
break; | |||
case NB_MULTIHAVE: | |||
btpd_log(BTPD_L_MSG, "sent multihave to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent multihave to %p\n", p); | |||
break; | |||
case NB_BITDATA: | |||
btpd_log(BTPD_L_MSG, "sent bitdata to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent bitdata to %p\n", p); | |||
break; | |||
case NB_SHAKE: | |||
btpd_log(BTPD_L_MSG, "sent shake to %p\n", p); | |||
break; | |||
btpd_log(BTPD_L_MSG, "sent shake to %p\n", p); | |||
break; | |||
} | |||
} | |||
@@ -157,8 +157,8 @@ peer_requested(struct peer *p, struct block *blk) | |||
{ | |||
struct block_request *req; | |||
BTPDQ_FOREACH(req, &p->my_reqs, p_entry) | |||
if (req->blk == blk) | |||
return 1; | |||
if (req->blk == blk) | |||
return 1; | |||
return 0; | |||
} | |||
@@ -171,15 +171,15 @@ peer_cancel(struct peer *p, struct block_request *req, struct net_buf *nb) | |||
int removed = 0; | |||
struct nb_link *nl; | |||
BTPDQ_FOREACH(nl, &p->outq, entry) { | |||
if (nl->nb == req->blk->msg) { | |||
removed = peer_unsend(p, nl); | |||
break; | |||
} | |||
if (nl->nb == req->blk->msg) { | |||
removed = peer_unsend(p, nl); | |||
break; | |||
} | |||
} | |||
if (!removed) | |||
peer_send(p, nb); | |||
peer_send(p, nb); | |||
if (p->nreqs_out == 0) | |||
peer_on_no_reqs(p); | |||
peer_on_no_reqs(p); | |||
} | |||
void | |||
@@ -194,14 +194,14 @@ peer_choke(struct peer *p) | |||
{ | |||
struct nb_link *nl = BTPDQ_FIRST(&p->outq); | |||
while (nl != NULL) { | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
if (nl->nb->type == NB_PIECE) { | |||
struct nb_link *data = next; | |||
next = BTPDQ_NEXT(next, entry); | |||
if (peer_unsend(p, nl)) | |||
peer_unsend(p, data); | |||
} | |||
nl = next; | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
if (nl->nb->type == NB_PIECE) { | |||
struct nb_link *data = next; | |||
next = BTPDQ_NEXT(next, entry); | |||
if (peer_unsend(p, nl)) | |||
peer_unsend(p, data); | |||
} | |||
nl = next; | |||
} | |||
p->flags |= PF_I_CHOKE; | |||
@@ -214,19 +214,19 @@ peer_want(struct peer *p, uint32_t index) | |||
assert(p->nwant < p->npieces); | |||
p->nwant++; | |||
if (p->nwant == 1) { | |||
if (p->nreqs_out == 0) { | |||
assert((p->flags & PF_DO_UNWANT) == 0); | |||
int unsent = 0; | |||
struct nb_link *nl = BTPDQ_LAST(&p->outq, nb_tq); | |||
if (nl != NULL && nl->nb->type == NB_UNINTEREST) | |||
unsent = peer_unsend(p, nl); | |||
if (!unsent) | |||
peer_send(p, nb_create_interest()); | |||
} else { | |||
assert((p->flags & PF_DO_UNWANT) != 0); | |||
p->flags &= ~PF_DO_UNWANT; | |||
} | |||
p->flags |= PF_I_WANT; | |||
if (p->nreqs_out == 0) { | |||
assert((p->flags & PF_DO_UNWANT) == 0); | |||
int unsent = 0; | |||
struct nb_link *nl = BTPDQ_LAST(&p->outq, nb_tq); | |||
if (nl != NULL && nl->nb->type == NB_UNINTEREST) | |||
unsent = peer_unsend(p, nl); | |||
if (!unsent) | |||
peer_send(p, nb_create_interest()); | |||
} else { | |||
assert((p->flags & PF_DO_UNWANT) != 0); | |||
p->flags &= ~PF_DO_UNWANT; | |||
} | |||
p->flags |= PF_I_WANT; | |||
} | |||
} | |||
@@ -236,11 +236,11 @@ peer_unwant(struct peer *p, uint32_t index) | |||
assert(p->nwant > 0); | |||
p->nwant--; | |||
if (p->nwant == 0) { | |||
p->flags &= ~PF_I_WANT; | |||
if (p->nreqs_out == 0) | |||
peer_send(p, nb_create_uninterest()); | |||
else | |||
p->flags |= PF_DO_UNWANT; | |||
p->flags &= ~PF_I_WANT; | |||
if (p->nreqs_out == 0) | |||
peer_send(p, nb_create_uninterest()); | |||
else | |||
p->flags |= PF_DO_UNWANT; | |||
} | |||
} | |||
@@ -280,7 +280,7 @@ peer_create_out(struct torrent *tp, const uint8_t *id, | |||
struct peer *p; | |||
if (net_connect(ip, port, &sd) != 0) | |||
return; | |||
return; | |||
p = peer_create_common(sd); | |||
p->tp = tp; | |||
@@ -299,7 +299,7 @@ peer_create_out_compact(struct torrent *tp, const char *compact) | |||
addr.sin_port = *(short *)(compact + 4); | |||
if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0) | |||
return; | |||
return; | |||
p = peer_create_common(sd); | |||
p->tp = tp; | |||
@@ -310,9 +310,9 @@ void | |||
peer_on_no_reqs(struct peer *p) | |||
{ | |||
if ((p->flags & PF_DO_UNWANT) != 0) { | |||
assert(p->nwant == 0); | |||
p->flags &= ~PF_DO_UNWANT; | |||
peer_send(p, nb_create_uninterest()); | |||
assert(p->nwant == 0); | |||
p->flags &= ~PF_DO_UNWANT; | |||
peer_send(p, nb_create_uninterest()); | |||
} | |||
} | |||
@@ -328,7 +328,7 @@ peer_on_shake(struct peer *p) | |||
uint8_t printid[21]; | |||
int i; | |||
for (i = 0; i < 20 && isprint(p->id[i]); i++) | |||
printid[i] = p->id[i]; | |||
printid[i] = p->id[i]; | |||
printid[i] = '\0'; | |||
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)); | |||
@@ -349,19 +349,19 @@ peer_on_choke(struct peer *p) | |||
{ | |||
btpd_log(BTPD_L_MSG, "received choke from %p\n", p); | |||
if ((p->flags & PF_P_CHOKE) != 0) | |||
return; | |||
return; | |||
else { | |||
if (p->nreqs_out > 0) | |||
peer_on_no_reqs(p); | |||
p->flags |= PF_P_CHOKE; | |||
dl_on_choke(p); | |||
struct nb_link *nl = BTPDQ_FIRST(&p->outq); | |||
while (nl != NULL) { | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
if (nl->nb->type == NB_REQUEST) | |||
peer_unsend(p, nl); | |||
nl = next; | |||
} | |||
if (p->nreqs_out > 0) | |||
peer_on_no_reqs(p); | |||
p->flags |= PF_P_CHOKE; | |||
dl_on_choke(p); | |||
struct nb_link *nl = BTPDQ_FIRST(&p->outq); | |||
while (nl != NULL) { | |||
struct nb_link *next = BTPDQ_NEXT(nl, entry); | |||
if (nl->nb->type == NB_REQUEST) | |||
peer_unsend(p, nl); | |||
nl = next; | |||
} | |||
} | |||
} | |||
@@ -370,10 +370,10 @@ peer_on_unchoke(struct peer *p) | |||
{ | |||
btpd_log(BTPD_L_MSG, "received unchoke from %p\n", p); | |||
if ((p->flags & PF_P_CHOKE) == 0) | |||
return; | |||
return; | |||
else { | |||
p->flags &= ~PF_P_CHOKE; | |||
dl_on_unchoke(p); | |||
p->flags &= ~PF_P_CHOKE; | |||
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); | |||
if ((p->flags & PF_P_WANT) != 0) | |||
return; | |||
return; | |||
else { | |||
p->flags |= PF_P_WANT; | |||
ul_on_interest(p); | |||
p->flags |= PF_P_WANT; | |||
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); | |||
if ((p->flags & PF_P_WANT) == 0) | |||
return; | |||
return; | |||
else { | |||
p->flags &= ~PF_P_WANT; | |||
ul_on_uninterest(p); | |||
p->flags &= ~PF_P_WANT; | |||
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); | |||
if (!has_bit(p->piece_field, index)) { | |||
set_bit(p->piece_field, index); | |||
p->npieces++; | |||
dl_on_piece_ann(p, index); | |||
set_bit(p->piece_field, index); | |||
p->npieces++; | |||
dl_on_piece_ann(p, index); | |||
} | |||
} | |||
@@ -419,10 +419,10 @@ peer_on_bitfield(struct peer *p, const uint8_t *field) | |||
assert(p->npieces == 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++) { | |||
if (has_bit(p->piece_field, i)) { | |||
p->npieces++; | |||
dl_on_piece_ann(p, i); | |||
} | |||
if (has_bit(p->piece_field, i)) { | |||
p->npieces++; | |||
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; | |||
BTPDQ_FOREACH(req, &p->my_reqs, p_entry) | |||
if ((nb_get_begin(req->blk->msg) == begin && | |||
nb_get_index(req->blk->msg) == index && | |||
nb_get_length(req->blk->msg) == length)) | |||
break; | |||
if ((nb_get_begin(req->blk->msg) == begin && | |||
nb_get_index(req->blk->msg) == index && | |||
nb_get_length(req->blk->msg) == length)) | |||
break; | |||
if (req != NULL) { | |||
btpd_log(BTPD_L_MSG, "received piece(%u,%u,%u) from %p\n", | |||
index, begin, length, p); | |||
assert(p->nreqs_out > 0); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
dl_on_block(p, req, index, begin, length, data); | |||
if (p->nreqs_out == 0) | |||
peer_on_no_reqs(p); | |||
btpd_log(BTPD_L_MSG, "received piece(%u,%u,%u) from %p\n", | |||
index, begin, length, p); | |||
assert(p->nreqs_out > 0); | |||
p->nreqs_out--; | |||
BTPDQ_REMOVE(&p->my_reqs, req, p_entry); | |||
dl_on_block(p, req, index, begin, length, data); | |||
if (p->nreqs_out == 0) | |||
peer_on_no_reqs(p); | |||
} else | |||
btpd_log(BTPD_L_MSG, "discarded piece(%u,%u,%u) from %p\n", | |||
index, begin, length, p); | |||
btpd_log(BTPD_L_MSG, "discarded piece(%u,%u,%u) from %p\n", | |||
index, begin, length, p); | |||
} | |||
void | |||
@@ -455,18 +455,18 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length) | |||
{ | |||
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) { | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
char * content = torrent_get_bytes(p->tp, cbegin, length); | |||
peer_send(p, nb_create_piece(index, begin, length)); | |||
peer_send(p, nb_create_torrentdata(content, length)); | |||
p->npiece_msgs++; | |||
if (p->npiece_msgs >= MAXPIECEMSGS) { | |||
peer_send(p, nb_create_choke()); | |||
peer_send(p, nb_create_unchoke()); | |||
p->flags |= PF_NO_REQUESTS; | |||
} | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
char * content = torrent_get_bytes(p->tp, cbegin, length); | |||
peer_send(p, nb_create_piece(index, begin, length)); | |||
peer_send(p, nb_create_torrentdata(content, length)); | |||
p->npiece_msgs++; | |||
if (p->npiece_msgs >= MAXPIECEMSGS) { | |||
peer_send(p, nb_create_choke()); | |||
peer_send(p, nb_create_unchoke()); | |||
p->flags |= PF_NO_REQUESTS; | |||
} | |||
} | |||
} | |||
@@ -475,18 +475,18 @@ peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length) | |||
{ | |||
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; | |||
BTPDQ_FOREACH(nl, &p->outq, entry) | |||
if (nl->nb->type == NB_PIECE | |||
&& nb_get_begin(nl->nb) == begin | |||
&& nb_get_index(nl->nb) == index | |||
&& nb_get_length(nl->nb) == length) { | |||
struct nb_link *data = BTPDQ_NEXT(nl, entry); | |||
if (peer_unsend(p, nl)) | |||
peer_unsend(p, data); | |||
break; | |||
} | |||
if (nl->nb->type == NB_PIECE | |||
&& nb_get_begin(nl->nb) == begin | |||
&& nb_get_index(nl->nb) == index | |||
&& nb_get_length(nl->nb) == length) { | |||
struct nb_link *data = BTPDQ_NEXT(nl, entry); | |||
if (peer_unsend(p, nl)) | |||
peer_unsend(p, data); | |||
break; | |||
} | |||
} | |||
int | |||
@@ -529,5 +529,5 @@ int | |||
peer_active_up(struct peer *p) | |||
{ | |||
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 | |||
#define BTPD_PEER_H | |||
#define PF_I_WANT 0x1 /* We want to download from 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_CHOKE 0x8 /* The peer is choking us */ | |||
#define PF_ON_READQ 0x10 | |||
#define PF_ON_WRITEQ 0x20 | |||
#define PF_ATTACHED 0x40 | |||
#define PF_NO_REQUESTS 0x80 | |||
#define PF_INCOMING 0x100 | |||
#define PF_DO_UNWANT 0x200 | |||
#define PF_I_WANT 0x1 /* We want to download from 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_CHOKE 0x8 /* The peer is choking us */ | |||
#define PF_ON_READQ 0x10 | |||
#define PF_ON_WRITEQ 0x20 | |||
#define PF_ATTACHED 0x40 | |||
#define PF_NO_REQUESTS 0x80 | |||
#define PF_INCOMING 0x100 | |||
#define PF_DO_UNWANT 0x200 | |||
#define MAXPIECEMSGS 128 | |||
#define MAXPIPEDREQUESTS 10 | |||
@@ -52,8 +52,8 @@ struct peer { | |||
struct { | |||
uint32_t msg_len; | |||
uint8_t msg_num; | |||
uint32_t pc_index; | |||
uint32_t pc_begin; | |||
uint32_t pc_index; | |||
uint32_t pc_begin; | |||
enum net_state state; | |||
size_t st_bytes; | |||
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 $ | |||
*/ | |||
@@ -9,86 +9,86 @@ | |||
/* | |||
* Tail queue declarations. | |||
*/ | |||
#define BTPDQ_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *tqh_first; /* first element */ \ | |||
struct type **tqh_last; /* addr of last next element */ \ | |||
#define BTPDQ_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *tqh_first; /* first element */ \ | |||
struct type **tqh_last; /* addr of last next element */ \ | |||
} | |||
#define BTPDQ_HEAD_INITIALIZER(head) \ | |||
{ NULL, &(head).tqh_first } | |||
#define BTPDQ_HEAD_INITIALIZER(head) \ | |||
{ NULL, &(head).tqh_first } | |||
#define BTPDQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *tqe_next; /* next element */ \ | |||
struct type **tqe_prev; /* address of previous next element */ \ | |||
#define BTPDQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *tqe_next; /* 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) \ | |||
(*(((struct headname *)((head)->tqh_last))->tqh_last)) | |||
#define BTPDQ_LAST(head, headname) \ | |||
(*(((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) \ | |||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) | |||
#define BTPDQ_PREV(elm, headname, field) \ | |||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) | |||
#define BTPDQ_FOREACH(var, head, field) \ | |||
for ((var) = BTPDQ_FIRST((head)); \ | |||
(var); \ | |||
(var) = BTPDQ_NEXT((var), field)) | |||
#define BTPDQ_FOREACH(var, head, field) \ | |||
for ((var) = BTPDQ_FIRST((head)); \ | |||
(var); \ | |||
(var) = BTPDQ_NEXT((var), field)) | |||
#define BTPDQ_INIT(head) do { \ | |||
BTPDQ_FIRST((head)) = NULL; \ | |||
(head)->tqh_last = &BTPDQ_FIRST((head)); \ | |||
#define BTPDQ_INIT(head) do { \ | |||
BTPDQ_FIRST((head)) = NULL; \ | |||
(head)->tqh_last = &BTPDQ_FIRST((head)); \ | |||
} while (0) | |||
#define BTPDQ_INSERT_AFTER(head, listelm, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field) = BTPDQ_NEXT((listelm), field)) != NULL)\ | |||
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ | |||
&BTPDQ_NEXT((elm), field); \ | |||
else { \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
} \ | |||
BTPDQ_NEXT((listelm), field) = (elm); \ | |||
(elm)->field.tqe_prev = &BTPDQ_NEXT((listelm), field); \ | |||
#define BTPDQ_INSERT_AFTER(head, listelm, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field) = BTPDQ_NEXT((listelm), field)) != NULL)\ | |||
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ | |||
&BTPDQ_NEXT((elm), field); \ | |||
else { \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
} \ | |||
BTPDQ_NEXT((listelm), field) = (elm); \ | |||
(elm)->field.tqe_prev = &BTPDQ_NEXT((listelm), field); \ | |||
} while (0) | |||
#define BTPDQ_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ | |||
BTPDQ_NEXT((elm), field) = (listelm); \ | |||
*(listelm)->field.tqe_prev = (elm); \ | |||
(listelm)->field.tqe_prev = &BTPDQ_NEXT((elm), field); \ | |||
#define BTPDQ_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ | |||
BTPDQ_NEXT((elm), field) = (listelm); \ | |||
*(listelm)->field.tqe_prev = (elm); \ | |||
(listelm)->field.tqe_prev = &BTPDQ_NEXT((elm), field); \ | |||
} while (0) | |||
#define BTPDQ_INSERT_HEAD(head, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field) = BTPDQ_FIRST((head))) != NULL) \ | |||
BTPDQ_FIRST((head))->field.tqe_prev = \ | |||
&BTPDQ_NEXT((elm), field); \ | |||
else \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
BTPDQ_FIRST((head)) = (elm); \ | |||
(elm)->field.tqe_prev = &BTPDQ_FIRST((head)); \ | |||
#define BTPDQ_INSERT_HEAD(head, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field) = BTPDQ_FIRST((head))) != NULL) \ | |||
BTPDQ_FIRST((head))->field.tqe_prev = \ | |||
&BTPDQ_NEXT((elm), field); \ | |||
else \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
BTPDQ_FIRST((head)) = (elm); \ | |||
(elm)->field.tqe_prev = &BTPDQ_FIRST((head)); \ | |||
} while (0) | |||
#define BTPDQ_INSERT_TAIL(head, elm, field) do { \ | |||
BTPDQ_NEXT((elm), field) = NULL; \ | |||
(elm)->field.tqe_prev = (head)->tqh_last; \ | |||
*(head)->tqh_last = (elm); \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
#define BTPDQ_INSERT_TAIL(head, elm, field) do { \ | |||
BTPDQ_NEXT((elm), field) = NULL; \ | |||
(elm)->field.tqe_prev = (head)->tqh_last; \ | |||
*(head)->tqh_last = (elm); \ | |||
(head)->tqh_last = &BTPDQ_NEXT((elm), field); \ | |||
} while (0) | |||
#define BTPDQ_REMOVE(head, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field)) != NULL) \ | |||
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ | |||
(elm)->field.tqe_prev; \ | |||
else { \ | |||
(head)->tqh_last = (elm)->field.tqe_prev; \ | |||
} \ | |||
*(elm)->field.tqe_prev = BTPDQ_NEXT((elm), field); \ | |||
#define BTPDQ_REMOVE(head, elm, field) do { \ | |||
if ((BTPDQ_NEXT((elm), field)) != NULL) \ | |||
BTPDQ_NEXT((elm), field)->field.tqe_prev = \ | |||
(elm)->field.tqe_prev; \ | |||
else { \ | |||
(head)->tqh_last = (elm)->field.tqe_prev; \ | |||
} \ | |||
*(elm)->field.tqe_prev = BTPDQ_NEXT((elm), field); \ | |||
} while (0) | |||
#endif |
@@ -40,7 +40,7 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz) | |||
tp->relpath = strdup(file); | |||
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->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->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++) | |||
if (has_bit(tp->piece_field, i)) | |||
tp->have_npieces++; | |||
if (has_bit(tp->piece_field, i)) | |||
tp->have_npieces++; | |||
tp->meta = *mi; | |||
free(mi); | |||
@@ -80,38 +80,38 @@ torrent_load2(const char *name, struct metainfo *mi) | |||
const char *file = name; | |||
if ((error = vopen(&ifd, O_RDWR, "%s/resume", file)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
} | |||
if (fstat(ifd, &sb) == -1) { | |||
error = errno; | |||
btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n", | |||
file, strerror(error)); | |||
close(ifd); | |||
return error; | |||
error = errno; | |||
btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n", | |||
file, strerror(error)); | |||
close(ifd); | |||
return error; | |||
} | |||
memsiz = | |||
ceil(mi->npieces / 8.0) + | |||
mi->npieces * ceil(mi->piece_length / (double)(1 << 17)); | |||
ceil(mi->npieces / 8.0) + | |||
mi->npieces * ceil(mi->piece_length / (double)(1 << 17)); | |||
if (sb.st_size != memsiz) { | |||
btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file); | |||
close(ifd); | |||
return EINVAL; | |||
btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file); | |||
close(ifd); | |||
return EINVAL; | |||
} | |||
mem = mmap(NULL, memsiz, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); | |||
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); | |||
if ((error = torrent_load3(file, mi, mem, memsiz) != 0)) { | |||
munmap(mem, memsiz); | |||
return error; | |||
munmap(mem, memsiz); | |||
return error; | |||
} | |||
return 0; | |||
@@ -126,22 +126,22 @@ torrent_load(const char *name) | |||
snprintf(file, PATH_MAX, "%s/torrent", name); | |||
if ((error = load_metainfo(file, -1, 0, &mi)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
} | |||
if (btpd_get_torrent(mi->info_hash) != NULL) { | |||
btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); | |||
error = EEXIST; | |||
btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); | |||
error = EEXIST; | |||
} | |||
if (error == 0) | |||
error = torrent_load2(name, mi); | |||
error = torrent_load2(name, mi); | |||
if (error != 0) { | |||
clear_metainfo(mi); | |||
free(mi); | |||
clear_metainfo(mi); | |||
free(mi); | |||
} | |||
return error; | |||
@@ -171,14 +171,14 @@ off_t | |||
torrent_bytes_left(struct torrent *tp) | |||
{ | |||
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)) { | |||
return tp->meta.total_length - | |||
((tp->have_npieces - 1) * tp->meta.piece_length + | |||
tp->meta.total_length % tp->meta.piece_length); | |||
return tp->meta.total_length - | |||
((tp->have_npieces - 1) * tp->meta.piece_length + | |||
tp->meta.total_length % tp->meta.piece_length); | |||
} else | |||
return tp->meta.total_length - | |||
tp->have_npieces * tp->meta.piece_length; | |||
return tp->meta.total_length - | |||
tp->have_npieces * tp->meta.piece_length; | |||
} | |||
char * | |||
@@ -187,9 +187,9 @@ torrent_get_bytes(struct torrent *tp, off_t start, size_t len) | |||
char *buf = btpd_malloc(len); | |||
struct bt_stream_ro *bts; | |||
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) | |||
btpd_err("Io error.\n"); | |||
btpd_err("Io error.\n"); | |||
bts_close_ro(bts); | |||
return buf; | |||
} | |||
@@ -200,11 +200,11 @@ torrent_put_bytes(struct torrent *tp, const char *buf, off_t start, size_t len) | |||
int err; | |||
struct bt_stream_wo *bts; | |||
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) | |||
btpd_err("Io error1: %s\n", strerror(err)); | |||
btpd_err("Io error1: %s\n", strerror(err)); | |||
if ((err = bts_close_wo(bts)) != 0) | |||
btpd_err("Io error2: %s\n", strerror(err)); | |||
btpd_err("Io error2: %s\n", strerror(err)); | |||
} | |||
int | |||
@@ -213,11 +213,11 @@ torrent_has_peer(struct torrent *tp, const uint8_t *id) | |||
int has = 0; | |||
struct peer *p = BTPDQ_FIRST(&tp->peers); | |||
while (p != NULL) { | |||
if (bcmp(p->id, id, 20) == 0) { | |||
has = 1; | |||
break; | |||
} | |||
p = BTPDQ_NEXT(p, p_entry); | |||
if (bcmp(p->id, id, 20) == 0) { | |||
has = 1; | |||
break; | |||
} | |||
p = BTPDQ_NEXT(p, p_entry); | |||
} | |||
return has; | |||
} | |||
@@ -226,10 +226,10 @@ off_t | |||
torrent_piece_size(struct torrent *tp, uint32_t index) | |||
{ | |||
if (index < tp->meta.npieces - 1) | |||
return tp->meta.piece_length; | |||
return tp->meta.piece_length; | |||
else { | |||
off_t allbutlast = tp->meta.piece_length * (tp->meta.npieces - 1); | |||
return tp->meta.total_length - allbutlast; | |||
off_t allbutlast = tp->meta.piece_length * (tp->meta.npieces - 1); | |||
return tp->meta.total_length - allbutlast; | |||
} | |||
} | |||
@@ -237,10 +237,10 @@ uint32_t | |||
torrent_block_size(struct piece *pc, uint32_t index) | |||
{ | |||
if (index < pc->nblocks - 1) | |||
return PIECE_BLOCKLEN; | |||
return PIECE_BLOCKLEN; | |||
else { | |||
uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1); | |||
return torrent_piece_size(pc->tp, pc->index) - allbutlast; | |||
uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1); | |||
return torrent_piece_size(pc->tp, pc->index) - allbutlast; | |||
} | |||
} | |||
@@ -52,7 +52,7 @@ struct torrent { | |||
unsigned *piece_count; | |||
uint64_t uploaded, downloaded; | |||
unsigned npeers; | |||
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); | |||
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); | |||
@@ -38,28 +38,28 @@ maybe_connect_to(struct torrent *tp, const char *pinfo) | |||
size_t len; | |||
if (!benc_isdct(pinfo)) | |||
return; | |||
return; | |||
if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20) | |||
return; | |||
return; | |||
if (bcmp(btpd_get_peer_id(), pid, 20) == 0) | |||
return; | |||
return; | |||
if (torrent_has_peer(tp, pid)) | |||
return; | |||
return; | |||
if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0) | |||
goto out; | |||
goto out; | |||
if (benc_dget_int64(pinfo, "port", &port) != 0) | |||
goto out; | |||
goto out; | |||
peer_create_out(tp, pid, ip, port); | |||
out: | |||
if (ip != NULL) | |||
free(ip); | |||
free(ip); | |||
} | |||
static void | |||
@@ -73,31 +73,31 @@ tracker_done(pid_t pid, void *arg) | |||
struct torrent *tp; | |||
if ((tp = btpd_get_torrent(req->info_hash)) == NULL) | |||
goto out; | |||
goto out; | |||
if (benc_validate(req->res->buf, req->res->buf_off) != 0 | |||
|| !benc_isdct(req->res->buf)) { | |||
if (req->res->buf_off != 0) { | |||
fwrite(req->res->buf, 1, req->res->buf_off, (stdout)); | |||
putchar('\n'); | |||
} | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
|| !benc_isdct(req->res->buf)) { | |||
if (req->res->buf_off != 0) { | |||
fwrite(req->res->buf, 1, req->res->buf_off, (stdout)); | |||
putchar('\n'); | |||
} | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
} | |||
if ((benc_dget_strz(req->res->buf, "failure reason", &buf, NULL)) == 0) { | |||
btpd_log(BTPD_L_ERROR, "Tracker failure: %s.\n", buf); | |||
free(buf); | |||
failed = 1; | |||
goto out; | |||
btpd_log(BTPD_L_ERROR, "Tracker failure: %s.\n", buf); | |||
free(buf); | |||
failed = 1; | |||
goto out; | |||
} | |||
if ((benc_dget_uint32(req->res->buf, "interval", &interval)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
} | |||
//tp->tracker_time = btpd_seconds + interval; | |||
@@ -106,34 +106,34 @@ tracker_done(pid_t pid, void *arg) | |||
size_t length; | |||
if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { | |||
for (peers = benc_first(peers); | |||
peers != NULL && net_npeers < net_max_peers; | |||
peers = benc_next(peers)) | |||
maybe_connect_to(tp, peers); | |||
for (peers = benc_first(peers); | |||
peers != NULL && net_npeers < net_max_peers; | |||
peers = benc_next(peers)) | |||
maybe_connect_to(tp, peers); | |||
} | |||
if (error == EINVAL) { | |||
error = benc_dget_str(req->res->buf, "peers", &peers, &length); | |||
if (error == 0 && length % 6 == 0) { | |||
error = benc_dget_str(req->res->buf, "peers", &peers, &length); | |||
if (error == 0 && length % 6 == 0) { | |||
size_t i; | |||
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) { | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||
failed = 1; | |||
goto out; | |||
} | |||
out: | |||
if (failed) { | |||
if (req->tr_event == TR_STARTED) { | |||
btpd_log(BTPD_L_BTPD, | |||
"Start request failed for %s.\n", tp->relpath); | |||
torrent_unload(tp); | |||
} else | |||
if (req->tr_event == TR_STARTED) { | |||
btpd_log(BTPD_L_BTPD, | |||
"Start request failed for %s.\n", tp->relpath); | |||
torrent_unload(tp); | |||
} else | |||
;//tp->tracker_time = btpd_seconds + 10; | |||
} | |||
munmap(req->res, REQ_SIZE); | |||
@@ -145,16 +145,16 @@ event2str(enum tr_event ev) | |||
{ | |||
switch (ev) { | |||
case TR_STARTED: | |||
return "started"; | |||
return "started"; | |||
case TR_STOPPED: | |||
return "stopped"; | |||
return "stopped"; | |||
case TR_COMPLETED: | |||
return "completed"; | |||
return "completed"; | |||
case TR_EMPTY: | |||
return ""; | |||
return ""; | |||
default: | |||
btpd_err("Bad tracker event %d.\n", ev); | |||
return ""; // Shut GCC up! | |||
btpd_err("Bad tracker event %d.\n", ev); | |||
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) ? '?' : '&'; | |||
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++) | |||
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); | |||
i = asprintf(url, "%s%cinfo_hash=%s" | |||
"&peer_id=%s" | |||
"&port=%d" | |||
"&uploaded=%" PRIu64 | |||
"&downloaded=%" PRIu64 | |||
"&left=%" PRIu64 | |||
"&compact=1" | |||
"%s%s", | |||
tp->meta.announce, qc, e_hash, e_id, net_port, | |||
tp->uploaded, tp->downloaded, left, | |||
req->tr_event == TR_EMPTY ? "" : "&event=", | |||
event); | |||
"&peer_id=%s" | |||
"&port=%d" | |||
"&uploaded=%" PRIu64 | |||
"&downloaded=%" PRIu64 | |||
"&left=%" PRIu64 | |||
"&compact=1" | |||
"%s%s", | |||
tp->meta.announce, qc, e_hash, e_id, net_port, | |||
tp->uploaded, tp->downloaded, left, | |||
req->tr_event == TR_EMPTY ? "" : "&event=", | |||
event); | |||
if (i < 0) | |||
return ENOMEM; | |||
return ENOMEM; | |||
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; | |||
size_t nbytes = size * nmemb; | |||
if (nbytes <= req->res->buf_len - req->res->buf_off) { | |||
memcpy(req->res->buf + req->res->buf_off, ptr, nbytes); | |||
req->res->buf_off += nbytes; | |||
return nbytes; | |||
memcpy(req->res->buf + req->res->buf_off, ptr, nbytes); | |||
req->res->buf_off += nbytes; | |||
return nbytes; | |||
} | |||
else | |||
return 0; | |||
return 0; | |||
} | |||
static void | |||
@@ -222,31 +222,31 @@ http_helper(struct tracker_req *req, struct torrent *tp) | |||
int err; | |||
if (create_url(req, tp, &url) != 0) | |||
goto memory_error; | |||
goto memory_error; | |||
if (curl_global_init(0) != 0) | |||
goto libcurl_error; | |||
goto libcurl_error; | |||
if ((handle = curl_easy_init()) == NULL) | |||
goto libcurl_error; | |||
goto libcurl_error; | |||
err = curl_easy_setopt(handle, CURLOPT_URL, url); | |||
if (err == 0) | |||
err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION); | |||
err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION); | |||
if (err == 0) | |||
err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); | |||
err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); | |||
if (err == 0) | |||
err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, req); | |||
err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, req); | |||
if (err == 0) | |||
err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, cerror); | |||
err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, cerror); | |||
if (err != 0) { | |||
strncpy(cerror, curl_easy_strerror(err), CURL_ERROR_SIZE - 1); | |||
goto handle_error; | |||
strncpy(cerror, curl_easy_strerror(err), CURL_ERROR_SIZE - 1); | |||
goto handle_error; | |||
} | |||
req->res->buf_off = 0; | |||
if (curl_easy_perform(handle) != 0) | |||
goto handle_error; | |||
goto handle_error; | |||
#if 0 | |||
curl_easy_cleanup(handle); | |||
@@ -263,12 +263,12 @@ libcurl_error: | |||
strncpy(cerror, "Generic libcurl error", CURL_ERROR_SIZE - 1); | |||
goto handle_error; | |||
handle_error: | |||
handle_error: | |||
req->res->buf_off = | |||
snprintf(req->res->buf, req->res->buf_len, | |||
"d%d:%s%d:%se", (int)strlen(fr), fr, (int)strlen(cerror), cerror); | |||
snprintf(req->res->buf, req->res->buf_len, | |||
"d%d:%s%d:%se", (int)strlen(fr), fr, (int)strlen(cerror), cerror); | |||
if (req->res->buf_off >= req->res->buf_len) | |||
req->res->buf_off = 0; | |||
req->res->buf_off = 0; | |||
exit(1); | |||
} | |||
@@ -281,7 +281,7 @@ tracker_req(struct torrent *tp, enum tr_event tr_event) | |||
btpd_log(BTPD_L_TRACKER, | |||
"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)); | |||
@@ -289,7 +289,7 @@ tracker_req(struct torrent *tp, enum tr_event tr_event) | |||
MAP_ANON | MAP_SHARED, -1, 0); | |||
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_off = 0; | |||
@@ -302,12 +302,12 @@ tracker_req(struct torrent *tp, enum tr_event tr_event) | |||
pid = fork(); | |||
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 | |||
int nfiles = getdtablesize(); | |||
for (int i = 0; i < nfiles; i++) | |||
close(i); | |||
http_helper(req, tp); | |||
int nfiles = getdtablesize(); | |||
for (int i = 0; i < nfiles; i++) | |||
close(i); | |||
http_helper(req, tp); | |||
} 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; | |||
BTPDQ_FOREACH(p, &m_peerq, ul_entry) | |||
if (p->flags & PF_I_CHOKE) | |||
peer_unchoke(p); | |||
peer_unchoke(p); | |||
} | |||
static void | |||
@@ -36,7 +36,7 @@ ul_on_lost_peer(struct peer *p) | |||
BTPDQ_REMOVE(&m_peerq, p, ul_entry); | |||
m_npeers--; | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) | |||
choke_do(); | |||
choke_do(); | |||
} | |||
void | |||
@@ -44,8 +44,8 @@ ul_on_lost_torrent(struct torrent *tp) | |||
{ | |||
struct peer *p; | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||
BTPDQ_REMOVE(&m_peerq, p, ul_entry); | |||
m_npeers--; | |||
BTPDQ_REMOVE(&m_peerq, p, ul_entry); | |||
m_npeers--; | |||
} | |||
choke_do(); | |||
} | |||
@@ -54,14 +54,14 @@ void | |||
ul_on_interest(struct peer *p) | |||
{ | |||
if ((p->flags & PF_I_CHOKE) == 0) | |||
choke_do(); | |||
choke_do(); | |||
} | |||
void | |||
ul_on_uninterest(struct peer *p) | |||
{ | |||
if ((p->flags & PF_I_CHOKE) == 0) | |||
choke_do(); | |||
choke_do(); | |||
} | |||
void | |||
@@ -8,7 +8,7 @@ btpd_malloc(size_t size) | |||
{ | |||
void *a; | |||
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; | |||
} | |||
@@ -17,7 +17,7 @@ btpd_calloc(size_t nmemb, size_t size) | |||
{ | |||
void *a; | |||
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; | |||
} | |||
@@ -25,17 +25,17 @@ static const char * | |||
logtype_str(uint32_t type) | |||
{ | |||
if (type & BTPD_L_BTPD) | |||
return "btpd"; | |||
return "btpd"; | |||
else if (type & BTPD_L_ERROR) | |||
return "error"; | |||
return "error"; | |||
else if (type & BTPD_L_CONN) | |||
return "conn"; | |||
return "conn"; | |||
else if (type & BTPD_L_TRACKER) | |||
return "tracker"; | |||
return "tracker"; | |||
else if (type & BTPD_L_MSG) | |||
return "msg"; | |||
return "msg"; | |||
else | |||
return ""; | |||
return ""; | |||
} | |||
void | |||
@@ -44,11 +44,11 @@ btpd_err(const char *fmt, ...) | |||
va_list ap; | |||
va_start(ap, fmt); | |||
if (BTPD_L_ERROR & btpd_logmask) { | |||
char tbuf[20]; | |||
time_t tp = time(NULL); | |||
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); | |||
printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR)); | |||
vprintf(fmt, ap); | |||
char tbuf[20]; | |||
time_t tp = time(NULL); | |||
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); | |||
printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR)); | |||
vprintf(fmt, ap); | |||
} | |||
va_end(ap); | |||
exit(1); | |||
@@ -60,11 +60,11 @@ btpd_log(uint32_t type, const char *fmt, ...) | |||
va_list ap; | |||
va_start(ap, fmt); | |||
if (type & btpd_logmask) { | |||
char tbuf[20]; | |||
time_t tp = time(NULL); | |||
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); | |||
printf("%s %s: ", tbuf, logtype_str(type)); | |||
vprintf(fmt, ap); | |||
char tbuf[20]; | |||
time_t tp = time(NULL); | |||
strftime(tbuf, 20, "%b %e %T", localtime(&tp)); | |||
printf("%s %s: ", tbuf, logtype_str(type)); | |||
vprintf(fmt, ap); | |||
} | |||
va_end(ap); | |||
} |
@@ -24,16 +24,16 @@ static void | |||
usage() | |||
{ | |||
printf("Usage: btcli command [options] [files]\n" | |||
"Commands:\n" | |||
"add <file_1> ... [file_n]\n" | |||
"\tAdd the given torrents to btpd.\n" | |||
"\n" | |||
"del <file_1> ... [file_n]\n" | |||
"\tRemove the given torrents from btpd.\n" | |||
"\n" | |||
"die\n" | |||
"\tShut down btpd.\n" | |||
"\n" | |||
"Commands:\n" | |||
"add <file_1> ... [file_n]\n" | |||
"\tAdd the given torrents to btpd.\n" | |||
"\n" | |||
"del <file_1> ... [file_n]\n" | |||
"\tRemove the given torrents from btpd.\n" | |||
"\n" | |||
"die\n" | |||
"\tShut down btpd.\n" | |||
"\n" | |||
"list\n" | |||
"\tList active torrents.\n" | |||
"\n" | |||
@@ -47,13 +47,13 @@ usage() | |||
"-w n\n" | |||
"\tRepeat every n seconds.\n" | |||
"\n" | |||
"Common options:\n" | |||
"--ipc key\n" | |||
"\tTalk to the btpd started with the same key.\n" | |||
"\n" | |||
"--help\n" | |||
"\tShow this help.\n" | |||
"\n"); | |||
"Common options:\n" | |||
"--ipc key\n" | |||
"\tTalk to the btpd started with the same key.\n" | |||
"\n" | |||
"--help\n" | |||
"\tShow this help.\n" | |||
"\n"); | |||
exit(1); | |||
} | |||
@@ -62,12 +62,12 @@ handle_error(int error) | |||
{ | |||
switch (error) { | |||
case 0: | |||
break; | |||
break; | |||
case ENOENT: | |||
case ECONNREFUSED: | |||
errx(1, "Couldn't connect. Check that btpd is running."); | |||
errx(1, "Couldn't connect. Check that btpd is running."); | |||
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)) { | |||
case 0: | |||
break; | |||
break; | |||
case EINVAL: | |||
errx(1, "--ipc argument only takes letters and digits."); | |||
errx(1, "--ipc argument only takes letters and digits."); | |||
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; | |||
if (hash != NULL) | |||
if (bcmp(hash, cb->meta->piece_hash[index], SHA_DIGEST_LENGTH) == 0) { | |||
set_bit(cb->piece_field, index); | |||
if (bcmp(hash, cb->meta->piece_hash[index], SHA_DIGEST_LENGTH) == 0) { | |||
set_bit(cb->piece_field, index); | |||
cb->have++; | |||
} | |||
} | |||
printf("\rTested: %5.1f%%", 100.0 * (index + 1) / cb->meta->npieces); | |||
fflush(stdout); | |||
} | |||
@@ -120,7 +120,7 @@ gen_ifile(char *path) | |||
size_t field_len; | |||
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); | |||
cb.path = path; | |||
@@ -129,24 +129,24 @@ gen_ifile(char *path) | |||
cb.meta = mi; | |||
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) | |||
err(1, "bts_hashes"); | |||
err(1, "bts_hashes"); | |||
printf("\nHave: %5.1f%%\n", 100.0 * cb.have / cb.meta->npieces); | |||
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 * | |||
(off_t)ceil(mi->piece_length / (double)(1 << 17))) < 0) | |||
err(1, "ftruncate: %s", path); | |||
(off_t)ceil(mi->piece_length / (double)(1 << 17))) < 0) | |||
err(1, "ftruncate: %s", path); | |||
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) | |||
err(1, "close %s.i", path); | |||
err(1, "close %s.i", path); | |||
clear_metainfo(mi); | |||
free(mi); | |||
@@ -173,45 +173,45 @@ cmd_add(int argc, char **argv) | |||
int ch; | |||
char *ipctok = NULL; | |||
while ((ch = getopt_long(argc, argv, "", add_opts, NULL)) != -1) { | |||
switch(ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
switch(ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
} | |||
argc -= optind; | |||
argv += optind; | |||
if (argc < 1) | |||
usage(); | |||
usage(); | |||
for (int i = 0; i < argc; i++) { | |||
int64_t code; | |||
char *res; | |||
int fd; | |||
char *path; | |||
errno = vopen(&fd, O_RDONLY, "%s.i", argv[i]); | |||
if (errno == ENOENT) { | |||
printf("Testing %s for content.\n", argv[i]); | |||
gen_ifile(argv[i]); | |||
} else if (errno != 0) | |||
err(1, "open %s.i", argv[i]); | |||
else | |||
close(fd); | |||
if ((errno = canon_path(argv[i], &path)) != 0) | |||
err(1, "canon_path"); | |||
do_add(ipctok, &path, 1, &res); | |||
free(path); | |||
benc_dget_int64(benc_first(res), "code", &code); | |||
if (code == EEXIST) | |||
printf("btpd already had %s.\n", argv[i]); | |||
else if (code != 0) { | |||
printf("btpd indicates error: %s for %s.\n", | |||
strerror(code), argv[i]); | |||
} | |||
int64_t code; | |||
char *res; | |||
int fd; | |||
char *path; | |||
errno = vopen(&fd, O_RDONLY, "%s.i", argv[i]); | |||
if (errno == ENOENT) { | |||
printf("Testing %s for content.\n", argv[i]); | |||
gen_ifile(argv[i]); | |||
} else if (errno != 0) | |||
err(1, "open %s.i", argv[i]); | |||
else | |||
close(fd); | |||
if ((errno = canon_path(argv[i], &path)) != 0) | |||
err(1, "canon_path"); | |||
do_add(ipctok, &path, 1, &res); | |||
free(path); | |||
benc_dget_int64(benc_first(res), "code", &code); | |||
if (code == EEXIST) | |||
printf("btpd already had %s.\n", argv[i]); | |||
else if (code != 0) { | |||
printf("btpd indicates error: %s for %s.\n", | |||
strerror(code), argv[i]); | |||
} | |||
free(res); | |||
} | |||
} | |||
@@ -237,45 +237,45 @@ cmd_del(int argc, char **argv) | |||
int ch; | |||
char *ipctok = NULL; | |||
while ((ch = getopt_long(argc, argv, "", del_opts, NULL)) != -1) { | |||
switch(ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
switch(ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
} | |||
argc -= optind; | |||
argv += optind; | |||
if (argc < 1) | |||
usage(); | |||
usage(); | |||
uint8_t hashes[argc][20]; | |||
char *res; | |||
const char *d; | |||
for (int i = 0; i < argc; i++) { | |||
struct metainfo *mi; | |||
if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0) | |||
err(1, "load_metainfo: %s", argv[i]); | |||
bcopy(mi->info_hash, hashes[i], 20); | |||
clear_metainfo(mi); | |||
free(mi); | |||
struct metainfo *mi; | |||
if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0) | |||
err(1, "load_metainfo: %s", argv[i]); | |||
bcopy(mi->info_hash, hashes[i], 20); | |||
clear_metainfo(mi); | |||
free(mi); | |||
} | |||
do_del(ipctok, hashes, argc, &res); | |||
d = benc_first(res); | |||
for (int i = 0; i < argc; i++) { | |||
int64_t code; | |||
benc_dget_int64(d, "code", &code); | |||
if (code == ENOENT) | |||
printf("btpd didn't have %s.\n", argv[i]); | |||
else if (code != 0) { | |||
printf("btpd indicates error: %s for %s.\n", | |||
strerror(code), argv[i]); | |||
} | |||
d = benc_next(d); | |||
int64_t code; | |||
benc_dget_int64(d, "code", &code); | |||
if (code == ENOENT) | |||
printf("btpd didn't have %s.\n", argv[i]); | |||
else if (code != 0) { | |||
printf("btpd indicates error: %s for %s.\n", | |||
strerror(code), argv[i]); | |||
} | |||
d = benc_next(d); | |||
} | |||
free(res); | |||
} | |||
@@ -302,13 +302,13 @@ cmd_die(int argc, char **argv) | |||
char *ipctok = NULL; | |||
while ((ch = getopt_long(argc, argv, "", die_opts, NULL)) != -1) { | |||
switch (ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
switch (ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
} | |||
do_die(ipctok); | |||
} | |||
@@ -420,14 +420,14 @@ grok_stat(char *ipctok, int iflag, int wait, | |||
again: | |||
do_stat(ipctok, &res); | |||
gettimeofday(&tv_cur, NULL); | |||
if (old == NULL) | |||
ds = wait; | |||
if (old == NULL) | |||
ds = wait; | |||
else { | |||
struct timeval delta; | |||
timersub(&tv_old, &tv_cur, &delta); | |||
ds = delta.tv_sec + delta.tv_usec / 1000000.0; | |||
if (ds < 0) | |||
ds = wait; | |||
struct timeval delta; | |||
timersub(&tv_old, &tv_cur, &delta); | |||
ds = delta.tv_sec + delta.tv_usec / 1000000.0; | |||
if (ds < 0) | |||
ds = wait; | |||
} | |||
tv_old = tv_cur; | |||
cur = parse_tors(res, hashes, nhashes); | |||
@@ -484,7 +484,7 @@ cmd_stat(int argc, char **argv) | |||
int iflag = 0; | |||
while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) { | |||
switch (ch) { | |||
switch (ch) { | |||
case 'i': | |||
iflag = 1; | |||
break; | |||
@@ -493,12 +493,12 @@ cmd_stat(int argc, char **argv) | |||
if (wait <= 0) | |||
errx(1, "-w argument must be an integer > 0."); | |||
break; | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
} | |||
argc -= optind; | |||
argv += optind; | |||
@@ -531,13 +531,13 @@ cmd_list(int argc, char **argv) | |||
char *ipctok = NULL; | |||
while ((ch = getopt_long(argc, argv, "", list_opts, NULL)) != -1) { | |||
switch (ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
switch (ch) { | |||
case 1: | |||
ipctok = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
} | |||
char *res; | |||
const char *p; | |||
@@ -572,18 +572,18 @@ int | |||
main(int argc, char **argv) | |||
{ | |||
if (argc < 2) | |||
usage(); | |||
usage(); | |||
int found = 0; | |||
for (int i = 0; !found && i < ncmds; i++) { | |||
if (strcmp(argv[1], cmd_table[i].name) == 0) { | |||
found = 1; | |||
cmd_table[i].fun(argc - 1, argv + 1); | |||
} | |||
if (strcmp(argv[1], cmd_table[i].name) == 0) { | |||
found = 1; | |||
cmd_table[i].fun(argc - 1, argv + 1); | |||
} | |||
} | |||
if (!found) | |||
usage(); | |||
usage(); | |||
return 0; | |||
} |
@@ -27,26 +27,26 @@ main(int argc, char **argv) | |||
int ch; | |||
while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) | |||
usage(); | |||
usage(); | |||
argc -= optind; | |||
argv += optind; | |||
if (argc < 1) | |||
usage(); | |||
usage(); | |||
while (argc > 0) { | |||
struct metainfo *mi; | |||
struct metainfo *mi; | |||
if ((errno = load_metainfo(*argv, -1, 1, &mi)) != 0) | |||
err(1, "load_metainfo: %s", *argv); | |||
if ((errno = load_metainfo(*argv, -1, 1, &mi)) != 0) | |||
err(1, "load_metainfo: %s", *argv); | |||
print_metainfo(mi); | |||
clear_metainfo(mi); | |||
free(mi); | |||
print_metainfo(mi); | |||
clear_metainfo(mi); | |||
free(mi); | |||
argc--; | |||
argv++; | |||
argc--; | |||
argv++; | |||
} | |||
return 0; | |||
@@ -19,21 +19,21 @@ ipc_open(const char *key, struct ipc **out) | |||
struct ipc *res; | |||
if (key == NULL) | |||
key = "default"; | |||
key = "default"; | |||
keylen = strlen(key); | |||
for (int i = 0; i < keylen; i++) | |||
if (!isalnum(key[i])) | |||
return EINVAL; | |||
if (!isalnum(key[i])) | |||
return EINVAL; | |||
res = malloc(sizeof(*res)); | |||
if (res == NULL) | |||
return ENOMEM; | |||
return ENOMEM; | |||
plen = sizeof(res->addr.sun_path); | |||
if (snprintf(res->addr.sun_path, plen, | |||
"/tmp/btpd_%u_%s", geteuid(), key) >= plen) { | |||
free(res); | |||
return ENAMETOOLONG; | |||
"/tmp/btpd_%u_%s", geteuid(), key) >= plen) { | |||
free(res); | |||
return ENAMETOOLONG; | |||
} | |||
res->addr.sun_family = AF_UNIX; | |||
*out = res; | |||
@@ -55,13 +55,13 @@ ipc_connect(struct ipc *ipc, FILE **out) | |||
int error; | |||
if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) | |||
return errno; | |||
return errno; | |||
if (connect(sd, (struct sockaddr *)&ipc->addr, sizeof(ipc->addr)) == -1) | |||
goto error; | |||
goto error; | |||
if ((fp = fdopen(sd, "r+")) == NULL) | |||
goto error; | |||
goto error; | |||
*out = fp; | |||
return 0; | |||
@@ -78,23 +78,23 @@ ipc_response(FILE *fp, char **out, uint32_t *len) | |||
char *buf; | |||
if (fread(&size, sizeof(size), 1, fp) != 1) { | |||
if (ferror(fp)) | |||
return errno; | |||
else | |||
return ECONNRESET; | |||
if (ferror(fp)) | |||
return errno; | |||
else | |||
return ECONNRESET; | |||
} | |||
if (size == 0) | |||
return EINVAL; | |||
return EINVAL; | |||
if ((buf = malloc(size)) == NULL) | |||
return ENOMEM; | |||
return ENOMEM; | |||
if (fread(buf, 1, size, fp) != size) { | |||
if (ferror(fp)) | |||
return errno; | |||
else | |||
return ECONNRESET; | |||
if (ferror(fp)) | |||
return errno; | |||
else | |||
return ECONNRESET; | |||
} | |||
*out = buf; | |||
@@ -104,25 +104,25 @@ ipc_response(FILE *fp, char **out, uint32_t *len) | |||
static int | |||
ipc_req_res(struct ipc *ipc, | |||
const char *req, uint32_t qlen, | |||
char **res, uint32_t *rlen) | |||
const char *req, uint32_t qlen, | |||
char **res, uint32_t *rlen) | |||
{ | |||
FILE *fp; | |||
int error; | |||
if ((error = ipc_connect(ipc, &fp)) != 0) | |||
return error; | |||
return error; | |||
if (fwrite(&qlen, sizeof(qlen), 1, fp) != 1) | |||
goto error; | |||
goto error; | |||
if (fwrite(req, 1, qlen, fp) != qlen) | |||
goto error; | |||
goto error; | |||
if (fflush(fp) != 0) | |||
goto error; | |||
goto error; | |||
if ((errno = ipc_response(fp, res, rlen)) != 0) | |||
goto error; | |||
goto error; | |||
if ((errno = benc_validate(*res, *rlen)) != 0) | |||
goto error; | |||
goto error; | |||
fclose(fp); | |||
return 0; | |||
@@ -142,14 +142,14 @@ btpd_die(struct ipc *ipc) | |||
uint32_t rsiz; | |||
if ((error = ipc_req_res(ipc, shutdown, size, &response, &rsiz)) != 0) | |||
return error; | |||
return error; | |||
error = benc_validate(response, rsiz); | |||
if (error == 0) { | |||
int64_t tmp; | |||
int64_t tmp; | |||
benc_dget_int64(response, "code", &tmp); | |||
error = tmp; | |||
error = tmp; | |||
} | |||
free(response); | |||
@@ -172,12 +172,12 @@ btpd_add(struct ipc *ipc, char **paths, unsigned npaths, char **out) | |||
buf_write(&iob, paths[i], plen); | |||
} | |||
buf_print(&iob, "e"); | |||
error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen); | |||
free(iob.buf); | |||
if (error == 0) | |||
*out = res; | |||
*out = res; | |||
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, "e", 1); | |||
error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen); | |||
free(iob.buf); | |||
if (error != 0) | |||
return error; | |||
return error; | |||
*out = res; | |||
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_del(struct ipc *ipc, uint8_t (*hash)[20], | |||
unsigned nhashes, char **out); | |||
unsigned nhashes, char **out); | |||
int btpd_die(struct ipc *ipc); | |||
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; | |||
if (len <= 0) | |||
return EINVAL; | |||
return 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; | |||
switch (*p) { | |||
case 'd': | |||
d = 1; | |||
d = 1; | |||
case 'l': | |||
for (p++; p <= end && *p != 'e'; p++) { | |||
if (d != 0) { | |||
if (d % 2 == 1 && !isdigit(*p)) | |||
return NULL; | |||
else | |||
d++; | |||
} | |||
if ((p = benc_validate_aux(p, end)) == NULL) | |||
return NULL; | |||
} | |||
if (p > end || (d != 0 && d % 2 != 1)) | |||
return NULL; | |||
break; | |||
for (p++; p <= end && *p != 'e'; p++) { | |||
if (d != 0) { | |||
if (d % 2 == 1 && !isdigit(*p)) | |||
return NULL; | |||
else | |||
d++; | |||
} | |||
if ((p = benc_validate_aux(p, end)) == NULL) | |||
return NULL; | |||
} | |||
if (p > end || (d != 0 && d % 2 != 1)) | |||
return NULL; | |||
break; | |||
case 'i': | |||
p++; | |||
if (p > end) | |||
return NULL; | |||
if (*p == '-') | |||
p++; | |||
if (p > end || !isdigit(*p)) | |||
return NULL; | |||
p++; | |||
while (p <= end && isdigit(*p)) | |||
p++; | |||
if (p > end || *p != 'e') | |||
return NULL; | |||
break; | |||
p++; | |||
if (p > end) | |||
return NULL; | |||
if (*p == '-') | |||
p++; | |||
if (p > end || !isdigit(*p)) | |||
return NULL; | |||
p++; | |||
while (p <= end && isdigit(*p)) | |||
p++; | |||
if (p > end || *p != 'e') | |||
return NULL; | |||
break; | |||
default: | |||
if (isdigit(*p)) { | |||
size_t len = 0; | |||
while (p <= end && isdigit(*p)) { | |||
len *= 10; | |||
len += *p - '0'; | |||
p++; | |||
} | |||
if (p <= end && *p == ':' && p + len <= end) | |||
p += len; | |||
else | |||
return NULL; | |||
} | |||
else | |||
return NULL; | |||
break; | |||
if (isdigit(*p)) { | |||
size_t len = 0; | |||
while (p <= end && isdigit(*p)) { | |||
len *= 10; | |||
len += *p - '0'; | |||
p++; | |||
} | |||
if (p <= end && *p == ':' && p + len <= end) | |||
p += len; | |||
else | |||
return NULL; | |||
} | |||
else | |||
return NULL; | |||
break; | |||
} | |||
return p; | |||
} | |||
@@ -86,21 +86,21 @@ benc_length(const char *p) | |||
switch (*p) { | |||
case 'd': | |||
case 'l': | |||
blen = 2; // [l|d]...e | |||
next = benc_first(p); | |||
while (*next != 'e') { | |||
size_t len = benc_length(next); | |||
blen += len; | |||
next += len; | |||
} | |||
return blen; | |||
blen = 2; // [l|d]...e | |||
next = benc_first(p); | |||
while (*next != 'e') { | |||
size_t len = benc_length(next); | |||
blen += len; | |||
next += len; | |||
} | |||
return blen; | |||
case 'i': | |||
for (next = p + 1; *next != 'e'; next++) | |||
; | |||
return next - p + 1; | |||
for (next = p + 1; *next != 'e'; next++) | |||
; | |||
return next - p + 1; | |||
default: | |||
assert(benc_str(p, &next, &blen, NULL) == 0); | |||
return next - p + blen; | |||
assert(benc_str(p, &next, &blen, NULL) == 0); | |||
return next - p + blen; | |||
} | |||
} | |||
@@ -109,7 +109,7 @@ benc_nelems(const char *p) | |||
{ | |||
size_t nelems = 0; | |||
for (p = benc_first(p); p != NULL; p = benc_next(p)) | |||
nelems++; | |||
nelems++; | |||
return nelems; | |||
} | |||
@@ -135,9 +135,9 @@ benc_str(const char *p, const char **out, size_t *len, const char**next) | |||
blen = *p - '0'; | |||
p++; | |||
while (isdigit(*p)) { | |||
blen *= 10; | |||
blen += *p - '0'; | |||
p++; | |||
blen *= 10; | |||
blen += *p - '0'; | |||
p++; | |||
} | |||
assert(*p == ':'); | |||
benc_safeset(len, blen); | |||
@@ -154,12 +154,12 @@ benc_strz(const char *p, char **out, size_t *len, const char **next) | |||
const char *bstr; | |||
if ((err = benc_str(p, &bstr, &blen, next)) == 0) { | |||
if ((*out = malloc(blen + 1)) != NULL) { | |||
memcpy(*out, bstr, blen); | |||
(*out)[blen] = '\0'; | |||
benc_safeset(len, blen); | |||
} else | |||
err = ENOMEM; | |||
if ((*out = malloc(blen + 1)) != NULL) { | |||
memcpy(*out, bstr, blen); | |||
(*out)[blen] = '\0'; | |||
benc_safeset(len, blen); | |||
} else | |||
err = ENOMEM; | |||
} | |||
return err; | |||
} | |||
@@ -172,11 +172,11 @@ benc_stra(const char *p, char **out, size_t *len, const char **next) | |||
const char *bstr; | |||
if ((err = benc_str(p, &bstr, &blen, next)) == 0) { | |||
if ((*out = malloc(blen)) != NULL) { | |||
memcpy(*out, bstr, blen); | |||
benc_safeset(len, blen); | |||
} else | |||
err = ENOMEM; | |||
if ((*out = malloc(blen)) != NULL) { | |||
memcpy(*out, bstr, blen); | |||
benc_safeset(len, blen); | |||
} else | |||
err = ENOMEM; | |||
} | |||
return err; | |||
} | |||
@@ -190,16 +190,16 @@ benc_int64(const char *p, int64_t *out, const char **next) | |||
assert(*p == 'i'); | |||
p++; | |||
if (*p == '-') { | |||
sign = -1; | |||
p++; | |||
sign = -1; | |||
p++; | |||
} | |||
assert(isdigit(*p)); | |||
res += sign * (*p - '0'); | |||
p++; | |||
while (isdigit(*p)) { | |||
res *= sign * 10; | |||
res += sign * (*p - '0'); | |||
p++; | |||
res *= sign * 10; | |||
res += sign * (*p - '0'); | |||
p++; | |||
} | |||
assert(*p == 'e'); | |||
benc_safeset(out, res); | |||
@@ -214,10 +214,10 @@ benc_uint32(const char *p, uint32_t *out, const char **next) | |||
int err; | |||
int64_t res; | |||
if ((err = benc_int64(p, &res, next)) == 0) { | |||
if (res >= 0 && res <= 0xffffffffUL) | |||
*out = (uint32_t)res; | |||
else | |||
err = EINVAL; | |||
if (res >= 0 && res <= 0xffffffffUL) | |||
*out = (uint32_t)res; | |||
else | |||
err = EINVAL; | |||
} | |||
return err; | |||
} | |||
@@ -235,17 +235,17 @@ benc_dget_any(const char *p, const char *key, const char **val) | |||
p = benc_first(p); | |||
while (p != NULL) { | |||
if ((res = benc_str(p, &bstr, &blen, &p)) != 0) | |||
return res; | |||
res = strncmp(bstr, key, blen); | |||
if (res == 0 && len == blen) { | |||
*val = p; | |||
return 0; | |||
} else if (res <= 0) { | |||
p = benc_next(p); | |||
} else | |||
return ENOENT; | |||
if ((res = benc_str(p, &bstr, &blen, &p)) != 0) | |||
return res; | |||
res = strncmp(bstr, key, blen); | |||
if (res == 0 && len == blen) { | |||
*val = p; | |||
return 0; | |||
} else if (res <= 0) { | |||
p = benc_next(p); | |||
} else | |||
return ENOENT; | |||
} | |||
return ENOENT; | |||
} | |||
@@ -255,8 +255,8 @@ benc_dget_lst(const char *p, const char *key, const char **val) | |||
{ | |||
int err; | |||
if ((err = benc_dget_any(p, key, val)) == 0) | |||
if (!benc_islst(*val)) | |||
err = EINVAL; | |||
if (!benc_islst(*val)) | |||
err = EINVAL; | |||
return err; | |||
} | |||
@@ -265,8 +265,8 @@ benc_dget_dct(const char *p, const char *key, const char **val) | |||
{ | |||
int err; | |||
if ((err = benc_dget_any(p, key, val)) == 0) | |||
if (!benc_isdct(*val)) | |||
err = EINVAL; | |||
if (!benc_isdct(*val)) | |||
err = EINVAL; | |||
return err; | |||
} | |||
@@ -276,8 +276,8 @@ benc_dget_str(const char *p, const char *key, const char **val, size_t *len) | |||
int err; | |||
const char *sp; | |||
if ((err = benc_dget_any(p, key, &sp)) == 0) | |||
err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
} | |||
int | |||
@@ -286,8 +286,8 @@ benc_dget_stra(const char *p, const char *key, char **val, size_t *len) | |||
int err; | |||
const char *sp; | |||
if ((err = benc_dget_any(p, key, &sp)) == 0) | |||
err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
} | |||
int | |||
@@ -296,8 +296,8 @@ benc_dget_strz(const char *p, const char *key, char **val, size_t *len) | |||
int err; | |||
const char *sp; | |||
if ((err = benc_dget_any(p, key, &sp)) == 0) | |||
err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL; | |||
return err; | |||
} | |||
int | |||
@@ -306,9 +306,9 @@ benc_dget_int64(const char *p, const char *key, int64_t *val) | |||
int err; | |||
const char *ip; | |||
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; | |||
} | |||
} | |||
int | |||
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; | |||
const char *ip; | |||
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; | |||
} | |||
} | |||
int | |||
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_dct(const char *p, const char *key, const char **val); | |||
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_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); | |||
@@ -44,7 +44,7 @@ print_metainfo(struct metainfo *tp) | |||
printf("Info hash: "); | |||
for (i = 0; i < 20; i++) | |||
printf("%.2x", tp->info_hash[i]); | |||
printf("%.2x", tp->info_hash[i]); | |||
printf("\n"); | |||
printf("Tracker URL: %s\n", tp->announce); | |||
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("Files:\n"); | |||
for (i = 0; i < tp->nfiles; i++) { | |||
printf("%s (%" PRId64 ")\n", | |||
tp->files[i].path, (int64_t)tp->files[i].length); | |||
printf("%s (%" PRId64 ")\n", | |||
tp->files[i].path, (int64_t)tp->files[i].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) | |||
{ | |||
if (len == 0) | |||
return 0; | |||
return 0; | |||
else if (len == 1 && path[0] == '.') | |||
return 0; | |||
return 0; | |||
else if (len == 2 && path[0] == '.' && path[1] == '.') | |||
return 0; | |||
return 0; | |||
else if (memchr(path, '/', len) != NULL) | |||
return 0; | |||
return 0; | |||
return 1; | |||
} | |||
@@ -81,27 +81,27 @@ fill_fileinfo(const char *fdct, struct fileinfo *tfp) | |||
const char *plst, *iter, *str; | |||
if ((err = benc_dget_off(fdct, "length", &tfp->length)) != 0) | |||
return err; | |||
return err; | |||
if ((err = benc_dget_lst(fdct, "path", &plst)) != 0) | |||
return err; | |||
return err; | |||
npath = plen = 0; | |||
iter = benc_first(plst); | |||
while (iter != NULL) { | |||
if (!benc_isstr(iter)) | |||
return EINVAL; | |||
benc_str(iter, &str, &len, &iter); | |||
if (!check_path(str, len)) | |||
return EINVAL; | |||
npath++; | |||
plen += len; | |||
if (!benc_isstr(iter)) | |||
return EINVAL; | |||
benc_str(iter, &str, &len, &iter); | |||
if (!check_path(str, len)) | |||
return EINVAL; | |||
npath++; | |||
plen += len; | |||
} | |||
if (npath == 0) | |||
return EINVAL; | |||
return EINVAL; | |||
if ((tfp->path = malloc(plen + (npath - 1) + 1)) == NULL) | |||
return ENOMEM; | |||
return ENOMEM; | |||
iter = benc_first(plst); | |||
benc_str(iter, &str, &len, &iter); | |||
@@ -109,11 +109,11 @@ fill_fileinfo(const char *fdct, struct fileinfo *tfp) | |||
plen = len; | |||
npath--; | |||
while (npath > 0) { | |||
tfp->path[plen++] = '/'; | |||
benc_str(iter, &str, &len, &iter); | |||
memcpy(tfp->path + plen, str, len); | |||
plen += len; | |||
npath--; | |||
tfp->path[plen++] = '/'; | |||
benc_str(iter, &str, &len, &iter); | |||
memcpy(tfp->path + plen, str, len); | |||
plen += len; | |||
npath--; | |||
} | |||
tfp->path[plen] = '\0'; | |||
return 0; | |||
@@ -124,18 +124,18 @@ clear_metainfo(struct metainfo *mip) | |||
{ | |||
int i; | |||
if (mip->piece_hash != NULL) | |||
free(mip->piece_hash); | |||
free(mip->piece_hash); | |||
if (mip->announce != NULL) | |||
free(mip->announce); | |||
free(mip->announce); | |||
if (mip->files != NULL) { | |||
for (i = 0; i < mip->nfiles; i++) { | |||
if (mip->files[i].path != NULL) | |||
free(mip->files[i].path); | |||
} | |||
free(mip->files); | |||
for (i = 0; i < mip->nfiles; i++) { | |||
if (mip->files[i].path != NULL) | |||
free(mip->files[i].path); | |||
} | |||
free(mip->files); | |||
} | |||
if (mip->name != NULL) | |||
free(mip->name); | |||
free(mip->name); | |||
} | |||
int | |||
@@ -147,91 +147,91 @@ fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes) | |||
const char *hash_addr; | |||
if (!benc_isdct(bep)) | |||
return EINVAL; | |||
return EINVAL; | |||
if ((err = benc_dget_strz(bep, "announce", &tp->announce, NULL)) != 0) | |||
goto out; | |||
goto out; | |||
if ((err = benc_dget_dct(bep, "info", &bep)) != 0) | |||
goto out; | |||
goto out; | |||
SHA1(bep, benc_length(bep), tp->info_hash); | |||
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) | |||
goto out; | |||
goto out; | |||
if (len % 20 != 0) { | |||
err = EINVAL; | |||
goto out; | |||
err = EINVAL; | |||
goto out; | |||
} | |||
tp->npieces = len / 20; | |||
tp->pieces_off = hash_addr - base_addr; | |||
if (mem_hashes) { | |||
if ((tp->piece_hash = malloc(len)) == NULL) { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
bcopy(hash_addr, tp->piece_hash, len); | |||
if ((tp->piece_hash = malloc(len)) == NULL) { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
bcopy(hash_addr, tp->piece_hash, len); | |||
} | |||
if ((err = benc_dget_strz(bep, "name", &tp->name, NULL)) != 0) | |||
goto out; | |||
goto out; | |||
err = benc_dget_off(bep, "length", &tp->total_length); | |||
if (err == 0) { | |||
tp->nfiles = 1; | |||
tp->files = calloc(1, sizeof(struct fileinfo)); | |||
if (tp->files != NULL) { | |||
tp->files[0].length = tp->total_length; | |||
tp->files[0].path = strdup(tp->name); | |||
if (tp->files[0].path == NULL) { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
} else { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
tp->nfiles = 1; | |||
tp->files = calloc(1, sizeof(struct fileinfo)); | |||
if (tp->files != NULL) { | |||
tp->files[0].length = tp->total_length; | |||
tp->files[0].path = strdup(tp->name); | |||
if (tp->files[0].path == NULL) { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
} else { | |||
err = ENOMEM; | |||
goto out; | |||
} | |||
} | |||
else if (err == ENOENT) { | |||
int i; | |||
const char *flst, *fdct; | |||
if ((err = benc_dget_lst(bep, "files", &flst)) != 0) | |||
goto out; | |||
tp->nfiles = benc_nelems(flst); | |||
if (tp->nfiles < 1) { | |||
err = EINVAL; | |||
goto out; | |||
} | |||
tp->files = calloc(tp->nfiles, sizeof(struct fileinfo)); | |||
tp->total_length = 0; | |||
i = 0; | |||
for (fdct = benc_first(flst); fdct != NULL; fdct = benc_next(fdct)) { | |||
if (!benc_isdct(fdct)) { | |||
err = EINVAL; | |||
goto out; | |||
} | |||
if ((err = fill_fileinfo(fdct, &tp->files[i])) != 0) | |||
goto out; | |||
tp->total_length += tp->files[i].length; | |||
i++; | |||
} | |||
int i; | |||
const char *flst, *fdct; | |||
if ((err = benc_dget_lst(bep, "files", &flst)) != 0) | |||
goto out; | |||
tp->nfiles = benc_nelems(flst); | |||
if (tp->nfiles < 1) { | |||
err = EINVAL; | |||
goto out; | |||
} | |||
tp->files = calloc(tp->nfiles, sizeof(struct fileinfo)); | |||
tp->total_length = 0; | |||
i = 0; | |||
for (fdct = benc_first(flst); fdct != NULL; fdct = benc_next(fdct)) { | |||
if (!benc_isdct(fdct)) { | |||
err = EINVAL; | |||
goto out; | |||
} | |||
if ((err = fill_fileinfo(fdct, &tp->files[i])) != 0) | |||
goto out; | |||
tp->total_length += tp->files[i].length; | |||
i++; | |||
} | |||
} | |||
else | |||
goto out; | |||
goto out; | |||
out: | |||
if (err != 0) | |||
clear_metainfo(tp); | |||
clear_metainfo(tp); | |||
return err; | |||
} | |||
@@ -244,31 +244,31 @@ load_metainfo(const char *path, off_t size, int mem_hashes, | |||
int fd, err = 0; | |||
if ((fd = open(path, O_RDONLY)) == -1) | |||
return errno; | |||
return errno; | |||
if (size <= 0) { | |||
struct stat sb; | |||
if (fstat(fd, &sb) == -1) { | |||
close(fd); | |||
return errno; | |||
} else | |||
size = sb.st_size; | |||
struct stat sb; | |||
if (fstat(fd, &sb) == -1) { | |||
close(fd); | |||
return errno; | |||
} else | |||
size = sb.st_size; | |||
} | |||
if ((buf = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) | |||
err = errno; | |||
err = errno; | |||
close(fd); | |||
if (err == 0) | |||
err = benc_validate(buf, size); | |||
err = benc_validate(buf, size); | |||
if (err == 0) | |||
if ((*res = calloc(1, sizeof(**res))) == NULL) | |||
err = ENOMEM; | |||
if ((*res = calloc(1, sizeof(**res))) == NULL) | |||
err = ENOMEM; | |||
if (err == 0) | |||
if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0) | |||
free(*res); | |||
if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0) | |||
free(*res); | |||
munmap(buf, size); | |||
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)); | |||
if (bts == NULL) | |||
return NULL; | |||
return NULL; | |||
bts->meta = meta; | |||
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); | |||
if (bts->fd != -1) { | |||
close(bts->fd); | |||
bts->fd = -1; | |||
close(bts->fd); | |||
bts->fd = -1; | |||
} | |||
bts->t_off = off; | |||
bts->index = 0; | |||
while (off >= files[bts->index].length) { | |||
off -= files[bts->index].length; | |||
bts->index++; | |||
off -= files[bts->index].length; | |||
bts->index++; | |||
} | |||
bts->f_off = off; | |||
@@ -63,31 +63,31 @@ bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len) | |||
boff = 0; | |||
while (boff < len) { | |||
if (bts->fd == -1) { | |||
int err = | |||
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); | |||
if (err != 0) | |||
return err; | |||
if (bts->f_off != 0) | |||
lseek(bts->fd, bts->f_off, SEEK_SET); | |||
} | |||
wantread = min(len - boff, files[bts->index].length - bts->f_off); | |||
didread = read(bts->fd, buf + boff, wantread); | |||
if (didread == -1) | |||
return errno; | |||
boff += didread; | |||
bts->f_off += didread; | |||
bts->t_off += didread; | |||
if (bts->f_off == files[bts->index].length) { | |||
close(bts->fd); | |||
bts->fd = -1; | |||
bts->f_off = 0; | |||
bts->index++; | |||
} | |||
if (didread != wantread) | |||
return ENOENT; | |||
if (bts->fd == -1) { | |||
int err = | |||
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); | |||
if (err != 0) | |||
return err; | |||
if (bts->f_off != 0) | |||
lseek(bts->fd, bts->f_off, SEEK_SET); | |||
} | |||
wantread = min(len - boff, files[bts->index].length - bts->f_off); | |||
didread = read(bts->fd, buf + boff, wantread); | |||
if (didread == -1) | |||
return errno; | |||
boff += didread; | |||
bts->f_off += didread; | |||
bts->t_off += didread; | |||
if (bts->f_off == files[bts->index].length) { | |||
close(bts->fd); | |||
bts->fd = -1; | |||
bts->f_off = 0; | |||
bts->index++; | |||
} | |||
if (didread != wantread) | |||
return ENOENT; | |||
} | |||
return 0; | |||
} | |||
@@ -96,7 +96,7 @@ void | |||
bts_close_ro(struct bt_stream_ro *bts) | |||
{ | |||
if (bts->fd != -1) | |||
close(bts->fd); | |||
close(bts->fd); | |||
free(bts); | |||
} | |||
@@ -112,11 +112,11 @@ bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash) | |||
SHA1_Init(&ctx); | |||
while (length > 0) { | |||
wantread = min(length, SHAFILEBUF); | |||
if ((err = bts_read_ro(bts, buf, wantread)) != 0) | |||
break; | |||
length -= wantread; | |||
SHA1_Update(&ctx, buf, wantread); | |||
wantread = min(length, SHAFILEBUF); | |||
if ((err = bts_read_ro(bts, buf, wantread)) != 0) | |||
break; | |||
length -= wantread; | |||
SHA1_Update(&ctx, buf, wantread); | |||
} | |||
SHA1_Final(hash, &ctx); | |||
return err; | |||
@@ -136,23 +136,23 @@ bts_hashes(struct metainfo *meta, | |||
off_t llen = meta->total_length % plen; | |||
if ((bts = bts_open_ro(meta, 0, fd_cb, arg)) == NULL) | |||
return ENOMEM; | |||
for (piece = 0; piece < meta->npieces; piece++) { | |||
return ENOMEM; | |||
for (piece = 0; piece < meta->npieces; piece++) { | |||
if (piece < meta->npieces - 1) | |||
err = bts_sha(bts, plen, hash); | |||
else | |||
err = bts_sha(bts, llen, hash); | |||
if (err == 0) | |||
cb(piece, hash, arg); | |||
else if (err == ENOENT) { | |||
cb(piece, NULL, arg); | |||
if (piece < meta->npieces - 1) | |||
bts_seek_ro(bts, (piece + 1) * plen); | |||
err = 0; | |||
} else | |||
break; | |||
err = bts_sha(bts, plen, hash); | |||
else | |||
err = bts_sha(bts, llen, hash); | |||
if (err == 0) | |||
cb(piece, hash, arg); | |||
else if (err == ENOENT) { | |||
cb(piece, NULL, arg); | |||
if (piece < meta->npieces - 1) | |||
bts_seek_ro(bts, (piece + 1) * plen); | |||
err = 0; | |||
} else | |||
break; | |||
} | |||
bts_close_ro(bts); | |||
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)); | |||
if (bts == NULL) | |||
return NULL; | |||
return NULL; | |||
bts->meta = meta; | |||
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; | |||
while (boff < len) { | |||
if (bts->fd == -1) { | |||
int err = | |||
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); | |||
if (err != 0) | |||
return err; | |||
if (bts->f_off != 0) | |||
lseek(bts->fd, bts->f_off, SEEK_SET); | |||
} | |||
wantwrite = min(len - boff, files[bts->index].length - bts->f_off); | |||
didwrite = write(bts->fd, buf + boff, wantwrite); | |||
if (didwrite == -1) | |||
return errno; | |||
boff += didwrite; | |||
bts->f_off += didwrite; | |||
bts->t_off += didwrite; | |||
if (bts->f_off == files[bts->index].length) { | |||
if (bts->fd == -1) { | |||
int err = | |||
bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); | |||
if (err != 0) | |||
return err; | |||
if (bts->f_off != 0) | |||
lseek(bts->fd, bts->f_off, SEEK_SET); | |||
} | |||
wantwrite = min(len - boff, files[bts->index].length - bts->f_off); | |||
didwrite = write(bts->fd, buf + boff, wantwrite); | |||
if (didwrite == -1) | |||
return errno; | |||
boff += didwrite; | |||
bts->f_off += didwrite; | |||
bts->t_off += didwrite; | |||
if (bts->f_off == files[bts->index].length) { | |||
if (fsync(bts->fd) == -1) { | |||
int err = errno; | |||
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) | |||
return errno; | |||
bts->fd = -1; | |||
bts->f_off = 0; | |||
bts->index++; | |||
} | |||
bts->fd = -1; | |||
bts->f_off = 0; | |||
bts->index++; | |||
} | |||
} | |||
return 0; | |||
} | |||
@@ -225,11 +225,11 @@ bts_close_wo(struct bt_stream_wo *bts) | |||
{ | |||
int err = 0; | |||
if (bts->fd != -1) { | |||
if (fsync(bts->fd) == -1) { | |||
err = errno; | |||
close(bts->fd); | |||
} else if (close(bts->fd) == -1) | |||
err = errno; | |||
if (fsync(bts->fd) == -1) { | |||
err = errno; | |||
close(bts->fd); | |||
} else if (close(bts->fd) == -1) | |||
err = errno; | |||
} | |||
free(bts); | |||
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_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 |
@@ -34,9 +34,9 @@ set_nonblocking(int fd) | |||
{ | |||
int oflags; | |||
if ((oflags = fcntl(fd, F_GETFL, 0)) == -1) | |||
return errno; | |||
return errno; | |||
if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1) | |||
return errno; | |||
return errno; | |||
return 0; | |||
} | |||
@@ -45,9 +45,9 @@ set_blocking(int fd) | |||
{ | |||
int oflags; | |||
if ((oflags = fcntl(fd, F_GETFL, 0)) == -1) | |||
return errno; | |||
return errno; | |||
if (fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) == -1) | |||
return errno; | |||
return errno; | |||
return 0; | |||
} | |||
@@ -58,16 +58,16 @@ mkdirs(char *path) | |||
char *spos = strchr(path + 1, '/'); // Must ignore the root | |||
while (spos != NULL) { | |||
*spos = '\0'; | |||
err = mkdir(path, 0777); | |||
*spos = '/'; | |||
if (err != 0 && errno != EEXIST) { | |||
err = errno; | |||
break; | |||
} | |||
spos = strchr(spos + 1, '/'); | |||
*spos = '\0'; | |||
err = mkdir(path, 0777); | |||
*spos = '/'; | |||
if (err != 0 && errno != EEXIST) { | |||
err = errno; | |||
break; | |||
} | |||
spos = strchr(spos + 1, '/'); | |||
} | |||
return err; | |||
} | |||
@@ -81,8 +81,8 @@ vopen(int *res, int flags, const char *fmt, ...) | |||
va_start(ap, fmt); | |||
if (vsnprintf(path, PATH_MAX, fmt, ap) >= PATH_MAX) { | |||
va_end(ap); | |||
return ENAMETOOLONG; | |||
va_end(ap); | |||
return ENAMETOOLONG; | |||
} | |||
va_end(ap); | |||
@@ -90,18 +90,18 @@ vopen(int *res, int flags, const char *fmt, ...) | |||
again: | |||
fd = open(path, flags, 0666); | |||
if (fd < 0 && errno == ENOENT && (flags & O_CREAT) != 0 && !didmkdirs) { | |||
if (mkdirs(path) == 0) { | |||
didmkdirs = 1; | |||
goto again; | |||
} else | |||
return errno; | |||
if (mkdirs(path) == 0) { | |||
didmkdirs = 1; | |||
goto again; | |||
} else | |||
return errno; | |||
} | |||
if (fd >= 0) { | |||
*res = fd; | |||
return 0; | |||
*res = fd; | |||
return 0; | |||
} else | |||
return errno; | |||
return errno; | |||
} | |||
int | |||
@@ -110,22 +110,22 @@ canon_path(const char *path, char **res) | |||
char rp[PATH_MAX]; | |||
if (realpath(path, rp) == NULL) | |||
return errno; | |||
return errno; | |||
#if 0 | |||
// This could be necessary on solaris. | |||
if (rp[0] != '/') { | |||
char wd[MAXPATHLEN]; | |||
if (getcwd(wd, MAXPATHLEN) == NULL) | |||
return errno; | |||
if (strlcat(wd, "/", MAXPATHLEN) >= MAXPATHLEN) | |||
return ENAMETOOLONG; | |||
if (strlcat(wd, rp, MAXPATHLEN) >= MAXPATHLEN) | |||
return ENAMETOOLONG; | |||
strcpy(rp, wd); | |||
char wd[MAXPATHLEN]; | |||
if (getcwd(wd, MAXPATHLEN) == NULL) | |||
return errno; | |||
if (strlcat(wd, "/", MAXPATHLEN) >= MAXPATHLEN) | |||
return ENAMETOOLONG; | |||
if (strlcat(wd, rp, MAXPATHLEN) >= MAXPATHLEN) | |||
return ENAMETOOLONG; | |||
strcpy(rp, wd); | |||
} | |||
#endif | |||
if ((*res = strdup(rp)) == NULL) | |||
return ENOMEM; | |||
return ENOMEM; | |||
return 0; | |||
} | |||
@@ -136,6 +136,6 @@ round_to_page(size_t size) | |||
size_t psize = getpagesize(); | |||
size_t rem = size % psize; | |||
if (rem != 0) | |||
size += psize - rem; | |||
size += psize - rem; | |||
return size; | |||
} |