The net code now calls the peer code when it has read a full message. This has mostly involved moving code from net.c to peer.c. * Added torrent_piece_size helper function.master
@@ -476,12 +476,7 @@ read_bitfield(struct peer *p, unsigned long rmax) | |||
rd->iob.buf_off += nread; | |||
if (rd->iob.buf_off == rd->iob.buf_len) { | |||
bcopy(rd->iob.buf, p->piece_field, rd->iob.buf_len); | |||
for (unsigned i = 0; i < p->tp->meta.npieces; i++) | |||
if (has_bit(p->piece_field, i)) { | |||
p->npieces++; | |||
cm_on_piece_ann(p, i); | |||
} | |||
peer_on_bitfield(p, rd->iob.buf); | |||
free(rd); | |||
net_generic_reader(p); | |||
} else | |||
@@ -513,16 +508,7 @@ read_piece(struct peer *p, unsigned long rmax) | |||
p->rate_to_me[btpd.seconds % RATEHISTORY] += nread; | |||
p->tp->downloaded += nread; | |||
if (rd->iob.buf_off == rd->iob.buf_len) { | |||
struct piece_req *req = BTPDQ_FIRST(&p->my_reqs); | |||
if (req != NULL && | |||
req->index == rd->index && | |||
req->begin == rd->begin && | |||
req->length == rd->iob.buf_len) { | |||
// | |||
off_t cbegin = rd->index * p->tp->meta.piece_length + rd->begin; | |||
torrent_put_bytes(p->tp, rd->iob.buf, cbegin, rd->iob.buf_len); | |||
cm_on_block(p); | |||
} | |||
peer_on_piece(p, rd->index, rd->begin, rd->iob.buf_len, rd->iob.buf); | |||
free(rd); | |||
net_generic_reader(p); | |||
} else | |||
@@ -578,54 +564,33 @@ net_generic_read(struct peer *p, unsigned long rmax) | |||
btpd_log(BTPD_L_MSG, "choke.\n"); | |||
if (msg_len != 1) | |||
goto bad_data; | |||
if ((p->flags & (PF_P_CHOKE|PF_I_WANT)) == PF_I_WANT) { | |||
p->flags |= PF_P_CHOKE; | |||
cm_on_undownload(p); | |||
} else | |||
p->flags |= PF_P_CHOKE; | |||
peer_on_choke(p); | |||
break; | |||
case MSG_UNCHOKE: | |||
btpd_log(BTPD_L_MSG, "unchoke.\n"); | |||
if (msg_len != 1) | |||
goto bad_data; | |||
if ((p->flags & (PF_P_CHOKE|PF_I_WANT)) | |||
== (PF_P_CHOKE|PF_I_WANT)) { | |||
p->flags &= ~PF_P_CHOKE; | |||
cm_on_download(p); | |||
} else | |||
p->flags &= ~PF_P_CHOKE; | |||
peer_on_unchoke(p); | |||
break; | |||
case MSG_INTEREST: | |||
btpd_log(BTPD_L_MSG, "interested.\n"); | |||
if (msg_len != 1) | |||
goto bad_data; | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == 0) { | |||
p->flags |= PF_P_WANT; | |||
cm_on_upload(p); | |||
} else | |||
p->flags |= PF_P_WANT; | |||
peer_on_interest(p); | |||
break; | |||
case MSG_UNINTEREST: | |||
btpd_log(BTPD_L_MSG, "uninterested.\n"); | |||
if (msg_len != 1) | |||
goto bad_data; | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) { | |||
p->flags &= ~PF_P_WANT; | |||
cm_on_unupload(p); | |||
} else | |||
p->flags &= ~PF_P_WANT; | |||
peer_on_uninterest(p); | |||
break; | |||
case MSG_HAVE: | |||
btpd_log(BTPD_L_MSG, "have.\n"); | |||
if (msg_len != 5) | |||
goto bad_data; | |||
else if (len - off >= msg_len + 4) { | |||
unsigned long piece = net_read32(buf + off + 5); | |||
if (!has_bit(p->piece_field, piece)) { | |||
set_bit(p->piece_field, piece); | |||
p->npieces++; | |||
cm_on_piece_ann(p, piece); | |||
} | |||
uint32_t index = net_read32(buf + off + 5); | |||
peer_on_have(p, index); | |||
} else | |||
got_part = 1; | |||
break; | |||
@@ -635,14 +600,9 @@ net_generic_read(struct peer *p, unsigned long rmax) | |||
goto bad_data; | |||
else if (p->npieces != 0) | |||
goto bad_data; | |||
else if (len - off >= msg_len + 4) { | |||
bcopy(buf + off + 5, p->piece_field, msg_len - 1); | |||
for (unsigned i = 0; i < p->tp->meta.npieces; i++) | |||
if (has_bit(p->piece_field, i)) { | |||
p->npieces++; | |||
cm_on_piece_ann(p, i); | |||
} | |||
} else { | |||
else if (len - off >= msg_len + 4) | |||
peer_on_bitfield(p, buf + off + 5); | |||
else { | |||
struct bitfield_reader *rp; | |||
size_t mem = sizeof(*rp) + msg_len - 1; | |||
p->reader->kill(p->reader); | |||
@@ -666,23 +626,18 @@ net_generic_read(struct peer *p, unsigned long rmax) | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) != PF_P_WANT) | |||
break; | |||
uint32_t index, begin, length; | |||
off_t cbegin; | |||
char *content; | |||
index = net_read32(buf + off + 5); | |||
begin = net_read32(buf + off + 9); | |||
length = net_read32(buf + off + 13); | |||
if (length > (1 << 15)) | |||
goto bad_data; | |||
if (index >= p->tp->meta.npieces | |||
|| !has_bit(p->tp->piece_field, index)) | |||
if (index >= p->tp->meta.npieces) | |||
goto bad_data; | |||
if (begin + length > p->tp->meta.piece_length) | |||
if (!has_bit(p->tp->piece_field, index)) | |||
goto bad_data; | |||
cbegin = index * p->tp->meta.piece_length + begin; | |||
if (cbegin + length > p->tp->meta.total_length) | |||
if (begin + length > torrent_piece_size(p->tp, index)) | |||
goto bad_data; | |||
content = torrent_get_bytes(p->tp, cbegin, length); | |||
net_send_piece(p, index, begin, content, length); | |||
peer_on_request(p, index, begin, length); | |||
} else | |||
got_part = 1; | |||
break; | |||
@@ -695,18 +650,9 @@ net_generic_read(struct peer *p, unsigned long rmax) | |||
uint32_t begin = net_read32(buf + off + 9); | |||
uint32_t length = msg_len - 9; | |||
if (len - off >= msg_len + 4) { | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
p->tp->downloaded += length; | |||
p->rate_to_me[btpd.seconds % RATEHISTORY] += length; | |||
struct piece_req *req = BTPDQ_FIRST(&p->my_reqs); | |||
if (req != NULL && | |||
req->index == index && | |||
req->begin == begin && | |||
req->length == length) { | |||
// | |||
torrent_put_bytes(p->tp, buf + off + 13, cbegin, length); | |||
cm_on_block(p); | |||
} | |||
peer_on_piece(p, index, begin, length, buf + off + 13); | |||
} else { | |||
struct piece_reader *rp; | |||
size_t mem = sizeof(*rp) + length; | |||
@@ -734,27 +680,16 @@ net_generic_read(struct peer *p, unsigned long rmax) | |||
if (msg_len != 13) | |||
goto bad_data; | |||
else if (len - off >= msg_len + 4) { | |||
struct piece_req *req; | |||
uint32_t index, begin, length; | |||
index = net_read32(buf + off + 5); | |||
begin = net_read32(buf + off + 9); | |||
length = net_read32(buf + off + 13); | |||
uint32_t index = net_read32(buf + off + 5); | |||
uint32_t begin = net_read32(buf + off + 9); | |||
uint32_t length = net_read32(buf + off + 13); | |||
if (index > p->tp->meta.npieces) | |||
goto bad_data; | |||
if (begin + length > torrent_piece_size(p->tp, index)) | |||
goto bad_data; | |||
btpd_log(BTPD_L_MSG, "cancel: %u, %u, %u\n", | |||
index, begin, length); | |||
req = BTPDQ_FIRST(&p->p_reqs); | |||
while (req != NULL) { | |||
if (req->index == index && | |||
req->begin == begin && | |||
req->length == length) { | |||
btpd_log(BTPD_L_MSG, "cancel matched.\n"); | |||
net_unsend_piece(p, req); | |||
break; | |||
} | |||
req = BTPDQ_NEXT(req, entry); | |||
} | |||
peer_on_cancel(p, index, begin, length); | |||
} else | |||
got_part = 1; | |||
break; | |||
@@ -93,6 +93,8 @@ void net_send_choke(struct peer *p); | |||
void net_send_have(struct peer *p, uint32_t index); | |||
void net_send_request(struct peer *p, struct piece_req *req); | |||
void net_send_piece(struct peer *p, uint32_t index, uint32_t begin, | |||
char *block, size_t blen); | |||
void net_send_cancel(struct peer *p, struct piece_req *req); | |||
void net_handshake(struct peer *p, int incoming); | |||
@@ -1,6 +1,8 @@ | |||
#include <sys/types.h> | |||
#include <sys/socket.h> | |||
#include <netinet/in.h> | |||
#include <math.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
@@ -166,10 +168,8 @@ peer_create_in(int sd) | |||
} | |||
void | |||
peer_create_out(struct torrent *tp, | |||
const uint8_t *id, | |||
const char *ip, | |||
int port) | |||
peer_create_out(struct torrent *tp, const uint8_t *id, | |||
const char *ip, int port) | |||
{ | |||
int sd; | |||
struct peer *p; | |||
@@ -201,3 +201,106 @@ peer_create_out_compact(struct torrent *tp, const char *compact) | |||
p->tp = tp; | |||
net_handshake(p, 0); | |||
} | |||
void | |||
peer_on_choke(struct peer *p) | |||
{ | |||
if ((p->flags & (PF_P_CHOKE|PF_I_WANT)) == PF_I_WANT) { | |||
p->flags |= PF_P_CHOKE; | |||
cm_on_undownload(p); | |||
} else | |||
p->flags |= PF_P_CHOKE; | |||
} | |||
void | |||
peer_on_unchoke(struct peer *p) | |||
{ | |||
if ((p->flags & (PF_P_CHOKE|PF_I_WANT)) == (PF_P_CHOKE|PF_I_WANT)) { | |||
p->flags &= ~PF_P_CHOKE; | |||
cm_on_download(p); | |||
} else | |||
p->flags &= ~PF_P_CHOKE; | |||
} | |||
void | |||
peer_on_interest(struct peer *p) | |||
{ | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == 0) { | |||
p->flags |= PF_P_WANT; | |||
cm_on_upload(p); | |||
} else | |||
p->flags |= PF_P_WANT; | |||
} | |||
void | |||
peer_on_uninterest(struct peer *p) | |||
{ | |||
if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT) { | |||
p->flags &= ~PF_P_WANT; | |||
cm_on_unupload(p); | |||
} else | |||
p->flags &= ~PF_P_WANT; | |||
} | |||
void | |||
peer_on_have(struct peer *p, uint32_t index) | |||
{ | |||
if (!has_bit(p->piece_field, index)) { | |||
set_bit(p->piece_field, index); | |||
p->npieces++; | |||
cm_on_piece_ann(p, index); | |||
} | |||
} | |||
void | |||
peer_on_bitfield(struct peer *p, 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++; | |||
cm_on_piece_ann(p, i); | |||
} | |||
} | |||
} | |||
void | |||
peer_on_piece(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length, const char *data) | |||
{ | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
struct piece_req *req = BTPDQ_FIRST(&p->my_reqs); | |||
if (req != NULL && | |||
req->index == index && | |||
req->begin == begin && | |||
req->length == length) { | |||
torrent_put_bytes(p->tp, data, cbegin, length); | |||
cm_on_block(p); | |||
} | |||
} | |||
void | |||
peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length) | |||
{ | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
char * content = torrent_get_bytes(p->tp, cbegin, length); | |||
net_send_piece(p, index, begin, content, length); | |||
} | |||
void | |||
peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length) | |||
{ | |||
struct piece_req *req = BTPDQ_FIRST(&p->p_reqs); | |||
while (req != NULL) { | |||
if (req->index == index | |||
&& req->begin == begin && req->length == length) { | |||
btpd_log(BTPD_L_MSG, "cancel matched.\n"); | |||
net_unsend_piece(p, req); | |||
break; | |||
} | |||
req = BTPDQ_NEXT(req, entry); | |||
} | |||
} |
@@ -48,7 +48,7 @@ void peer_choke(struct peer *p); | |||
void peer_unwant(struct peer *p, uint32_t index); | |||
void peer_want(struct peer *p, uint32_t index); | |||
void peer_request(struct peer *p, uint32_t index, | |||
uint32_t begin, uint32_t len); | |||
uint32_t begin, uint32_t len); | |||
void peer_cancel(struct peer *p, uint32_t index, uint32_t begin, uint32_t len); | |||
void peer_have(struct peer *p, uint32_t index); | |||
@@ -57,8 +57,21 @@ unsigned long peer_get_rate(unsigned long *rates); | |||
void peer_create_in(int sd); | |||
void peer_create_out(struct torrent *tp, const uint8_t *id, | |||
const char *ip, int port); | |||
const char *ip, int port); | |||
void peer_create_out_compact(struct torrent *tp, const char *compact); | |||
void peer_kill(struct peer *p); | |||
void peer_on_interest(struct peer *p); | |||
void peer_on_uninterest(struct peer *p); | |||
void peer_on_choke(struct peer *p); | |||
void peer_on_unchoke(struct peer *p); | |||
void peer_on_have(struct peer *p, uint32_t index); | |||
void peer_on_bitfield(struct peer *p, uint8_t *field); | |||
void peer_on_piece(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length, const char *data); | |||
void peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length); | |||
void peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | |||
uint32_t length); | |||
#endif |
@@ -43,7 +43,7 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz) | |||
btpd_err("Out of memory.\n"); | |||
tp->piece_count = btpd_calloc(mi->npieces, sizeof(tp->piece_count[0])); | |||
BTPDQ_INIT(&tp->peers); | |||
BTPDQ_INIT(&tp->getlst); | |||
@@ -251,3 +251,14 @@ torrent_get_by_hash(const uint8_t *hash) | |||
tp = BTPDQ_NEXT(tp, entry); | |||
return tp; | |||
} | |||
off_t | |||
torrent_piece_size(struct torrent *tp, uint32_t index) | |||
{ | |||
if (index < tp->meta.npieces - 1) | |||
return tp->meta.piece_length; | |||
else { | |||
off_t allbutlast = tp->meta.piece_length * (tp->meta.npieces - 1); | |||
return tp->meta.total_length - allbutlast; | |||
} | |||
} |
@@ -64,4 +64,6 @@ int torrent_has_peer(struct torrent *tp, const uint8_t *id); | |||
struct torrent *torrent_get_by_hash(const uint8_t *hash); | |||
off_t torrent_piece_size(struct torrent *tp, uint32_t index); | |||
#endif |