Bug 234258 - SIGIO not delivered on socket when incoming connection arrives
Summary: SIGIO not delivered on socket when incoming connection arrives
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 12.0-RELEASE
Hardware: i386 Any
: --- Affects Many People
Assignee: Jason A. Harmening
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2018-12-21 22:04 UTC by Kenneth Adelman
Modified: 2019-01-21 08:27 UTC (History)
3 users (show)

See Also:
jah: mfc-stable12+


Attachments
proposed patch (369 bytes, patch)
2018-12-28 18:33 UTC, Jason A. Harmening
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Kenneth Adelman 2018-12-21 22:04:52 UTC
If a socket is set:

fcntl(sock, F_SETOWN, getpid()) and 
fcntl(sock, F_SETFL,O_ASYNC)

when a connection arrives a SIGIO signal should be delivered to the appropriate process. Under FreeBSD 11.2 and prior releases, this works. Under FreeBSD 12.0-RELEASE, no signal is delivered.  This is the case with at least TCP and UNIX domain sockets.

Duplicate by compiling and running the attached source code. "telnet 127.0.0.1 2666" to tickle the code with an incoming connection. Expected behavior is for the signal handler to fire and print "signalfired(): SIGIO fired" to stderr. Under FreeBSD 11.2 and prior (back to at least FreeBSD 2 the code that relied on this worked), this works. Under FreeBSD 12.0-RELEASE the signal is not delivered.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>


static void signalfired()
{
        fprintf(stderr,"signalfired(): SIGIO fired\n");
}

int main(void)
{
        int sock;
        struct sockaddr_in sin = { AF_INET };  /* socket address */

        sin.sin_addr.s_addr = INADDR_ANY;
        sin.sin_port = htons(2666);

        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) {
            perror("socket");
            exit(1);
        }

        if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0){
            perror("bind");
            exit(1);
        }

        if (signal(SIGIO,(void *) signalfired)) {
            perror("trapping signal");
            exit(1);
        }
        if (fcntl(sock, F_SETOWN, getpid()) == -1) {
            perror("fcntl(F_SETOWN)");
            exit(1);
        }
        if (fcntl(sock, F_SETFL, O_ASYNC) == -1) {
            perror("fcntl(F_SETFL)");
            exit(1);
        }

        if (listen(sock, 10) < 0) {
            perror("listen");
            exit(1);
        }
        fprintf(stderr,"sleeping, test by \"telnet localhost %d\"\n",2666);
        sleep(10000);
}
Comment 1 Jason A. Harmening freebsd_committer freebsd_triage 2018-12-27 19:37:12 UTC
It looks like this is fallout from the split between dataflow and listening sockets done in r319722.  Listening sockets now take a completely separate path through solisten_wakeup(), which unlike sowakeup() does not pend SIGIO for SS_ASYNC sockets.
Comment 2 Jason A. Harmening freebsd_committer freebsd_triage 2018-12-28 18:33:01 UTC
Created attachment 200584 [details]
proposed patch
Comment 3 Kenneth Adelman 2018-12-29 09:03:49 UTC
I've rebuilt 12.0-RELEASE from sources with this tiny edit and can confirm that (1) the minimum case source code works as expected, and (2) the application I was debugging that brought the problem to my attention now works. Thanks!
Comment 4 commit-hook freebsd_committer freebsd_triage 2019-01-13 20:34:32 UTC
A commit references this bug:

Author: jah
Date: Sun Jan 13 20:33:55 UTC 2019
New revision: 343005
URL: https://svnweb.freebsd.org/changeset/base/343005

Log:
  Handle SIGIO for listening sockets

  r319722 separated struct socket and parts of the socket I/O path into
  listening-socket-specific and dataflow-socket-specific pieces.  Listening
  socket connection notifications are now handled by solisten_wakeup() instead
  of sowakeup(), but solisten_wakeup() does not currently post SIGIO to the
  owning process.

  PR:	234258
  Reported by:	Kenneth Adelman
  MFC after:	1 week
  Differential Revision:	https://reviews.freebsd.org/D18664

Changes:
  head/sys/kern/uipc_socket.c
Comment 5 commit-hook freebsd_committer freebsd_triage 2019-01-21 08:25:37 UTC
A commit references this bug:

Author: jah
Date: Mon Jan 21 08:24:49 UTC 2019
New revision: 343254
URL: https://svnweb.freebsd.org/changeset/base/343254

Log:
  MFC r343005: Handle SIGIO for listening sockets

  r319722 separated struct socket and parts of the socket I/O path into
  listening-socket-specific and dataflow-socket-specific pieces.  Listening
  socket connection notifications are now handled by solisten_wakeup() instead
  of sowakeup(), but solisten_wakeup() does not currently post SIGIO to the
  owning process.

  PR:	234258

Changes:
_U  stable/12/
  stable/12/sys/kern/uipc_socket.c