Re: Lack of Documentation about SA_RESTART...

Paolo Ornati
2005-07-12T10:13:56Z

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

On Tue, 12 Jul 2005 10:38:11 +0200
Paolo Ornati <ornati@fastwebnet.it> wrote:

> The particular case you analized (blocking connect interrupted by a
> SA_RESTART signal) is interesting... and since SUSV3 says
> "but the connection request shall not be aborted, and the
> connection shall be established asynchronously" (with select()
> or poll()...)
> both for EINPROGRESS and EINTR, I think it's quite stupit to
> automatically restart it and then return EALREADY.
>
> The logically correct behaviur with blocking connect interrupted and
> then restarted should be to continue the blocking wait... IHMO.

it seems that Linux is doing the Right Thing... see the attached
program...

$ make
gcc -O2 -Wall -o conntest connect_test.c

FROM ANOTHER CONSOLE: this is needed to block connect()...
# iptables -A OUTPUT -p tcp --dport 3500 -m state --state NEW -j DROP

$ ./conntest WITHOUT_SA_RESTART
connect(): errno = 4 # EINTR, as expected
Cannot setup client!

$ ./conntest # connect is restarted after SIGALRM, and then it blocks again

FROM ANOTHER CONSOLE:
# iptables -D OUTPUT -p tcp --dport 3500 -m state --state NEW -j DROP

and then "conntest" (thanks to TCP protocol retries) will terminate.

:-)

--
Paolo Ornati
Linux 2.6.12.2 on x86_64

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

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <unistd.h>

void sighandler(int sig)
{
/* nothing :) */
}

int setup_alarm_handler(int flags)
{
struct sigaction sa = {
.sa_handler = &sighandler,
.sa_flags = flags
};
return sigaction(SIGALRM, &sa, NULL);
}

int setup_server(int port)
{
int sock;
struct sockaddr_in sa = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = htonl(INADDR_ANY)
};

if ((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
goto error;
if (bind(sock, (struct sockaddr*)&sa, sizeof(sa)) < 0)
goto error_clean;
if (listen(sock, 16) < 0)
goto error_clean;
return sock;

error_clean:
close(sock);
error:
return -1;
}

int setup_client(const char *server, int port)
{
int sock;
struct sockaddr_in sa = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = inet_addr(server)
};

if ((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
goto error;
if (connect(sock, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
printf("connect(): errno = %d\n", errno);
goto error_clean;
}
return sock;

error_clean:
close(sock);
error:
return -1;
}

int main(int argc, char *argv[])
{
int server, client;
int flags = SA_RESTART;

if (argc > 1)
flags = 0;

if (setup_alarm_handler(flags))
return 1;

server = setup_server(3500);
if (server < 0) {
printf("Cannot setup server!\n");
return 1;
}
alarm(1);
client = setup_client("127.0.0.1", 3500);
if (client < 0) {
printf("Cannot setup client!\n");
return 1;
}
printf("Ok!\n");
return 0;
}

[-- Attachment #3: Makefile --]
[-- Type: application/octet-stream, Size: 49 bytes --]

conntest: connect_test.c
gcc -O2 -Wall -o $@ $<