listen() ignores the backlog argument?
Asked Answered
K

2

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.

Kindrakindred answered 24/2, 2011 at 22:1 Comment(0)
S
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().

Stamata answered 24/2, 2011 at 23:26 Comment(10)
Do you know if there's a reason to set a minimum of 16, as opposed to say 1?Calumet
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; }Extractor
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.Correspond
@Correspond IMO it gives a hint for maximum number of clients waiting for connection .Incrust
@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. Prescription
@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?Prescription
@satoru, also, it will set to 16 (minimum), not 2 (btw 1 is also power of 2 == 2^0)Prescription
@Prescription please try to add kernel keyword to your search. :)Extractor
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.Crucifixion
@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.Stamata
R
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 )

Ruthven answered 24/2, 2011 at 22:28 Comment(1)
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: books.google.com/… )Ruthven

© 2022 - 2024 — McMap. All rights reserved.