From: Michael Kerrisk <m.kerrisk@gmx.net>
To: linux-kernel@vger.kernel.org
Subject: Shutdown(), TCP sockets, and select() discrepancy
Date: Tue, 17 Dec 2002 18:01:20 +0100 (MET) [thread overview]
Message-ID: <20192.1040144480@www24.gmx.net> (raw)
After an offline discussion with Andi Kleen, I thought I'd bring this topic
here.
I have been experimenting with shutdown() and select() on TCP sockets and
noted a clear discrepancy from (seemingly all) other Unix flavours. On most
implementations, if we do a SHUT_WR or SHUT_RDWR, then the socket should test
as writable when we call select(), since a write() etc. will fail with a
SIGPIPE signal or an EPIPE error.
On Linux this doesn't happen - is there a reason why Linux differs in this
respect from other implementations? Given that FreeBSD, Solaris 8, HP/UX 11,
Irix 6.5, and OSF 5.1/a all do mark a socket as writable in this case, things
appear to be broken, de facto, on Linux.
At the foot of this mail is a test program I wrote which
demonstrates the disrepancy. When I run this on SuSE 8.0 (kernel 2.4.18)
and SuSE 7.2 (kernel 2.2.19) I see the following:
$ ./is_shutdown_select 1
Listening socket (fd=3) set up okay
Active socket (fd=4) set up okay
Connection established (fd=5)
shutdown(4, 1)
3:
4:
5: r w
$ ./is_shutdown_select 2
Listening socket (fd=3) set up okay
Active socket (fd=4) set up okay
Connection established (fd=5)
shutdown(4, 2)
3:
4: r
5: r w
But On FreeBSD 4.7 I see the following (which is what I expected to see on
Linux):
$ ./is_shutdown_select 1
Listening socket (fd=3) set up okay
Active socket (fd=4) set up okay
Connection established (fd=5)
shutdown(4, 1)
3:
4: w
5: r w
$ ./is_shutdown_select 2
Listening socket (fd=3) set up okay
Active socket (fd=4) set up okay
Connection established (fd=5)
shutdown(4, 2)
3:
4: r w
5: r w
Solaris 8, HP/UX 11, Irix 6.5, and OSF 5.1/a (I had to modify the header
files included slightly for the latter OSes) give the same results as FreeBSD
4.7.
Cheers
Michael
============================
/* is_shutdown_select.c
Experiment to determine behaviour of select() after a shutdown()
is performed on one or both ends of a TCP socket pair.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#define errExit(msg) { perror(msg); exit(EXIT_FAILURE); }
#define PORT_NUM 50000 /* Port number for server */
int
main(int argc, char *argv[])
{
struct sockaddr_in svaddr;
int fd[3], optval, j;
fd_set rfds, wfds;
int nfds;
struct timeval tmo = { 0, 0 }; /* For polling select() */
if (argc > 1 && strcmp(argv[1], "--help") == 0) {
fprintf(stderr, "%s active-how accept-how\n", argv[0]);
exit(EXIT_FAILURE);
} /* if */
fd[0] = socket(AF_INET, SOCK_STREAM, 0); /* Listening socket */
if (fd[0] == -1) errExit("socket");
optval = 1;
if (setsockopt(fd[0], SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval)) == -1) errExit("setsockopt");
/* Bind to wildcard host address + well-known port, and mark as
listening socket */
memset(&svaddr, 0, sizeof(svaddr));
svaddr.sin_family = AF_INET;
svaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Wildcard address */
svaddr.sin_port = htons(PORT_NUM); if (bind(fd[0], (struct sockaddr *)
&svaddr, sizeof(svaddr)) == -1)
errExit("bind");
if (listen(fd[0], 5) == -1) errExit("listen");
printf("Listening socket (fd=%d) set up okay\n", fd[0]);
/* Active sockets */
fd[1] = socket(AF_INET, SOCK_STREAM, 0);
if (fd[1] == -1) errExit("socket");
svaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1], (struct sockaddr *) &svaddr, sizeof(svaddr)) == -1)
errExit("connect");
printf("Active socket (fd=%d) set up okay\n", fd[1]);
fd[2] = accept(fd[0], NULL, NULL);
if (fd[2] == -1) errExit("accept");
printf("Connection established (fd=%d)\n", fd[2]);
if (argc > 1) { /* Do a shutdown on active socket */
if (shutdown(fd[1], atoi(argv[1])) == -1)
errExit("shutdown (active socket)");
printf("shutdown(%d, %d)\n", fd[1], atoi(argv[1]));
} /* if */
if (argc > 2) { /* Do a shutdown on accepted socket */
if (shutdown(fd[2], atoi(argv[2])) == -1)
errExit("shutdown (accepted socket)");
printf("shutdown(%d, %d)\n", fd[2], atoi(argv[2]));
} /* if */
FD_ZERO(&rfds);
FD_ZERO(&wfds);
nfds = 0;
for (j = 0; j < 3; j++) {
FD_SET(fd[j], &rfds);
FD_SET(fd[j], &wfds);
if (fd[j] >= nfds)
nfds = fd[j] + 1;
} /* for */
if (select(nfds, &rfds, &wfds, NULL, &tmo) == -1) errExit("select");
for (j = 0; j < 3; j++) {
printf("%d: ", fd[j]);
if (FD_ISSET(fd[j], &rfds))
printf("r ");
if (FD_ISSET(fd[j], &wfds))
printf("w ");
printf("\n");
} /* for */
exit(EXIT_SUCCESS);
} /* main */
--
+++ GMX - Mail, Messaging & more http://www.gmx.net +++
NEU: Mit GMX ins Internet. Rund um die Uhr für 1 ct/ Min. surfen!
reply other threads:[~2002-12-17 16:53 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20192.1040144480@www24.gmx.net \
--to=m.kerrisk@gmx.net \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.