@@ -2,6 +2,7 @@ | |||||
#define BTPD_H | #define BTPD_H | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/socket.h> | |||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
@@ -872,12 +872,11 @@ net_shake_read(struct peer *p, unsigned long rmax) | |||||
if (in->buf_off < 68) | if (in->buf_off < 68) | ||||
break; | break; | ||||
else { | else { | ||||
if (!hs->incoming && bcmp(in->buf + 48, p->id, 20) != 0) | |||||
goto bad_shake; | |||||
else if (hs->incoming && torrent_has_peer(p->tp, in->buf + 48)) | |||||
goto bad_shake; // Not really, but we are already connected | |||||
if (hs->incoming) | |||||
bcopy(in->buf + 48, p->id, 20); | |||||
if (torrent_has_peer(p->tp, in->buf + 48)) | |||||
goto bad_shake; // Not really, but we're already connected. | |||||
else if (bcmp(in->buf + 48, btpd.peer_id, 20) == 0) | |||||
goto bad_shake; // Connection from myself. | |||||
bcopy(in->buf + 48, p->id, 20); | |||||
hs->state = SHAKE_ID; | hs->state = SHAKE_ID; | ||||
} | } | ||||
default: | default: | ||||
@@ -922,6 +921,22 @@ net_handshake(struct peer *p, int incoming) | |||||
net_send_shake(p); | net_send_shake(p); | ||||
} | } | ||||
int | |||||
net_connect2(struct sockaddr *sa, socklen_t salen, int *sd) | |||||
{ | |||||
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; | |||||
} | |||||
return 0; | |||||
} | |||||
int | int | ||||
net_connect(const char *ip, int port, int *sd) | net_connect(const char *ip, int port, int *sd) | ||||
{ | { | ||||
@@ -939,25 +954,14 @@ net_connect(const char *ip, int port, int *sd) | |||||
if (getaddrinfo(ip, portstr, &hints, &res) != 0) | if (getaddrinfo(ip, portstr, &hints, &res) != 0) | ||||
return errno; | return errno; | ||||
if (res) { | |||||
if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { | |||||
btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno)); | |||||
freeaddrinfo(res); | |||||
return errno; | |||||
} | |||||
set_nonblocking(*sd); | |||||
if (connect(*sd, res->ai_addr, res->ai_addrlen) == -1 && | |||||
errno != EINPROGRESS) { | |||||
btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno)); | |||||
close(*sd); | |||||
freeaddrinfo(res); | |||||
return errno; | |||||
} | |||||
} | |||||
int error = net_connect2(res->ai_addr, res->ai_addrlen, sd); | |||||
freeaddrinfo(res); | freeaddrinfo(res); | ||||
btpd.npeers++; | |||||
return 0; | |||||
if (error == 0) | |||||
btpd.npeers++; | |||||
return error; | |||||
} | } | ||||
void | void | ||||
@@ -99,6 +99,7 @@ void net_handshake(struct peer *p, int incoming); | |||||
void net_read_cb(int sd, short type, void *arg); | void net_read_cb(int sd, short type, void *arg); | ||||
void net_write_cb(int sd, short type, void *arg); | void net_write_cb(int sd, short type, void *arg); | ||||
int net_connect2(struct sockaddr *sa, socklen_t salen, int *sd); | |||||
int net_connect(const char *ip, int port, int *sd); | int net_connect(const char *ip, int port, int *sd); | ||||
void net_unsend_piece(struct peer *p, struct piece_req *req); | void net_unsend_piece(struct peer *p, struct piece_req *req); | ||||
@@ -1,4 +1,6 @@ | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/socket.h> | |||||
#include <netinet/in.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
@@ -173,6 +175,25 @@ peer_create_out(struct torrent *tp, | |||||
p = peer_create_common(sd); | p = peer_create_common(sd); | ||||
p->tp = tp; | p->tp = tp; | ||||
bcopy(id, p->id, 20); | |||||
//bcopy(id, p->id, 20); | |||||
net_handshake(p, 0); | |||||
} | |||||
void | |||||
peer_create_out_compact(struct torrent *tp, const char *compact) | |||||
{ | |||||
int sd; | |||||
struct peer *p; | |||||
struct sockaddr_in addr; | |||||
addr.sin_family = AF_INET; | |||||
addr.sin_addr.s_addr = *(long *)compact; | |||||
addr.sin_port = *(short *)(compact + 4); | |||||
if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0) | |||||
return; | |||||
p = peer_create_common(sd); | |||||
p->tp = tp; | |||||
net_handshake(p, 0); | net_handshake(p, 0); | ||||
} | } |
@@ -58,7 +58,7 @@ unsigned long peer_get_rate(unsigned long *rates); | |||||
void peer_create_in(int sd); | void peer_create_in(int sd); | ||||
void peer_create_out(struct torrent *tp, const uint8_t *id, | 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_kill(struct peer *p); | ||||
#endif | #endif |
@@ -21,7 +21,7 @@ | |||||
#define PRIu64 "llu" | #define PRIu64 "llu" | ||||
#endif | #endif | ||||
#define REQ_SIZE (getpagesize() * 2) | |||||
#define REQ_SIZE (1024 + 6 * 50) | |||||
struct tracker_req { | struct tracker_req { | ||||
enum tr_event tr_event; | enum tr_event tr_event; | ||||
@@ -102,16 +102,29 @@ tracker_done(struct child *child) | |||||
tp->tracker_time = btpd.seconds + interval; | tp->tracker_time = btpd.seconds + interval; | ||||
if ((benc_dget_lst(req->res->buf, "peers", &peers)) != 0) { | |||||
btpd_log(BTPD_L_TRACKER, "Bad data from tracker.\n"); | |||||
failed = 1; | |||||
goto out; | |||||
int error = 0; | |||||
size_t length; | |||||
if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { | |||||
for (peers = benc_first(peers); | |||||
peers != NULL && btpd.npeers < btpd.maxpeers; | |||||
peers = benc_next(peers)) | |||||
maybe_connect_to(tp, peers); | |||||
} | } | ||||
for (peers = benc_first(peers); | |||||
peers != NULL && btpd.npeers < btpd.maxpeers; | |||||
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) { | |||||
for (size_t i = 0; i < length; i += 6) | |||||
peer_create_out_compact(tp, peers + i * 6); | |||||
} | |||||
} | |||||
if (error != 0) { | |||||
btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n"); | |||||
failed = 1; | |||||
goto out; | |||||
} | |||||
out: | out: | ||||
if (failed) { | if (failed) { | ||||
@@ -165,10 +178,13 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) | |||||
left = torrent_bytes_left(tp); | left = torrent_bytes_left(tp); | ||||
i = asprintf(url, "%s%cinfo_hash=%s&peer_id=%s&port=%d" | |||||
i = asprintf(url, "%s%cinfo_hash=%s" | |||||
"&peer_id=%s" | |||||
"&port=%d" | |||||
"&uploaded=%" PRIu64 | "&uploaded=%" PRIu64 | ||||
"&downloaded=%" PRIu64 | "&downloaded=%" PRIu64 | ||||
"&left=%" PRIu64 | "&left=%" PRIu64 | ||||
"&compact=1" | |||||
"%s%s", | "%s%s", | ||||
tp->meta.announce, qc, e_hash, e_id, btpd.port, | tp->meta.announce, qc, e_hash, e_id, btpd.port, | ||||
tp->uploaded, tp->downloaded, left, | tp->uploaded, tp->downloaded, left, | ||||