]> granicus.if.org Git - transmission/commitdiff
Use large kernel buffers for the UDP socket when uTP is enabled.
authorJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Fri, 18 Feb 2011 00:43:47 +0000 (00:43 +0000)
committerJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Fri, 18 Feb 2011 00:43:47 +0000 (00:43 +0000)
Since we're using a single UDP socket to implement multiple uTP sockets,
and since we're not always timely in servicing an incoming UDP packet,
it's important to use a large receive buffer.  The send buffer is probably
less critical, we increase it nonetheless.

libtransmission/session.c
libtransmission/tr-udp.c
libtransmission/tr-udp.h

index 57ba77f019737efed4c73ca11674c95c02be0afc..c01641957ef267adbc758f5f20c3d50d50268046 100644 (file)
@@ -1990,6 +1990,8 @@ toggle_utp(  void * data )
 
     session->isUTPEnabled = !session->isUTPEnabled;
 
+    tr_udpSetSocketBuffers( session );
+
     /* But don't call tr_utpClose -- see reset_timer in tr-utp.c for an
        explanation. */
 }
index 85d962650122744969756bb6cef84e40812f3ccd..5dfef00937258c2faa9bee158b34c509236fb931 100644 (file)
@@ -33,6 +33,77 @@ THE SOFTWARE.
 #include "tr-utp.h"
 #include "tr-udp.h"
 
+/* Since we use a single UDP socket in order to implement multiple
+   uTP sockets, try to set up huge buffers. */
+
+#define RECV_BUFFER_SIZE (4 * 1024 * 1024)
+#define SEND_BUFFER_SIZE (1 * 1024 * 1024)
+#define SMALL_BUFFER_SIZE (32 * 1024)
+
+static void
+set_socket_buffers(int fd, int large)
+{
+    int size, rbuf, sbuf, rc;
+    socklen_t rbuf_len = sizeof(rbuf), sbuf_len = sizeof(sbuf);
+
+    size = large ? RECV_BUFFER_SIZE : SMALL_BUFFER_SIZE;
+    rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+    if(rc < 0)
+        tr_nerr("UDP", "Failed to set receive buffer: %s",
+                tr_strerror(errno));
+
+    size = large ? SEND_BUFFER_SIZE : SMALL_BUFFER_SIZE;
+    rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+    if(rc < 0)
+        tr_nerr("UDP", "Failed to set send buffer: %s",
+                tr_strerror(errno));
+
+    if(large) {
+        rc = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &rbuf_len);
+        if(rc < 0)
+            rbuf = 0;
+
+        rc = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &sbuf_len);
+        if(rc < 0)
+            sbuf = 0;
+
+        if(rbuf < RECV_BUFFER_SIZE) {
+            tr_nerr("UDP", "Failed to set receive buffer: requested %d, got %d",
+                    RECV_BUFFER_SIZE, rbuf);
+#ifdef __linux__
+            tr_ninf("UDP",
+                    "Please add the line "
+                    "\"net.core.rmem_max = %d\" to /etc/sysctl.conf",
+                    RECV_BUFFER_SIZE);
+#endif
+        }
+
+        if(sbuf < SEND_BUFFER_SIZE) {
+            tr_nerr("UDP", "Failed to set send buffer: requested %d, got %d",
+                    SEND_BUFFER_SIZE, sbuf);
+#ifdef __linux__
+            tr_ninf("UDP",
+                    "Please add the line "
+                    "\"net.core.wmem_max = %d\" to /etc/sysctl.conf",
+                    SEND_BUFFER_SIZE);
+#endif
+        }
+    }
+}
+
+void
+tr_udpSetSocketBuffers(tr_session *session)
+{
+    tr_bool utp = tr_sessionIsUTPEnabled(session);
+    if(session->udp_socket >= 0)
+        set_socket_buffers(session->udp_socket, utp);
+    if(session->udp6_socket >= 0)
+        set_socket_buffers(session->udp6_socket, utp);
+}
+
+
+
+
 /* BEP-32 has a rather nice explanation of why we need to bind to one
    IPv6 address, if I may say so myself. */
 
@@ -199,6 +270,8 @@ tr_udpInit(tr_session *ss)
             tr_nerr("UDP", "Couldn't allocate IPv6 event");
     }
 
+    tr_udpSetSocketBuffers(ss);
+
     if(ss->isDHTEnabled)
         tr_dhtInit(ss);
 
index b331e39e94e69fdec32c4f17f5cf738956557efd..98825b949fe717c5fe363be7fbd903517c20883f 100644 (file)
@@ -27,4 +27,4 @@ THE SOFTWARE.
 
 void tr_udpInit( tr_session * );
 void tr_udpUninit( tr_session * );
-
+void tr_udpSetSocketBuffers(tr_session *);