How can I increase the TCP listen backlog value of a socket when the application has a hardcoded value?

Solution Unverified - Updated

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                 *:*   
Components
Category
Tags

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.