Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Aug 2002 10:20:04 -0700 (PDT)
From:      Daniel Eischen <eischen@pcnet1.pcnet.com>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/42100: libc_r: accept(2) can't handle descriptor being closed/shutdown
Message-ID:  <200208281720.g7SHK4xA015629@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/42100; it has been noted by GNATS.

From: Daniel Eischen <eischen@pcnet1.pcnet.com>
To: archie@packetdesign.com
Cc:  
Subject: Re: bin/42100: libc_r: accept(2) can't handle descriptor being closed/shutdown
Date: Wed, 28 Aug 2002 10:08:40 -0400

 I hacked up your program a bit and it looks like the kernel
 isn't doing the right thing for accept() on a closed file
 descriptor.  If you take a look at lib/libc_r/uthread_accept.c,
 you'll see that it loops:
 
 	while ((ret = __sys_accept(fd, name, namelen)) < 0) {
 		/* Check if the socket is to block: */
 		if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0
 		    && (errno == EWOULDBLOCK || errno == EAGAIN)) {
 			/* Save the socket file descriptor: */
 			curthread->data.fd.fd = fd;
 			curthread->data.fd.fname = __FILE__;
 			curthread->data.fd.branch = __LINE__;
 	[...]
 
 waiting for errno to be something other than EWOULDBLOCK or
 EAGAIN.  So I modified your test program to mimic what libc_r
 was doing.  The kernel seems to ignore the fact that the
 file is closed and always returns EAGAIN.  I would expect
 EBADF or something.
 
 -- 
 Dan Eischen
 
 /* Set to "1" to abort on signal, or "0" for thread-based delayed abort */
 #ifndef SIGNAL_TEST
 #define SIGNAL_TEST     1
 #endif
 
 #ifdef __linux__
 #define _XOPEN_SOURCE   600
 #define _GNU_SOURCE     1
 #define _BSD_SOURCE     1
 #define _ISOC99_SOURCE  1
 #endif
 
 #include <sys/types.h>
 #define accept	__sys_accept
 #include <sys/socket.h>
 #undef accept
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 
 #include <fcntl.h>
 #define poll	__sys_poll
 #include <poll.h>
 #undef poll
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
 #include <err.h>
 
 #if SIGNAL_TEST
 static void     signal_handler(int sig);
 #else
 #include <pthread.h>
 static void     *thread_entry(void *arg);
 static pthread_t tid;
 #endif
 
 static int      sock;
 
 int
 main(int ac, char **av)
 {
 	struct sockaddr_in sin;
 	socklen_t slen;
 	struct pollfd fds;
 	int flags;
 	int ret;
 
 	/* Create socket */
 	if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
 		err(1, "socket");
 	memset(&sin, 0, sizeof(sin));
 #ifndef __linux__
 	sin.sin_len = sizeof(sin);
 #endif
 	sin.sin_family = AF_INET;
 	if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1)
 		err(1, "socket");
 	slen = sizeof(sin);
 	if (listen(sock, 10) == -1)
 		err(1, "listen");
 	/* Set non-blocking. */
 	if ((flags = fcntl(sock, F_GETFL, 0) < 0))
 		err(1, "fcntl");
 	flags |= O_NONBLOCK;
 	if (fcntl(sock, F_SETFL, flags) < 0)
 		err(1, "fcntl");
 
 #if SIGNAL_TEST
 	/* Register signal handler */
 	signal(SIGINT, signal_handler);
 	signal(SIGTERM, signal_handler);
 #else
 	/* Spawn thread */
 	if ((errno = pthread_create(&tid, NULL, thread_entry, NULL)) != 0)
 		err(1, "pthread_create");
 #endif
 
 	/* Listen for connections on socket */
 	printf("main: waiting for connection...\n");
 	while (((ret = __sys_accept(sock, (struct sockaddr *)&sin, &slen)) < 0)
 	    && (errno == EWOULDBLOCK || errno == EAGAIN)) {
 		printf("accept returned %d, errno %d\n", ret, errno);
 		fds.events = POLLRDNORM | POLLERR | POLLHUP;
 		fds.fd = sock;
 		__sys_poll(&fds, 1, 2000);
 	}
 	if (ret < 0)
 		err(1, "main: accept");
 	printf("main: got connection?\n");
 	return (0);
 }
 
 #if SIGNAL_TEST
 static void
 signal_handler(int sig)
 #else
 static void *
 thread_entry(void *arg)
 #endif
 {
 #if SIGNAL_TEST
 	printf("%s: rec'd signal %d...\n", __FUNCTION__, sig);
 #else
 	printf("%s: sleeping 2 seconds...\n", __FUNCTION__);
 	sleep(2);
 #endif
 	srandom(getpid() ^ time(NULL));
 	if ((random() & 0x00400000) != 0) {
 		printf("%s: shutdown()'ing socket...\n", __FUNCTION__);
 		if (shutdown(sock, SHUT_RDWR) == -1)
 			err(1, "thread: shutdown");
 	} else {
 		printf("%s: close()'ing socket...\n", __FUNCTION__);
 		if (close(sock) == -1)
 			err(1, "thread: shutdown");
 	}
 #if !SIGNAL_TEST
 	return (NULL);
 #endif
 }
 

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200208281720.g7SHK4xA015629>