Re: Lack of Documentation about SA_RESTART...

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 12 Jul 2005 10:38:11 +0200
Paolo Ornati <[email protected]> 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
#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: Makefile
Description: Binary data


[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux