about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorLeonid Evdokimov <leon@darkk.net.ru>2011-01-24 23:31:52 +0200
committerEric Wong <normalperson@yhbt.net>2011-01-26 18:15:57 +0000
commit5668fb5c22e3726e732e4f5160aed93fa2c2b12e (patch)
treefe94bbff5567c424453980566395aaa6011af9c4
parente024be4e45fe08c83b3132bd227f3065695c231d (diff)
downloadlibnodelay-5668fb5c22e3726e732e4f5160aed93fa2c2b12e.tar.gz
Enforce NODELAY on setsockopt().
-rw-r--r--nodelay.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/nodelay.c b/nodelay.c
index 134a95a..c391f65 100644
--- a/nodelay.c
+++ b/nodelay.c
@@ -13,6 +13,7 @@
 #include <netinet/tcp.h>
 #include <errno.h>
 #include <unistd.h>
+#include <stdlib.h>
 
 #if defined(__GNUC__) && (__GNUC__ >= 3)
 #  define unlikely(x)        __builtin_expect (!!(x), 0)
@@ -21,13 +22,25 @@
 #endif
 
 static int (*real_socket)(int, int, int);
+static int (*real_setsockopt)(int , int , int , const void *, socklen_t);
+
+static int nodelay_value;
 
 void __attribute__ ((constructor)) nodelay_init(void)
 {
-        real_socket = dlsym(RTLD_NEXT, "socket");
+        char* nodelay = getenv("NODELAY");
+        if (nodelay)
+                nodelay_value = atoi(nodelay);
+        else
+                nodelay_value = 1;
 
+        real_socket = dlsym(RTLD_NEXT, "socket");
         if (!real_socket || dlerror())
                 _exit(1);
+
+        real_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
+        if (!real_setsockopt || dlerror())
+                _exit(1);
 }
 
 int socket(int domain, int type, int protocol)
@@ -44,12 +57,27 @@ int socket(int domain, int type, int protocol)
             type == SOCK_STREAM &&
             domain == PF_INET) {
                 int orig_errno = errno;
-                int optval = 1;
+                int optval = nodelay_value;
 
                 /* don't care too much if it fails */
-                setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));
+                real_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));
                 errno = orig_errno;
         }
 
         return fd;
 }
+
+int setsockopt(int sockfd, int level, int optname, const void *poptval, socklen_t optlen)
+{
+        int optval;
+
+        if (unlikely(!real_socket))
+                nodelay_init();
+
+        optval = nodelay_value;
+        if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
+                poptval = &optval;
+                optlen = sizeof(optval);
+        }
+        return real_setsockopt(sockfd, level, optname, poptval, optlen);
+}