From owner-freebsd-bugs Wed Feb 27 19:40:54 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id 8579837B41C for ; Wed, 27 Feb 2002 19:40:02 -0800 (PST) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g1S3e2376790; Wed, 27 Feb 2002 19:40:02 -0800 (PST) (envelope-from gnats) Received: from segfault.monkeys.com (246.dsl6660157.rstatic.surewest.net [66.60.157.246]) by hub.freebsd.org (Postfix) with ESMTP id 85FAE37B400 for ; Wed, 27 Feb 2002 19:39:44 -0800 (PST) Received: by segfault.monkeys.com (Postfix, from userid 1237) id A169F660B; Wed, 27 Feb 2002 19:39:38 -0800 (PST) Message-Id: <20020228033938.A169F660B@segfault.monkeys.com> Date: Wed, 27 Feb 2002 19:39:38 -0800 (PST) From: rfg@monkeys.com Reply-To: rfg@monkeys.com To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.113 Subject: kern/35396: poll(2) doesn't set POLLERR for failed connect(2) attempts Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 35396 >Category: kern >Synopsis: poll(2) doesn't set POLLERR for failed connect(2) attempts >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Feb 27 19:40:01 PST 2002 >Closed-Date: >Last-Modified: >Originator: Ronald F. Guilmette >Release: FreeBSD 4.3-RELEASE i386 >Organization: Infinite Monkeys & Co. >Environment: FreeBSD 4.3-RELEASE #0 >Description: If you create a socket and then use fcntl(2) to set O_NONBLOCK for it (thus making it non-blocking) and then you start up an asynchronous connect(2) on the socket to some dead host/port, and then use poll(2) to try to check status on the state of the socket, eventually, the connect attempt will actually fail (after a suitable number of failed retries) and the call to poll(2) will return, but in the specific `struct pollfd' structure corresponding to the socket's fd, the POLLERR bit will _not_ be set in the `revents' field. That (POLLERR) bit _should_ be set when such errors occur however. The behavion of poll(2) under FreeBSD 4.3 is clearly not correct behavior. The connect attempt _has_ failed with an error. But poll(2) is failing to properly set the corresponding POLLERR bit to note that fact. (See my posting today to freebsd-questions for a bit more background on this problem.) >How-To-Repeat: The short example program below illustrates the problem. It attempts to connect to a dead/filtered port on one of my servers. This program should (after a short delay) print "poll(2) indicates connect error", but instead it prints "getsockopt(2) indicates connect error", thus indicating that the connection error has _not_ been flaged via a POLLERR bit being set. cut here ======================================================================= /* poll(2) error test #1 */ #include #include #include #include #include #include #include #include #include #include #include #include static struct protoent *tcp_proto; static void fatal (register char const *const fmt, register char const *const arg) { fprintf (stderr, fmt, arg); putc ('\n', stderr); exit (1); } static void poll_for_completion (register int const fd) { auto struct pollfd pfd; auto int err; auto socklen_t err_size; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; if (poll (&pfd, 1, -1) == -1) fatal ("Error in poll: %s", strerror (errno)); if (pfd.revents & POLLERR) fatal ("poll(2) indicates connect error", NULL); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &err, &err_size) == -1) fatal ("Error in getsockopt: %s", strerror (errno)); if (err != 0) fatal ("getsockopt(2) indicates connect error: %s", strerror (err)); fatal ("Connect successful", NULL); } static void start_connecting (struct in_addr addr, unsigned short port) { auto struct sockaddr_in sin; register int fd; if ((fd = socket (PF_INET, SOCK_STREAM, tcp_proto->p_proto)) == -1) fatal ("Error creating socket: %s", strerror (errno)); if (fcntl (fd, F_SETFL, O_NONBLOCK) == -1) fatal ("Error setting O_NONBLOCK for socket: %s", strerror (errno)); memset (&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_addr = addr; sin.sin_port = htons (port); if (connect (fd, (struct sockaddr *) &sin, sizeof sin) == -1) { if (errno != EINPROGRESS) { printf ("Connection failed immediately\n"); close (fd); } else poll_for_completion (fd); } else { printf ("Connection completed immediately\n"); close (fd); } } int main (void) { static char const protocol_name[] = "tcp"; auto struct in_addr addr; if ((tcp_proto = getprotobyname (protocol_name)) == NULL) fatal ("Cannot find number for protocol: %s", protocol_name); inet_aton ("66.60.157.246", &addr); start_connecting (addr, 32767); return 0; } ======================================================================= >Fix: Hack the kernel and make poll(2) properly check for connect(2) errors. If it finds any, have it set the POLLERR bit in the relevant `struct pollfd' structure. >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message