netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Geoffrey Lee <glee@gnupilgrims.org>
To: "David S. Miller" <davem@redhat.com>
Cc: kuznet@ms2.inr.ac.ru, netdev@oss.sgi.com
Subject: Re: [PATCH] connect() return value.
Date: Fri, 16 Aug 2002 11:08:09 +1000	[thread overview]
Message-ID: <20020816010809.GA28446@anakin.wychk.org> (raw)
In-Reply-To: <20020815.142337.95077599.davem@redhat.com>

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

On Thu, Aug 15, 2002 at 02:23:37PM -0700, David S. Miller wrote:
>    From: Geoffrey Lee <glee@gnupilgrims.org>
>    Date: Thu, 15 Aug 2002 21:02:10 +1000
> 
>    On Wed, Aug 14, 2002 at 08:15:14PM -0700, David S. Miller wrote:
>    > How extensive are your notes on poll() behavior on TCP
>    > sockets? :-)
> 
>    Hmm, in which regard?
>    
>    Is there something specific that you are searching for? :-)
> 
> POLLHUP in particular.  I remember we verified that our behavior
> matched Solaris but no checks were performed against others.


In all honesty, none for that. But it would be a worthwhile experiment
I think. Let us see what happens.


Today, we are going to see what happens with POLLHUP on different Unix
implementations. Source code is provided.

poll.c (server that uses poll)
linger.c (our client to invoke the POLLHUP condition)

Note in poll.c I used size_t as the 3rd argument to accept instead
of socklen_t, as only Linux had socklen_t.

We also see that we get a compile warning when compiling the client as
on SunOS 5.6 the 4th argument to setsockopt is a char *. But we can
ignore that warning.


The following operating systems will be tested against:

OSF1 4.0 (Digital UNIX)
SunOS 5.6 (Solaris)
Linux 2.4.18


We will start the server on a machine with some specified port. We 
call listen for the specified socket, and accept. Next, we block
in the call to poll with fd set to the socket descriptor returned
by accept, and events and revents zeroed. On the call to poll, we 
specify -1 as a senitel that we want to block forever until something
interesting arrives (the error condition).

On the client, we connect to the server to the specified port
as normal. We specify the SO_LINGER option, with l_onoff set to 1 and
linger time set to 0. After we successfully connect to the server, we
call the close call immediately, to issue a RST to the server.


This is what happens on Linux 2.4.18:

$ ./poll -p 8888 
accept ok.
poll: POLLERR set
poll: POLLHUP set
sever terminating
$ 

On the client side:

$ ./linger -h [ip] -p 8888
connecting ..
closing ...
closed.
$ 


So, sending a RST will trigger POLLHUP and POLLERR on Linux.


On OSF1 4.0, we get this:

On the server:
$ ./poll -p 8888
accept ok.

On the client side:
$ ./linger -h [ip] -p 8888
connecting ..
closing ...
closed.
$ 


So on Digital UNIX, it blocks forever in the call to poll.

That's strange. Let's see what happens on SunOS 5.6:

./poll -p 8888
accept ok.


On the client side:

./linger -h [ip] -p 8888
connecting ..
closing ...
closed.
$ 


So on SunOS 5.6, it also blocks forever.


Do you know which Solaris was tested the last time it was found that
Linux behaves the same way as Solaris?

By the way, while we are on the subject of poll, what should one include
to get POLLRDNORM and INFTIM?

I found on OSF1 4.0 one can have both by including <poll.h>,
on SunOS 5.6, one can get POLLRDNORM by including <poll.h>, for INFTIM,
one must include <sys/stropts.h> as well.

On Linux, one will not be able to get them by including both <poll.h>
or <sys/stropts.h>. <sys/poll.h> will not work either. by including 
<linux/poll.h>, then one can get POLLRDNORM defined. But I could not
find INFTIM anywhere on Linux.


	-- G.



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

#include <sys/socket.h>

#include <netinet/in.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* getopt */

#define HOST "192.168.0.1"
#define PORT (22)

int main(argc, argv)
	int argc;
	char *argv[];
{
	int sockfd;
	int c;
	struct linger ling;
	struct sockaddr_in servaddr;
	char *host = HOST;
	unsigned short port = PORT;
	


	while ((c = getopt(argc, argv, "h:p:")) != -1) {
		switch (c) {
			case 'h':
				host = (char *)strdup(optarg);
				break;
			case 'p':
				port = atoi(optarg);
				break;
			default:
				break;
		}
	}

	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	if (sockfd < 0) {
		printf("socket\n");
		exit(1);
	}

	bzero(&servaddr, sizeof(struct sockaddr_in));

	servaddr.sin_family = AF_INET;
	servaddr.sin_port   = htons(port);
	servaddr.sin_addr.s_addr   = inet_addr(host);

	ling.l_onoff = 1;
	ling.l_linger = 0;

	if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0) {
		printf("setsockopt\n");
		exit(1);
	}

	printf("connecting ..\n");
	if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) {
		printf("connect: %s\n", strerror(errno));
		exit(1);
	}

	printf("closing ...\n");
	close(sockfd);	/* send RST */
	printf("closed.\n");

	exit(0);
}

[-- Attachment #3: poll.c --]
[-- Type: text/x-csrc, Size: 1702 bytes --]

#include <poll.h>
#include <sys/socket.h>

#include <netinet/in.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strdup */
#include <unistd.h> /* getopt */

#define PORT (22)

#define BACKLOG 20

#ifndef INFTIM
#define INFTIM (-1)
#endif


extern char *optarg;

int main(argc, argv)
	int argc;
	char *argv[];
{
	struct pollfd nfd;
	struct sockaddr_in saddr, caddr;
	int fd;
	int c;
	int clientfd;
	size_t len;
	unsigned short port = PORT;

	
	bzero(&saddr, sizeof(struct sockaddr_in));
	bzero(&caddr, sizeof(struct sockaddr_in));

	while ((c = getopt(argc, argv, "h:p:")) != -1) {
		switch (c) {
			case 'p':
				port = atoi(optarg);
				break;
			default:
				break;
		}
	}

	saddr.sin_family = AF_INET;
	saddr.sin_port   = htons(port);
	saddr.sin_addr.s_addr   = INADDR_ANY;

	fd = socket(AF_INET, SOCK_STREAM, 0);

	if (fd < 0) {
		printf("socket\n");
		exit(1);
	}

	if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) < 0) {
		printf("bind\n");
		exit(1);
	}

	if (listen(fd, BACKLOG) < 0) {
		printf("listen\n");
		exit(1);
	}

	len = sizeof(struct sockaddr_in);

	if ((clientfd = accept(fd, (struct sockaddr *)&caddr, &len)) < 0) {
		printf("accept: %s\n", strerror(errno)), exit(1);
	}

	printf("accept ok.\n");

	/* reset */	
	nfd.fd = clientfd;
	nfd.events = 0;
	nfd.revents = 0;

	if (poll(&nfd, 1, INFTIM) < 0) 
		printf("poll: %s\n", strerror(errno)), exit(1);

	if (nfd.revents & POLLERR) 
		printf("poll: POLLERR set\n");

	if (nfd.revents & POLLHUP)
		printf("poll: POLLHUP set\n");

	if (nfd.revents & POLLNVAL)
		printf("poll: POLLNVAL set\n"); /* should not happen */

	close(clientfd);
	printf("sever terminating\n");
	exit(0);
}

      reply	other threads:[~2002-08-16  1:08 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-08-10 10:24 [PATCH] connect() return value Geoffrey Lee
2002-08-11 20:46 ` kuznet
2002-08-11 23:25   ` Geoffrey Lee
2002-08-12  1:28     ` kuznet
2002-08-13  2:21       ` Geoffrey Lee
2002-08-13  4:44         ` kuznet
2002-08-13  5:37           ` Geoffrey Lee
2002-08-13 10:17             ` kuznet
2002-08-13 11:34               ` Geoffrey Lee
2002-08-13 13:47                 ` kuznet
2002-08-13 14:32                   ` Geoffrey Lee
2002-08-13 15:28                     ` kuznet
2002-08-13 23:51                       ` Geoffrey Lee
2002-08-14  0:36                         ` kuznet
2002-08-14  3:02                           ` Geoffrey Lee
2002-08-14  4:16                             ` kuznet
2002-08-14  4:57                               ` Geoffrey Lee
2002-08-14 17:25                                 ` kuznet
2002-08-15  3:25                                   ` glee
2002-08-15  3:15                                     ` David S. Miller
2002-08-15 11:02                                       ` Geoffrey Lee
2002-08-15 21:23                                         ` David S. Miller
2002-08-16  1:08                                           ` Geoffrey Lee [this message]

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=20020816010809.GA28446@anakin.wychk.org \
    --to=glee@gnupilgrims.org \
    --cc=davem@redhat.com \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=netdev@oss.sgi.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).