Search code examples
linuxsocketsnagle

setsockopt( TCP_NODELAY, 1 ): Permission denied


I have code that's worked without change since the 90s that is now getting Permission denied on Linux when trying to turn off the Nagle algorithm. Read of the man pages and a google search don't indicate why. Any ideas?

  int iFlags, iSize;

  /* NOTE: Sol 2.8 header requires socklen_t but man page says int! */

  int iSizeSize = sizeof( iSize );

#ifdef _WIN32
  unsigned long      ulMSDummy;
  if ( ioctlsocket( iFD, FIONBIO, (u_long FAR*) &ulMSDummy ) != 0 ) {
      printf( "%s: ioctlsocket( %s:%d, FIONBIO, 1 ): %s",
           pszName, pszAddr, iPort, strerror(errno));
      return -1;
  }
#else
  if ( ( iFlags = fcntl( iFD, F_GETFL, 0 ) ) < 0 ) {
      AKWarn( "%s: fcntl( %s:%d, F_GETFL ): %s",
           pszName, pszAddr, iPort, strerror(errno));
      return -1;
  }

  // NOTE: O_NDELAY may need to be changed to FNDELAY on some
  // platforms (which does the same thing) or O_NONBLOCK (which may
  // cause AKread() to return different values when there's no data).
  // Any of these three make the socket non-blocking, which is
  // DIFFERENT from TCP_NODELAY (see below).

  if ( fcntl( iFD, F_SETFL, iFlags | O_NDELAY ) < 0 ) {
      printf( "%s: fcntl( %s:%d, F_SETFL, +NDELAY ): %s",
           pszName, pszAddr, iPort, strerror(errno));
      return -1;
  }
#endif

  // NOTE: TCP_NODELAY is unrelated to the various NDELAY/NONBLOCK
  // options (above).  Instead, it disables the "Nagle Algorithm",
  // which caches tiny packets.

  // NOTE: This option hardcodes a tradeoff for less latency and more
  // packets.  Actually this could be a configuration parameter.

  iFlags = 1;
  if ( setsockopt( iFD, SOL_SOCKET, TCP_NODELAY,
                   (char*) &iFlags, sizeof( int ) ) ) {
      printf( "%s: setsockopt( %s:%d, TCP_NODELAY, %d ): %s",
           pszName, pszAddr, iPort, iFlags, strerror(errno) );
#ifndef __linux__
      return -1; // giving Permission denied on Linux???
#endif
  }

Solution

  •  if ( setsockopt( iFD, SOL_SOCKET, TCP_NODELAY,
    

    This is simply wrong from start. It should be IPPROTO_TCP and not SOL_SOCKET. These are different constants. Likely it never properly worked before, i.e. did something else than you intended.