To be honest - I feared that when I saw your messages regarding this. Here is my original message from july. Attached is also a small test program.
Hi, I'm trying to use asio (that's boost::asio without boost) to handle listening sockets asynchronuosly. This appears not to work. There are also some reports on the net about this problem. I was able to reproduce the problem with a small C-programm that does the same steps as asio. The relevant sequence of system calls is: kqueue() = 3 (0x3) socket(PF_INET,SOCK_STREAM,6) = 4 (0x4) setsockopt(0x4,0xffff,0x800,0x7fffffffea2c,0x4) = 0 (0x0) kevent(3,{ 4,EVFILT_READ,EV_ADD|EV_CLEAR,0x0,0x0,0x0 4,EVFILT_WRITE,EV_ADD|EV_CLEAR,0x0,0x0,0x0 },2,0x0,0,0x0) = 0 (0x0) setsockopt(0x4,0xffff,0x4,0x7fffffffea2c,0x4) = 0 (0x0) bind(4,{ AF_INET 0.0.0.0:8080 },16) = 0 (0x0) listen(0x4,0x80) = 0 (0x0) ioctl(4,FIONBIO,0xffffea2c) = 0 (0x0) kevent(3,{ 4,EVFILT_READ,EV_ADD|EV_CLEAR,0x0,0x0,0x0 4,EVFILT_WRITE,EV_ADD|EV_CLEAR,0x0,0x0,0x0 },2,0x0,0,0x0) = 0 (0x0) kevent(3,0x0,0,0x7fffffffe5a0,32,0x0) ERR#4 'Interrupted system call' The problem here is that asio registers each file descriptor with EVFILT_READ and EVFILT_WRITE as soon as it is opened (first kevent call). After bringing the socket into the listening state and when async_accept() is called it registers the socket a second time. According to the man page this is perfectly legal and can be used to modify the registration. With this sequence of calls kevent() does not return when a connection is established successfully. I tracked down the problem and the reason is in soo_kqfilter(). This is called for the first EVFILT_READ registration and decides based on the SO_ACCEPTCONN flag which filter operations to use solisten_filtops or soread_filtops. In this case it chooses soread_filtops. The second EVFILT_READ registration does not call soo_kqfilter() again, but just updates the filter from the data and fflags field so the listening socket ends up with the wrong filter operations. -----Original Message----- From: Gleb Smirnoff [mailto:gleb...@freebsd.org] Sent: Wednesday, February 01, 2017 7:08 PM To: Hartmut Brandt Cc: src-committ...@freebsd.org; svn-src-all@freebsd.org; svn-src-h...@freebsd.org Subject: Re: svn commit: r313043 - head/sys/kern On Wed, Feb 01, 2017 at 01:12:07PM +0000, Hartmut Brandt wrote: H> Author: harti H> Date: Wed Feb 1 13:12:07 2017 H> New Revision: 313043 H> URL: https://svnweb.freebsd.org/changeset/base/313043 H> H> Log: H> Merge filt_soread and filt_solisten and decide what to do when checking H> for EVFILT_READ at the point of the check not when the event is registers. H> This fixes a problem with asio when accepting a connection. H> H> Reviewed by: kib@, Scott Mitchell This goes into opposite direction with what I am doing: https://reviews.freebsd.org/D9356 Can you please explain the problem with asio when accepting a connection? -- Totus tuus, Glebius.
#include <sys/socket.h> #include <sys/types.h> #include <sys/event.h> #include <sys/filio.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <stdio.h> #include <string.h> #include <err.h> static void wait_loop(int kq, int sock) { struct kevent ev[32]; struct sockaddr_in addr; socklen_t socklen; for (;;) { int nev = kevent(kq, NULL, 0, ev, 32, NULL); if (nev < 1) err(1, "kevent"); for (int i = 0; i < nev; ++i) { if (ev[i].ident == sock) { printf("accept\n"); int fd = accept(ev[i].ident, (struct sockaddr *)&addr, &socklen); if (fd == -1) err(1, "accept"); } } } } int main() { struct sockaddr_in addr; /* open a TCP socket */ int kq = kqueue(); int sock = socket(PF_INET, SOCK_STREAM, 0); struct kevent ev[2]; EV_SET(&ev[0], sock, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, NULL); EV_SET(&ev[1], sock, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, NULL); int opt = 1; setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) err(1, "kevent"); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); memset(&addr, 0, sizeof(addr)); addr.sin_port = htons(10000); bind(sock, (struct sockaddr *)&addr, sizeof(addr)); listen(sock, 0x80); ioctl(sock, FIONBIO, &opt); if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) err(1, "kevent"); wait_loop(kq, sock); }
_______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"