28

I have the following problem:

I have sockfd = socket(AF_INET, SOCK_STREAM, 0)

After I set up and bind the socket (let's say with sockfd.sin_port = htons(666)), I immediately do:

listen(sockfd, 3);

sleep(50); // for test purposes

I'm sleeping for 50 seconds to test the backlog argument, which seems to be ignored because I can establish a connection* more than 3 times on port 666.

*: What I mean is that I get a syn/ack for each Nth SYN (n>3) sent from the client and placed in the listen queue, instead of being dropped. What could be wrong? I've read the man pages of listen(2) and tcp(7) and found:

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. See tcp(7) for more information.

, but even with sysctl -w sys.net.ipv4.tcp_max_syn_backlog=2 and sysctl -w net.ipv4.tcp_syncookies=0, I still get the same results! I must be missing something or completely missunderstand listen()'s backlog purpose.

sth
  • 222,467
  • 53
  • 283
  • 367
Markoff Chaney
  • 313
  • 1
  • 4
  • 7

2 Answers2

42

The backlog argument to listen() is only advisory.

POSIX says:

The backlog argument provides a hint to the implementation which the implementation shall use to limit the number of outstanding connections in the socket's listen queue.

Current versions of the Linux kernel round it up to the next highest power of two, with a minimum of 16. The revelant code is in reqsk_queue_alloc().

caf
  • 233,326
  • 40
  • 323
  • 462
  • 1
    Do you know if there's a *reason* to set a minimum of 16, as opposed to say 1? – gojomo Feb 14 '13 at 03:11
  • 1
    This is not entirely correct. Function reqsk_queue_alloc() compute value for table allocation, but in the function inet_listen() value of backlog assigned to sk->sk_max_ack_backlog and this value is used here: static inline int sk_acceptq_is_full(struct sock *sk) { return sk->sk_ack_backlog > sk->sk_max_ack_backlog; } – Nikolai Mar 02 '14 at 14:04
  • I am using Ubuntu. If I didn't misunderstand you, when I set `backlog` to 1, it will be rounded up to 2 (which is the next highest power of two). But event when I call `listen` with `backlog` 1, I can create 100 connections to the socket successfully. – satoru May 20 '14 at 01:04
  • @satoru IMO it gives a hint for maximum number of clients waiting for connection . – sonus21 Feb 26 '15 at 14:21
  • @satoru, maybe your system is as per cited man page: `When syncookies are enabled there is no logical maximum length and this setting is ignored. ` – Marisha Sep 23 '19 at 14:39
  • @Nikolai, I want to understand your comment, I've searched for `inet_listen()` but find on web staff for Apple `https://opensource.apple.com/source/postfix/postfix-144/postfix/src/util/inet_listen.c.auto.html`, but the question has tag `Linux`. Any idea why is that? – Marisha Sep 23 '19 at 14:44
  • @satoru, also, it will set to 16 (minimum), not 2 (btw 1 is also power of 2 == 2^0) – Marisha Sep 23 '19 at 14:46
  • 1
    @Marisha please try to add kernel keyword to your search. :) – Nikolai Sep 23 '19 at 14:51
  • Linux isn't necessarily POSIX compliant, nor does it declare such compliance. As much as your answer is indeed very useful in context of POSIX, the question is tagged with "linux" explicitly. – Armen Michaeli Aug 31 '21 at 15:07
  • 1
    @amn: Linux does use the POSIX semantics as guidance, particularly in the case of the sockets interface. Regardless, my answer also included the actual Linux behaviour with a link to the source code that implements it, which I think pretty conclusively answers the question in a Linux-specific context. – caf Sep 01 '21 at 03:25
4

Different operating systems provide different numbers of queued connections with different backlog numbers. FreeBSD appears to be one of the few OSes that actually has a 1-to-1 mapping. (source: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA108&ots=Kq9FQogkTr&dq=berkeley%20listen%20backlog%20ack&pg=PA108#v=onepage&q=berkeley%20listen%20backlog%20ack&f=false )

gpcz
  • 806
  • 6
  • 8
  • The same source says that Berkeley-based OSes multiply backlog by 1.5 and give a queue for that, but that the reasons for doing so are "lost to history". This new source link points you to the specific page where it says that: (source: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA108&ots=Kq9FQogkTr&dq=berkeley%20listen%20backlog%20ack&pg=PA106#v=onepage&q=berkeley%20listen%20backlog%20ack&f=false ) – gpcz Feb 24 '11 at 22:36