How can I increase the TCP listen backlog value of a socket when the application has a hardcoded value?
Environment
- Red Hat Enterprise Linux 7
- TCP application with hard-coded
listen()backlog parameter
Issue
- The application has a hard coded value for the listen backlog that cannot be changed via its configuration file
- We need the value to be larger
- Application changes will take too long
Resolution
- There is no system configuration parameters that can do this
- It can be done by re-writing the
listen()function and pre-loading it when the application is started- This approach will not work for setuid binaries
- Red Hat does not recommend replacing system libraries with your own libraries but if you must change the backlog setting and you cannot change the application this approach is an option.
Unsupported Disclaimer
The following information has been provided by Red Hat, but is outside the scope of the posted Service Level Agreements and support procedures. The information is provided as-is and any configuration settings or installed applications made from the information in this article could make the Operating System unsupported by Red Hat Global Support Services. The intent of this article is to provide information to accomplish the system's needs. Use of the information in this article at the user's own risk.
Method
- forcebacklog.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
int listen(int socketfd, int backlog);
int listen(int socketfd, int backlog)
{
static int (*orig_listen)(int, int) = NULL;
char *env;
errno = 0;
/* resolve original listen function or return an error */
if(!orig_listen && !(*(void **)(&orig_listen) = dlsym(RTLD_NEXT, "listen")))
errno = EACCES;
else
{
/* Get the backlog value from the environment or default to 128 */
if((env = getenv("BACKLOG")))
backlog = atoi(env);
else
backlog = 128;
/* call original function with new backlog */
(*orig_listen)(socketfd, backlog);
}
/* return -1 if errno has been set -- note may be set by the original listen
function */
if (errno > 0)
return -1;
else return 0;
}
- make file
CC=gcc
CFLAGS=-fPIC -ansi -pedantic -Wall
LDFLAGS=-shared -Wl,-soname,forcebacklog.so
LDLIBS=-ldl
default: forcebacklog.so
strip -s forcebacklog.so
%.so: %.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS)
clean:
rm -f *.so *.o
- Some instructions
1. To make the so file
make
2. Run application
BACKLOG=234
sets a backlog of 234, any value <= net.core.somaxconn can be set.
If the value is > net.core.somaxconn the system will set it to the
net.core.somaxconn value
LD_PRELOAD=./forcebacklog.so
Tells the system to preload the forcebacklog.so library. The above path has
it in the current directory but it can be anywhere
backlog_tester 12481 20
This is the application to run along with its arguments, port 12481 and a
backlog of 20.
BACKLOG=234 LD_PRELOAD=./forcebacklog.so /cloud/seagate/C/backlog_tester 12481 20
3. Confirm that the backlog is 234 and not 20 (note that net.core.somaxconn is set to 255
# ss -nl src :12481
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 234 *:12481 *:*
4. Example when the command is run without forcebacklog
# ss -nl src :12481
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 20 *:12481 *:*
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.