Strangely such connections are not entirely uncommon. Added a hand shake time out of 60 seconds to resolve this. Added a peer_on_tick function which is used to monitor peers for different timeouts. Timestamps are compared against the reborn btpd_seconds. The issue has been reported by Ludvig Omholt and Arnaud Bergeron.master
@@ -32,8 +32,11 @@ | |||||
static uint8_t m_peer_id[20]; | static uint8_t m_peer_id[20]; | ||||
static struct event m_sigint; | static struct event m_sigint; | ||||
static struct event m_sigterm; | static struct event m_sigterm; | ||||
static struct event m_heartbeat; | |||||
static int m_shutdown; | static int m_shutdown; | ||||
long btpd_seconds; | |||||
void | void | ||||
btpd_exit(int code) | btpd_exit(int code) | ||||
{ | { | ||||
@@ -92,6 +95,14 @@ signal_cb(int signal, short type, void *arg) | |||||
btpd_shutdown(30); | btpd_shutdown(30); | ||||
} | } | ||||
static void | |||||
heartbeat_cb(int fd, short type, void *arg) | |||||
{ | |||||
btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); | |||||
btpd_seconds++; | |||||
net_on_tick(); | |||||
} | |||||
struct td_cb { | struct td_cb { | ||||
void (*cb)(void *); | void (*cb)(void *); | ||||
void *arg; | void *arg; | ||||
@@ -196,4 +207,6 @@ btpd_init(void) | |||||
btpd_ev_add(&m_sigint, NULL); | btpd_ev_add(&m_sigint, NULL); | ||||
signal_set(&m_sigterm, SIGTERM, signal_cb, NULL); | signal_set(&m_sigterm, SIGTERM, signal_cb, NULL); | ||||
btpd_ev_add(&m_sigterm, NULL); | btpd_ev_add(&m_sigterm, NULL); | ||||
evtimer_set(&m_heartbeat, heartbeat_cb, NULL); | |||||
btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); | |||||
} | } |
@@ -39,6 +39,8 @@ | |||||
#define BTPD_L_BTPD 0x00000010 | #define BTPD_L_BTPD 0x00000010 | ||||
#define BTPD_L_POL 0x00000020 | #define BTPD_L_POL 0x00000020 | ||||
extern long btpd_seconds; | |||||
void btpd_init(void); | void btpd_init(void); | ||||
void btpd_log(uint32_t type, const char *fmt, ...); | void btpd_log(uint32_t type, const char *fmt, ...); | ||||
@@ -18,7 +18,6 @@ | |||||
#include "btpd.h" | #include "btpd.h" | ||||
static struct event m_bw_timer; | |||||
static unsigned long m_bw_bytes_in; | static unsigned long m_bw_bytes_in; | ||||
static unsigned long m_bw_bytes_out; | static unsigned long m_bw_bytes_out; | ||||
@@ -178,7 +177,8 @@ net_write(struct peer *p, unsigned long wmax) | |||||
nwritten = writev(p->sd, iov, niov); | nwritten = writev(p->sd, iov, niov); | ||||
if (nwritten < 0) { | if (nwritten < 0) { | ||||
if (errno == EAGAIN) { | if (errno == EAGAIN) { | ||||
btpd_ev_add(&p->out_ev, WRITE_TIMEOUT); | |||||
btpd_ev_add(&p->out_ev, NULL); | |||||
p->t_wantwrite = btpd_seconds; | |||||
return 0; | return 0; | ||||
} else { | } else { | ||||
btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno)); | btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno)); | ||||
@@ -217,8 +217,10 @@ net_write(struct peer *p, unsigned long wmax) | |||||
bcount = 0; | bcount = 0; | ||||
} | } | ||||
} | } | ||||
if (!BTPDQ_EMPTY(&p->outq)) | |||||
btpd_ev_add(&p->out_ev, WRITE_TIMEOUT); | |||||
if (!BTPDQ_EMPTY(&p->outq)) { | |||||
btpd_ev_add(&p->out_ev, NULL); | |||||
p->t_wantwrite = btpd_seconds; | |||||
} | |||||
return nwritten; | return nwritten; | ||||
} | } | ||||
@@ -570,15 +572,11 @@ compute_rates(void) { | |||||
m_rate_dwn += tot_dwn - compute_rate_sub(m_rate_dwn); | m_rate_dwn += tot_dwn - compute_rate_sub(m_rate_dwn); | ||||
} | } | ||||
void | |||||
net_bw_cb(int sd, short type, void *arg) | |||||
static void | |||||
net_bw_tick(void) | |||||
{ | { | ||||
struct peer *p; | struct peer *p; | ||||
btpd_ev_add(&m_bw_timer, (& (struct timeval) { 1, 0 })); | |||||
compute_rates(); | |||||
m_bw_bytes_out = net_bw_limit_out; | m_bw_bytes_out = net_bw_limit_out; | ||||
m_bw_bytes_in = net_bw_limit_in; | m_bw_bytes_in = net_bw_limit_in; | ||||
@@ -597,7 +595,8 @@ net_bw_cb(int sd, short type, void *arg) | |||||
} | } | ||||
if (net_bw_limit_out) { | if (net_bw_limit_out) { | ||||
while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { | |||||
while (((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL | |||||
&& m_bw_bytes_out > 0)) { | |||||
BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | ||||
p->flags &= ~PF_ON_WRITEQ; | p->flags &= ~PF_ON_WRITEQ; | ||||
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | ||||
@@ -611,6 +610,28 @@ net_bw_cb(int sd, short type, void *arg) | |||||
} | } | ||||
} | } | ||||
static void | |||||
run_peer_ticks(void) | |||||
{ | |||||
struct net *n; | |||||
struct peer *p, *next; | |||||
BTPDQ_FOREACH_MUTABLE(p, &net_unattached, p_entry, next) | |||||
peer_on_tick(p); | |||||
BTPDQ_FOREACH(n, &m_torrents, entry) | |||||
BTPDQ_FOREACH_MUTABLE(p, &n->peers, p_entry, next) | |||||
peer_on_tick(p); | |||||
} | |||||
void | |||||
net_on_tick(void) | |||||
{ | |||||
run_peer_ticks(); | |||||
compute_rates(); | |||||
net_bw_tick(); | |||||
} | |||||
void | void | ||||
net_read_cb(int sd, short type, void *arg) | net_read_cb(int sd, short type, void *arg) | ||||
{ | { | ||||
@@ -629,16 +650,11 @@ void | |||||
net_write_cb(int sd, short type, void *arg) | net_write_cb(int sd, short type, void *arg) | ||||
{ | { | ||||
struct peer *p = (struct peer *)arg; | struct peer *p = (struct peer *)arg; | ||||
if (type == EV_TIMEOUT) { | |||||
btpd_log(BTPD_L_CONN, "Write attempt timed out.\n"); | |||||
peer_kill(p); | |||||
return; | |||||
} | |||||
if (net_bw_limit_out == 0) { | |||||
if (net_bw_limit_out == 0) | |||||
net_write(p, 0); | net_write(p, 0); | ||||
} else if (m_bw_bytes_out > 0) { | |||||
else if (m_bw_bytes_out > 0) | |||||
m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | ||||
} else { | |||||
else { | |||||
p->flags |= PF_ON_WRITEQ; | p->flags |= PF_ON_WRITEQ; | ||||
BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); | BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); | ||||
} | } | ||||
@@ -672,7 +688,4 @@ net_init(void) | |||||
event_set(&m_net_incoming, sd, EV_READ | EV_PERSIST, | event_set(&m_net_incoming, sd, EV_READ | EV_PERSIST, | ||||
net_connection_cb, NULL); | net_connection_cb, NULL); | ||||
btpd_ev_add(&m_net_incoming, NULL); | btpd_ev_add(&m_net_incoming, NULL); | ||||
evtimer_set(&m_bw_timer, net_bw_cb, NULL); | |||||
btpd_ev_add(&m_bw_timer, (& (struct timeval) { 1, 0 })); | |||||
} | } |
@@ -11,8 +11,6 @@ | |||||
#define MSG_PIECE 7 | #define MSG_PIECE 7 | ||||
#define MSG_CANCEL 8 | #define MSG_CANCEL 8 | ||||
#define WRITE_TIMEOUT (& (struct timeval) { 60, 0 }) | |||||
extern struct peer_tq net_unattached; | extern struct peer_tq net_unattached; | ||||
extern struct peer_tq net_bw_readq; | extern struct peer_tq net_bw_readq; | ||||
extern struct peer_tq net_bw_writeq; | extern struct peer_tq net_bw_writeq; | ||||
@@ -20,6 +18,8 @@ extern unsigned net_npeers; | |||||
void net_init(void); | void net_init(void); | ||||
void net_on_tick(void); | |||||
void net_create(struct torrent *tp); | void net_create(struct torrent *tp); | ||||
void net_kill(struct torrent *tp); | void net_kill(struct torrent *tp); | ||||
@@ -61,6 +61,9 @@ struct peer { | |||||
unsigned long rate_up, rate_dwn; | unsigned long rate_up, rate_dwn; | ||||
unsigned long count_up, count_dwn; | unsigned long count_up, count_dwn; | ||||
long t_created; | |||||
long t_wantwrite; | |||||
struct { | struct { | ||||
uint32_t msg_len; | uint32_t msg_len; | ||||
uint8_t msg_num; | uint8_t msg_num; | ||||
@@ -66,7 +66,8 @@ peer_send(struct peer *p, struct net_buf *nb) | |||||
if (BTPDQ_EMPTY(&p->outq)) { | if (BTPDQ_EMPTY(&p->outq)) { | ||||
assert(p->outq_off == 0); | assert(p->outq_off == 0); | ||||
btpd_ev_add(&p->out_ev, WRITE_TIMEOUT); | |||||
btpd_ev_add(&p->out_ev, NULL); | |||||
p->t_wantwrite = btpd_seconds; | |||||
} | } | ||||
BTPDQ_INSERT_TAIL(&p->outq, nl, entry); | BTPDQ_INSERT_TAIL(&p->outq, nl, entry); | ||||
} | } | ||||
@@ -263,6 +264,7 @@ peer_create_common(int sd) | |||||
p->sd = sd; | p->sd = sd; | ||||
p->flags = PF_I_CHOKE | PF_P_CHOKE; | p->flags = PF_I_CHOKE | PF_P_CHOKE; | ||||
p->t_created = btpd_seconds; | |||||
BTPDQ_INIT(&p->my_reqs); | BTPDQ_INIT(&p->my_reqs); | ||||
BTPDQ_INIT(&p->outq); | BTPDQ_INIT(&p->outq); | ||||
@@ -507,6 +509,18 @@ peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | |||||
} | } | ||||
} | } | ||||
void | |||||
peer_on_tick(struct peer *p) | |||||
{ | |||||
if ((p->flags & PF_ATTACHED) == 0 && btpd_seconds - p->t_created >= 60) { | |||||
btpd_log(BTPD_L_CONN, "hand shake timed out.\n"); | |||||
peer_kill(p); | |||||
} else if (!BTPDQ_EMPTY(&p->outq) && btpd_seconds - p->t_wantwrite >= 60) { | |||||
btpd_log(BTPD_L_CONN, "write attempt timed out.\n"); | |||||
peer_kill(p); | |||||
} | |||||
} | |||||
int | int | ||||
peer_chokes(struct peer *p) | peer_chokes(struct peer *p) | ||||
{ | { | ||||
@@ -52,6 +52,7 @@ void peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||||
uint32_t length); | uint32_t length); | ||||
void peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | void peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin, | ||||
uint32_t length); | uint32_t length); | ||||
void peer_on_tick(struct peer *p); | |||||
int peer_active_down(struct peer *p); | int peer_active_down(struct peer *p); | ||||
int peer_active_up(struct peer *p); | int peer_active_up(struct peer *p); | ||||