Subject: kern/12608: Need to F_SETOWN a socket before O_ASYNC works
To: None <gnats-bugs@gnats.netbsd.org>
From: None <cagney@tpgi.com.au>
List: netbsd-bugs
Date: 04/10/2001 21:01:09
>Number: 12608
>Category: kern
>Synopsis: Need to F_SETOWN a socket before O_ASYNC works
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Apr 10 21:02:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator: Andrew Cagney
>Release: 1.5.1_ALPHA
>Organization:
>Environment:
NetBSD localhost 1.5.1_ALPHA NetBSD 1.5.1_ALPHA (LULUnfs) #0: Sat Mar 31 21:42:51 EST 2001 boor@localhost:/usr/src/sys/arch/i386/compile/LULUnfs i386
>Description:
It would appear that, by default a socket has fcntl(F_GETOWN)
set to zero and consequently fcntl(F_SETFL, O_ASYNC) has no
effect unless the owner is set to getpid().
The FD created by accepting a connection on that socket does appear
to work.
Per how-to-repeat, adding code to get the owner and set it if zero
works around the problem.
I believe the code works without the set-owner on Solaris 2.5.1 and
FreeBSD 3.x.
>How-To-Repeat:
I've extracted the relevant code.Yes I should turn it into a real
program...
static void
nonblocking_fd (int fd)
{
#if defined(F_SETFL) && (defined (O_ASYNC) || defined (O_NONBLOCK))
int flags = fcntl (fd, F_GETFL, 0);
if (gdbsocket_log)
{
gdblog_string (gdbsocket_log, "[");
gdblog_long (gdbsocket_log, fd);
gdblog_string (gdbsocket_log, ":");
}
#if defined (O_NONBLOCK)
flags |= O_NONBLOCK;
if (gdbsocket_log)
gdblog_string (gdbsocket_log, " O_NONBLOCK");
#endif
if (gdbsocket_log)
gdblog_string (gdbsocket_log, "]\n");
fcntl (fd, F_SETFL, flags);
#endif
}
static void
async_fd (int fd)
{
int flags;
gdblog_string (gdbsocket_log, "[");
gdblog_long (gdbsocket_log, fd);
#if defined(F_SETFL) && (defined (O_ASYNC) || defined (O_NONBLOCK))
flags = fcntl (fd, F_GETFL, 0);
#if defined (O_ASYNC)
flags |= O_ASYNC;
gdblog_string (gdbsocket_log, " O_ASYNC");
#elif defined (FASYNC)
flags |= FASYNC;
gdblog_string (gdbsocket_log, " FASYNC");
#endif
fcntl (fd, F_SETFL, flags);
#endif
#if defined (F_SETOWN)
/* some systems don't set the process to deliver the SIGIO to. */
flags = fcntl (fd, F_GETOWN, 0);
if (flags == 0)
{
flags = getpid ();
fcntl (fd, F_SETOWN, flags);
gdblog_string (gdbsocket_log, " [OWN ");
gdblog_long (gdbsocket_log, flags);
gdblog_string (gdbsocket_log, "]");
}
#endif
gdblog_string (gdbsocket_log, "]\n");
}
void
gdbsocket_sigio_disable (void)
{
if (gdbsocket_log)
gdblog_string (gdbsocket_log, "[gdbsocket_sigio_disable");
signal (SIGIO, SIG_IGN);
if (gdbsocket_log)
gdblog_string (gdbsocket_log, "]\n");
}
/* Create our socket */
server_fd = socket (PF_INET, SOCK_STREAM, 0);
/* allow reuse */
on = 1;
setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof (on));
on = 1;
setsockopt (server_fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof (on));
/* bind it to the requested UDP port */
sockaddr.sin_family = PF_INET;
sockaddr.sin_addr.s_addr = htonl (INADDR_ANY);
sockaddr.sin_port = htons (port_nr);
if (bind (server_fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) < 0)
{
int te = errno;
close (server_fd);
gdblog_string (gdbsocket_log, " BIND ERROR]\n");
errno = te;
return -1;
}
listen (server_fd, 1);
/* Don't let a closed pipe kill us */
signal (SIGPIPE, SIG_IGN);
gdbsocket_sigio_disable ();
nonblocking_fd (server_fd);
async_fd (server_fd);
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted: