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: