Connect hangs for a while before returns -1 with ECONNREFUSED on 3.2 for loopback

Yurij M. Plotnikov
2012-02-03T06:34:55Z

[-- Attachment #1: Type: text/plain, Size: 777 bytes --]

On kernel 3.2.0-0.bpo.1-amd64 I see some strange behaviour of connect()
in case of connection via loopback. Lets see the following steps (there
are two processes on the host, and the first one with two threads)

Thread1:
1. socket(PF_INET, SOCK_STREAM, 0) -> 3
2. bind(10.27.10.1:26820) -> 0 /* The address is bound to some interface, eth1 */
3. listen(3, 1) -> 0

sleep for a while

Thread2:
4. shutdown(3, SHUT_RD) -> 0

sleep for a while

Another process:
5. socket(PF_INET, SOCK_STREAM, 0) -> 4
6. connect(4, 10.27.10.1:26820)

connect() returns -1 with ECONNREFUSED but after some time. In case of
two peer hosts connect() returns -1 with ECONNREFUSED almost
immediately, so does for the other kernel versions.

In attachment c program to reproduce this problem.

[-- Attachment #2: connect_loopback.c --]
[-- Type: text/x-csrc, Size: 1042 bytes --]

#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <errno.h>

main()
{
int child_sock;
int sock;
struct sockaddr_in addr;
int rc;
int proc;

sock = socket(PF_INET, SOCK_STREAM, 0);
printf("socket() -> %d(%d)\n", sock, errno);

addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = inet_addr("10.0.1.1");
rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
printf("bind() -> %d(%d)\n", rc, errno);

rc = listen(sock, 1);
printf("listen() -> %d(%d)\n", rc, errno);

sleep(1);

rc = shutdown(sock, SHUT_RD);
printf("shutdown() -> %d(%d)\n", rc, errno);

proc = fork();
if (proc)
{
child_sock = socket(PF_INET, SOCK_STREAM, 0);
printf("Child: socket() -> %d(%d)\n", child_sock, errno);
rc = connect(child_sock, (struct sockaddr *)&addr, sizeof(addr));
printf("connect() -> %d(%d)\n", rc, errno);
}
else
{
printf("Waiting...\n");getchar();
}

return 0;
}