about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2005-08-12 20:25:52 +0000
committerRichard Nyberg <rnyberg@murmeldjur.se>2005-08-12 20:25:52 +0000
commiteaf95339c7c3e33da1b3c179a397c8af6c06ea74 (patch)
tree1e520ca93c3e3f273ccb10308dd58864b53027c6
parentfcbec726e5e5fadaad46fa05fcc13f7c9f8810ea (diff)
downloadbtpd-eaf95339c7c3e33da1b3c179a397c8af6c06ea74.tar.gz
btpd-eaf95339c7c3e33da1b3c179a397c8af6c06ea74.zip
Set an upper limit on how many piece messages to queue for
writing to a peer. If more requests arrive they will be ignored.
When all pieces have been sent to the peer, in order for it not to
wait on the ignored requests, its state will be reset by a choke
followed by an unchoke message. 

Without this limit there was no bound on how much memory btpd would
consume to satisfy a greedy peer.

-rw-r--r--btpd/net.c1
-rw-r--r--btpd/peer.c35
-rw-r--r--btpd/peer.h23
3 files changed, 45 insertions, 14 deletions
diff --git a/btpd/net.c b/btpd/net.c
index 081cdc4..2b89de4 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -129,6 +129,7 @@ net_write(struct peer *p, unsigned long wmax)
     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->rate_from_me[btpd.seconds % RATEHISTORY] += bufdelta;
diff --git a/btpd/peer.c b/btpd/peer.c
index 6f1eb3d..3eb53c9 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -86,6 +86,10 @@ 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)) {
@@ -101,6 +105,21 @@ peer_unsend(struct peer *p, struct nb_link *nl)
 }
 
 void
+peer_sent(struct peer *p, struct net_buf *nb)
+{
+    switch (nb->type) {
+    case NB_TORRENTDATA:
+	assert(p->npiece_msgs > 0);
+	p->npiece_msgs--;
+	break;
+    case NB_UNCHOKE:
+	assert(p->npiece_msgs == 0);
+	p->flags &= ~PF_NO_REQUESTS;
+	break;
+    }
+}
+
+void
 peer_request(struct peer *p, uint32_t index, uint32_t begin, uint32_t len)
 {
     if (p->tp->endgame == 0)
@@ -345,10 +364,18 @@ 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);
-    peer_send(p, nb_create_piece(index, begin, length));
-    peer_send(p, nb_create_torrentdata(content, length));
+    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, btpd.choke_msg);
+	    peer_send(p, btpd.unchoke_msg);
+	    p->flags |= PF_NO_REQUESTS;
+	}
+    }
 }
 
 void
diff --git a/btpd/peer.h b/btpd/peer.h
index dd9db0f..675c9a8 100644
--- a/btpd/peer.h
+++ b/btpd/peer.h
@@ -1,22 +1,23 @@
 #ifndef BTPD_PEER_H
 #define BTPD_PEER_H
 
-#define PF_I_WANT	0x01	/* We want to download from the peer */
-#define PF_I_CHOKE	0x02	/* We choke the peer */
-#define	PF_P_WANT	0x04	/* The peer wants to download from us */
-#define	PF_P_CHOKE	0x08	/* The peer is choking us */
-#define PF_ON_READQ	0x10
-#define PF_ON_WRITEQ	0x20
-#define PF_ATTACHED	0x40
-#define PF_WRITE_CLOSE	0x80	/* Close connection after writing all data */
+#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_WRITE_CLOSE	 0x80	/* Close connection after writing all data */
+#define PF_NO_REQUESTS	0x100
 
 #define RATEHISTORY 20
-
+#define MAXPIECEMSGS 128
 #define MAXPIPEDREQUESTS 10
 
 struct peer {
     int sd;
-    uint8_t flags;
+    uint16_t flags;
     uint8_t *piece_field;
     uint32_t npieces;
     uint32_t nwant;
@@ -28,6 +29,7 @@ struct peer {
     struct nb_tq my_reqs;
 
     unsigned nreqs_out;
+    unsigned npiece_msgs;
 
     size_t outq_off;
     struct nb_tq outq;
@@ -50,6 +52,7 @@ BTPDQ_HEAD(peer_tq, peer);
 
 void peer_send(struct peer *p, struct net_buf *nb);
 int peer_unsend(struct peer *p, struct nb_link *nl);
+void peer_sent(struct peer *p, struct net_buf *nb);
 
 void peer_unchoke(struct peer *p);
 void peer_choke(struct peer *p);