Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/common/kevent.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ kevent_copyin_one(struct kqueue *kq, const struct kevent *src)
memcpy(&kn->kev, src, sizeof(kn->kev));
kn->kev.flags &= ~EV_ENABLE;
kn->kev.flags |= EV_ADD;//FIXME why?
kn->kn_kq = kq;
kn->kn_kq = kq;
assert(filt->kn_create);
if (filt->kn_create(filt, kn) < 0) {
knote_release(kn);
Expand Down
20 changes: 15 additions & 5 deletions src/common/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,24 @@ struct eventfd {
/*
* Flags used by knote->kn_flags
*/
#define KNFL_PASSIVE_SOCKET (0x01) /* Socket is in listen(2) mode */
#define KNFL_REGULAR_FILE (0x02) /* File descriptor is a regular file */
#define KNFL_STREAM_SOCKET (0x03) /* File descriptor is a stream socket */
#define KNFL_KNOTE_DELETED (0x10) /* The knote object is no longer valid */
#define KNFL_FILE (1U << 0U)
#define KNFL_PIPE (1U << 1U)
#define KNFL_BLOCKDEV (1U << 2U)
#define KNFL_CHARDEV (1U << 3U)
#define KNFL_SOCKET_PASSIVE (1U << 4U)
#define KNFL_SOCKET_STREAM (1U << 5U)
#define KNFL_SOCKET_DGRAM (1U << 6U)
#define KNFL_SOCKET_RDM (1U << 7U)
#define KNFL_SOCKET_SEQPACKET (1U << 8U)
#define KNFL_KNOTE_DELETED (1U << 31U)
#define KNFL_SOCKET (KNFL_SOCKET_STREAM |\
KNFL_SOCKET_DGRAM |\
KNFL_SOCKET_RDM |\
KNFL_SOCKET_SEQPACKET)

struct knote {
struct kevent kev;
int kn_flags;
unsigned int kn_flags;
union {
/* OLD */
int pfd; /* Used by timerfd */
Expand Down
100 changes: 76 additions & 24 deletions src/linux/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,32 +552,94 @@ linux_get_descriptor_type(struct knote *kn)
{
socklen_t slen;
struct stat sb;
int i, lsock, stype;
int ret, lsock, stype;
socklen_t out_len;
const int fd = (int)kn->kev.ident;

/*
* Test if the descriptor is a socket.
* Determine the actual descriptor type.
*/
if (fstat(kn->kev.ident, &sb) < 0) {
if (fstat(fd, &sb) < 0) {
dbg_perror("fstat(2)");
return (-1);
}
if (S_ISREG(sb.st_mode)) {
kn->kn_flags |= KNFL_REGULAR_FILE;
dbg_printf("fd %d is a regular file\n", (int)kn->kev.ident);
return (0);
switch (sb.st_mode & S_IFMT) {
case S_IFREG:
dbg_printf("fd %d is a regular file\n", fd);
kn->kn_flags |= KNFL_FILE;
break;

case S_IFIFO:
dbg_printf("fd %d is a pipe\n", fd);
kn->kn_flags |= KNFL_PIPE;
break;

case S_IFBLK:
dbg_printf("fd %d is a block device\n", fd);
kn->kn_flags |= KNFL_BLOCKDEV;
break;

case S_IFCHR:
dbg_printf("fd %d is a character device\n", fd);
kn->kn_flags |= KNFL_CHARDEV;
break;

case S_IFSOCK:
dbg_printf("fd %d is a socket\n", fd);
break; /* deferred type determination */

default:
errno = EBADF;
dbg_perror("unknown fd type");
return -1;
}

/*
* Test if the socket is active or passive.
*/
if (! S_ISSOCK(sb.st_mode))
if (!S_ISSOCK(sb.st_mode))
return (0);

/*
* Determine socket type.
*/
slen = sizeof(stype);
stype = 0;
ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, &stype, &slen);
if (ret < 0) {
dbg_perror("getsockopt(3)");
return (-1);
}
switch (stype) {
case SOCK_STREAM:
dbg_printf("fd %d is a stream socket\n", fd);
kn->kn_flags |= KNFL_SOCKET_STREAM;
break;

case SOCK_DGRAM:
dbg_printf("fd %d is a datagram socket\n", fd);
kn->kn_flags |= KNFL_SOCKET_DGRAM;
break;

case SOCK_RDM:
dbg_printf("fd %d is a reliable datagram socket\n", fd);
kn->kn_flags |= KNFL_SOCKET_RDM;
break;

case SOCK_SEQPACKET:
dbg_printf("fd %d is a sequenced and reliable datagram socket\n", fd);
kn->kn_flags |= KNFL_SOCKET_SEQPACKET;
break;

default:
errno = EBADF;
dbg_perror("unknown socket type");
return (-1);
}
slen = sizeof(lsock);
lsock = 0;
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, (char *) &lsock, &slen);
if (i < 0) {
ret = getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &lsock, &slen);
if (ret < 0) {
switch (errno) {
case ENOTSOCK: /* same as lsock = 0 */
break;
Expand All @@ -587,7 +649,7 @@ linux_get_descriptor_type(struct knote *kn)
}
} else {
if (lsock)
kn->kn_flags |= KNFL_PASSIVE_SOCKET;
kn->kn_flags |= KNFL_SOCKET_PASSIVE;
}

/*
Expand All @@ -597,8 +659,8 @@ linux_get_descriptor_type(struct knote *kn)
* Looking at SO_GET_FILTER is a good way of doing this.
*/
out_len = 0;
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_GET_FILTER, NULL, &out_len);
if (i < 0) {
ret = getsockopt(fd, SOL_SOCKET, SO_GET_FILTER, NULL, &out_len);
if (ret < 0) {
switch (errno) {
case ENOTSOCK: /* same as lsock = 0 */
break;
Expand All @@ -608,18 +670,8 @@ linux_get_descriptor_type(struct knote *kn)
}
} else {
if (out_len)
kn->kn_flags |= KNFL_PASSIVE_SOCKET;
}

slen = sizeof(stype);
stype = 0;
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_TYPE, (char *) &lsock, &slen);
if (i < 0) {
dbg_perror("getsockopt(3)");
return (-1);
kn->kn_flags |= KNFL_SOCKET_PASSIVE;
}
if (stype == SOCK_STREAM)
kn->kn_flags |= KNFL_STREAM_SOCKET;

return (0);
}
Expand Down
25 changes: 16 additions & 9 deletions src/linux/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ get_eof_offset(int fd)
int
evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr)
{
int ret;
int serr;
socklen_t slen = sizeof(serr);
struct epoll_event * const ev = (struct epoll_event *) ptr;

/* Special case: for regular files, return the offset from current position to end of file */
if (src->kn_flags & KNFL_REGULAR_FILE) {
if (src->kn_flags & KNFL_FILE) {
memcpy(dst, &src->kev, sizeof(*dst));
dst->data = get_eof_offset(src->kev.ident);

Expand Down Expand Up @@ -113,10 +116,14 @@ evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr)
if (ev->events & EPOLLHUP)
dst->flags |= EV_EOF;
#endif
if (ev->events & EPOLLERR)
dst->fflags = 1; /* FIXME: Return the actual socket error */
if (ev->events & EPOLLERR) {
if (src->kn_flags & KNFL_SOCKET) {
ret = getsockopt(src->kev.ident, SOL_SOCKET, SO_ERROR, &serr, &slen);
dst->fflags = ((ret < 0) ? errno : serr);
} else { dst->fflags = EIO; }
}

if (src->kn_flags & KNFL_PASSIVE_SOCKET) {
if (src->kn_flags & KNFL_SOCKET_PASSIVE) {
/* On return, data contains the length of the
socket backlog. This is not available under Linux.
*/
Expand All @@ -132,7 +139,7 @@ evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr)
dst->data = 0;
} else {
dst->data = i;
if (dst->data == 0 && src->kn_flags & KNFL_STREAM_SOCKET)
if (dst->data == 0 && src->kn_flags & KNFL_SOCKET_STREAM)
dst->flags |= EV_EOF;
}
}
Expand Down Expand Up @@ -164,7 +171,7 @@ evfilt_read_knote_create(struct filter *filt, struct knote *kn)
ev.data.ptr = kn;

/* Special case: for regular files, add a surrogate eventfd that is always readable */
if (kn->kn_flags & KNFL_REGULAR_FILE) {
if (kn->kn_flags & KNFL_FILE) {
int evfd;

kn->kn_epollfd = filter_epfd(filt);
Expand Down Expand Up @@ -210,7 +217,7 @@ evfilt_read_knote_delete(struct filter *filt, struct knote *kn)
if (kn->kev.flags & EV_DISABLE)
return (0);

if ((kn->kn_flags & KNFL_REGULAR_FILE) && (kn->kdata.kn_eventfd != -1)) {
if ((kn->kn_flags & KNFL_FILE) && (kn->kdata.kn_eventfd != -1)) {
if (kn->kn_registered && epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) {
dbg_perror("epoll_ctl(2)");
return (-1);
Expand All @@ -236,7 +243,7 @@ evfilt_read_knote_enable(struct filter *filt, struct knote *kn)
ev.events = kn->data.events;
ev.data.ptr = kn;

if (kn->kn_flags & KNFL_REGULAR_FILE) {
if (kn->kn_flags & KNFL_FILE) {
if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_eventfd, &ev) < 0) {
dbg_perror("epoll_ctl(2)");
return (-1);
Expand All @@ -254,7 +261,7 @@ evfilt_read_knote_enable(struct filter *filt, struct knote *kn)
int
evfilt_read_knote_disable(struct filter *filt, struct knote *kn)
{
if (kn->kn_flags & KNFL_REGULAR_FILE) {
if (kn->kn_flags & KNFL_FILE) {
if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) {
dbg_perror("epoll_ctl(2)");
return (-1);
Expand Down
40 changes: 24 additions & 16 deletions src/linux/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@
#include "private.h"

int
evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr)
evfilt_write_copyout(struct kevent *dst, struct knote *src, void *ptr)
{
int ret;
int serr;
socklen_t slen = sizeof(serr);
struct epoll_event * const ev = (struct epoll_event *) ptr;

epoll_event_dump(ev);
Expand All @@ -44,8 +47,12 @@ evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr)
if (ev->events & EPOLLHUP)
dst->flags |= EV_EOF;
#endif
if (ev->events & EPOLLERR)
dst->fflags = 1; /* FIXME: Return the actual socket error */
if (ev->events & EPOLLERR) {
if (src->kn_flags & KNFL_SOCKET) {
ret = getsockopt(src->kev.ident, SOL_SOCKET, SO_ERROR, &serr, &slen);
dst->fflags = ((ret < 0) ? errno : serr);
} else { dst->fflags = EIO; }
}

/* On return, data contains the the amount of space remaining in the write buffer */
if (ioctl(dst->ident, SIOCOUTQ, &dst->data) < 0) {
Expand All @@ -58,16 +65,17 @@ evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr)
}

int
evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
evfilt_write_knote_create(struct filter *filt, struct knote *kn)
{
struct epoll_event ev;

if (linux_get_descriptor_type(kn) < 0)
return (-1);

/* TODO: return EBADF? */
if (kn->kn_flags & KNFL_REGULAR_FILE)
if (kn->kn_flags & KNFL_FILE) {
errno = EBADF;
return (-1);
}

/* Convert the kevent into an epoll_event */
kn->data.events = EPOLLOUT;
Expand All @@ -84,7 +92,7 @@ evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
}

int
evfilt_socket_knote_modify(struct filter *filt, struct knote *kn,
evfilt_write_knote_modify(struct filter *filt, struct knote *kn,
const struct kevent *kev)
{
(void) filt;
Expand All @@ -94,7 +102,7 @@ evfilt_socket_knote_modify(struct filter *filt, struct knote *kn,
}

int
evfilt_socket_knote_delete(struct filter *filt, struct knote *kn)
evfilt_write_knote_delete(struct filter *filt, struct knote *kn)
{
if (kn->kev.flags & EV_DISABLE)
return (0);
Expand All @@ -103,7 +111,7 @@ evfilt_socket_knote_delete(struct filter *filt, struct knote *kn)
}

int
evfilt_socket_knote_enable(struct filter *filt, struct knote *kn)
evfilt_write_knote_enable(struct filter *filt, struct knote *kn)
{
struct epoll_event ev;

Expand All @@ -115,7 +123,7 @@ evfilt_socket_knote_enable(struct filter *filt, struct knote *kn)
}

int
evfilt_socket_knote_disable(struct filter *filt, struct knote *kn)
evfilt_write_knote_disable(struct filter *filt, struct knote *kn)
{
return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
}
Expand All @@ -124,10 +132,10 @@ const struct filter evfilt_write = {
EVFILT_WRITE,
NULL,
NULL,
evfilt_socket_copyout,
evfilt_socket_knote_create,
evfilt_socket_knote_modify,
evfilt_socket_knote_delete,
evfilt_socket_knote_enable,
evfilt_socket_knote_disable,
evfilt_write_copyout,
evfilt_write_knote_create,
evfilt_write_knote_modify,
evfilt_write_knote_delete,
evfilt_write_knote_enable,
evfilt_write_knote_disable,
};
8 changes: 4 additions & 4 deletions src/windows/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,24 +197,24 @@ windows_get_descriptor_type(struct knote *kn)
lsock = 0;
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, (char *)&lsock, &slen);
if (i == 0 && lsock)
kn->kn_flags |= KNFL_PASSIVE_SOCKET;
kn->kn_flags |= KNFL_SOCKET_PASSIVE;

slen = sizeof(stype);
stype = 0;
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_TYPE, (char *) &lsock, &slen);
i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_TYPE, (char *)&stype, &slen);
if (i < 0) {
dbg_perror("getsockopt(3)");
return (-1);
}
if (stype == SOCK_STREAM)
kn->kn_flags |= KNFL_STREAM_SOCKET;
kn->kn_flags |= KNFL_SOCKET_STREAM;
break;
}
default: {
struct stat sb;
if (fstat((int)kn->kev.ident, &sb) == 0) {
dbg_printf("HANDLE %d appears to be a regular file", kn->kev.ident);
kn->kn_flags |= KNFL_REGULAR_FILE;
kn->kn_flags |= KNFL_FILE;
}
}
}
Expand Down
Loading