libnodelay.git  about / heads / tags
LD_PRELOAD library to disable Nagle's algorithm
blob 6e7e2e16171520a9ed42ec11f05d90d1bb391431 2011 bytes (raw)
$ git show HEAD:nodelay.c	# shows this blob on the CLI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 
/*
 * LD_PRELOAD-able library that disables the Nagle algorithm for all
 * TCP sockets, both server and client.
 *
 * Copyright (C) 2009 Eric Wong <normalperson@yhbt.net>
 *
 * Licensed under the Lesser GNU General Public License, version 3 or later
 * and the GNU General Public License, version 2.
 * See http://www.gnu.org/licenses/
 */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/socket.h>
#include <netinet/in.h>
#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)
# else
#  define unlikely(x)	(x)
#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)
{
	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)
{
	int fd;

	if (unlikely(!real_socket))
		nodelay_init();

	fd = real_socket(domain, type, protocol);

	if (fd >= 0 &&
	    protocol == IPPROTO_TCP &&
	    (type & SOCK_STREAM) == SOCK_STREAM &&
	    domain == PF_INET) {
		int orig_errno = errno;
		int optval = nodelay_value;

		/* don't care too much if it fails */
		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();

	if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
		optval = nodelay_value;

		poptval = &optval;
		optlen = sizeof(optval);
	}
	return real_setsockopt(sockfd, level, optname, poptval, optlen);
}

git clone https://yhbt.net/libnodelay.git