mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-23 11:49:50 +00:00
Handle ENOTSOCK properly
git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/trunk@282 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
parent
5df12e7eb2
commit
cc1c0f78fd
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2010-08-01 v0.9 r282
|
||||
------------------------------------------------------------------------
|
||||
|
||||
* Set kevent.data = 1 for passive sockets that have at least one pending
|
||||
connection.
|
||||
(Credit to Julien Blache for finding and researching this bug)
|
||||
|
||||
* Fix various compilation errors under Solaris.
|
||||
(Credit to Joakim Johansson for testing and providing patches)
|
||||
|
||||
2010-07-21 v0.8 r264
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
program="libkqueue"
|
||||
version="0.9pre"
|
||||
version="0.9"
|
||||
abi_major="0"
|
||||
abi_minor="0"
|
||||
abi_version="$abi_major.$abi_minor"
|
||||
|
8
configure
vendored
8
configure
vendored
@ -165,15 +165,15 @@ check_linker() {
|
||||
# Appears to be a problem with GCC 4.0 and binutils
|
||||
#
|
||||
default_ld="$cc"
|
||||
ldflags="-o $program.so.$abi_major.$abi_minor $ldflags"
|
||||
ldflags="-shared -o $program.so.$abi_major.$abi_minor $ldflags"
|
||||
|
||||
# FIXME: port to solaris
|
||||
if [ "$target" = "linux" ] ; then
|
||||
ldflags="-shared $ldflags -Wl,-export-dynamic -Wl,-soname,$program.so.$abi_major"
|
||||
ldflags="$ldflags -Wl,-export-dynamic -Wl,-soname,$program.so.$abi_major"
|
||||
fi
|
||||
|
||||
if [ "$target" = "solaris" ] ; then
|
||||
default_ld="/usr/ccs/bin/ld"
|
||||
ldflags="-G $ldflags"
|
||||
ldflags="$ldflags"
|
||||
fi
|
||||
|
||||
finalize ld "$default_ld"
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private.h"
|
||||
@ -139,3 +141,31 @@ knote_events_pending(struct filter *filt)
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if a socket is active or passive.
|
||||
*/
|
||||
int
|
||||
knote_get_socket_type(struct knote *kn)
|
||||
{
|
||||
socklen_t slen;
|
||||
int i, lsock;
|
||||
|
||||
slen = sizeof(lsock);
|
||||
lsock = 0;
|
||||
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, &lsock, &slen);
|
||||
if (i < 0) {
|
||||
switch (errno) {
|
||||
case ENOTSOCK: /* same as lsock = 0 */
|
||||
return (0);
|
||||
break;
|
||||
default:
|
||||
dbg_printf("getsockopt(3) failed: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
if (lsock)
|
||||
kn->flags |= KNFL_PASSIVE_SOCKET;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
@ -61,11 +61,17 @@ struct kqueue;
|
||||
struct kevent;
|
||||
struct evfilt_data;
|
||||
|
||||
/*
|
||||
* Flags used by knote->flags
|
||||
*/
|
||||
#define KNFL_PASSIVE_SOCKET (0x01) /* Socket is in listen(2) mode */
|
||||
|
||||
/* TODO: Make this a variable length structure and allow
|
||||
each filter to add custom fields at the end.
|
||||
*/
|
||||
struct knote {
|
||||
struct kevent kev;
|
||||
int flags;
|
||||
union {
|
||||
int pfd; /* Used by timerfd */
|
||||
int events; /* Used by socket */
|
||||
@ -135,6 +141,7 @@ struct knote * knote_new(void);
|
||||
void knote_free(struct filter *, struct knote *);
|
||||
void knote_free_all(struct filter *);
|
||||
void knote_insert(struct filter *, struct knote *);
|
||||
int knote_get_socket_type(struct knote *);
|
||||
|
||||
/* TODO: these deal with the eventlist, should use a different prefix */
|
||||
void knote_enqueue(struct filter *, struct knote *);
|
||||
|
@ -127,15 +127,22 @@ evfilt_socket_copyout(struct filter *filt,
|
||||
if (ev->events & EPOLLERR)
|
||||
dst->fflags = 1; /* FIXME: Return the actual socket error */
|
||||
|
||||
/* On return, data contains the number of bytes of protocol
|
||||
data available to read.
|
||||
*/
|
||||
if (ioctl(dst->ident,
|
||||
(dst->filter == EVFILT_READ) ? SIOCINQ : SIOCOUTQ,
|
||||
&dst->data) < 0) {
|
||||
/* race condition with socket close, so ignore this error */
|
||||
dbg_puts("ioctl(2) of socket failed");
|
||||
dst->data = 0;
|
||||
if (kn->flags & KNFL_PASSIVE_SOCKET) {
|
||||
/* On return, data contains the length of the
|
||||
socket backlog. This is not available under Linux.
|
||||
*/
|
||||
dst->data = 1;
|
||||
} else {
|
||||
/* On return, data contains the number of bytes of protocol
|
||||
data available to read.
|
||||
*/
|
||||
if (ioctl(dst->ident,
|
||||
(dst->filter == EVFILT_READ) ? SIOCINQ : SIOCOUTQ,
|
||||
&dst->data) < 0) {
|
||||
/* race condition with socket close, so ignore this error */
|
||||
dbg_puts("ioctl(2) of socket failed");
|
||||
dst->data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (kn->kev.flags & EV_DISPATCH) {
|
||||
@ -159,6 +166,9 @@ evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
|
||||
if (knote_get_socket_type(kn) < 0)
|
||||
return (-1);
|
||||
|
||||
/* Convert the kevent into an epoll_event */
|
||||
if (kn->kev.filter == EVFILT_READ)
|
||||
kn->data.events = EPOLLIN | EPOLLRDHUP;
|
||||
|
@ -91,6 +91,9 @@ evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
|
||||
#if TODO
|
||||
struct epoll_event ev;
|
||||
|
||||
if (knote_get_socket_type(kn) < 0)
|
||||
return (-1);
|
||||
|
||||
/* Convert the kevent into an epoll_event */
|
||||
if (kn->kev.filter == EVFILT_READ)
|
||||
kn->kn_events = EPOLLIN | EPOLLRDHUP;
|
||||
|
43
test/read.c
43
test/read.c
@ -14,6 +14,8 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include "common.h"
|
||||
|
||||
static int __thread kqfd;
|
||||
@ -183,6 +185,46 @@ test_kevent_socket_oneshot(void)
|
||||
kevent_socket_drain();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if the data field returns 1 when a listen(2) socket has
|
||||
* a pending connection.
|
||||
*/
|
||||
void
|
||||
test_kevent_socket_listen_backlog(void)
|
||||
{
|
||||
struct kevent kev;
|
||||
struct sockaddr_in sain;
|
||||
socklen_t sa_len = sizeof(sain);
|
||||
int one = 1;
|
||||
const short port = 14973;
|
||||
int clnt, srvr;
|
||||
|
||||
/* Create a passive socket */
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = htons(port);
|
||||
if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0) abort();
|
||||
if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &one, sizeof(one)) != 0) abort();
|
||||
if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) abort();
|
||||
if (listen(srvr, 100) < 0) abort();
|
||||
|
||||
/* Watch for events on the socket */
|
||||
test_no_kevents(kqfd);
|
||||
kevent_add(kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
|
||||
test_no_kevents(kqfd);
|
||||
|
||||
/* Simulate a client connecting to the server */
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = htons(port);
|
||||
sain.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0) abort();
|
||||
if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0) abort();
|
||||
|
||||
/* Verify that data=1 */
|
||||
kev.data = 1;
|
||||
kevent_cmp(&kev, kevent_get(kqfd));
|
||||
test_no_kevents(kqfd);
|
||||
}
|
||||
|
||||
#if HAVE_EV_DISPATCH
|
||||
void
|
||||
@ -284,6 +326,7 @@ test_evfilt_read(int _kqfd)
|
||||
#if HAVE_EV_DISPATCH
|
||||
test(kevent_socket_dispatch);
|
||||
#endif
|
||||
test(kevent_socket_listen_backlog);
|
||||
test(kevent_socket_eof);
|
||||
close(sockfd[0]);
|
||||
close(sockfd[1]);
|
||||
|
@ -119,6 +119,9 @@ When an EVFILT_SIGNAL event is generated, the <code>data</code> field
|
||||
is set to 1 regardless of how many times the signal was received by the process.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
When an EVFILT_READ event occurs on a listening socket, the <code>data</code> field is set to 1 regardless of how many pending connections are available.
|
||||
|
||||
<!--
|
||||
<li>
|
||||
The EVFILT_PROC filter only supports the NOTE_EXIT flag, and the <code>ident</code> field must contain the PID of a child of the current process. This filter is only suitable as an event-driven replacement for the <code>wait(2)</code> family of system calls.
|
||||
|
Loading…
Reference in New Issue
Block a user