#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int curtest = 1;
#define OK(testname) printf("ok %d - %s\n", curtest, testname); \
curtest++;
static void
fail(int error, const char *func, const char *socktype, const char *rest)
{
printf("not ok %d\n", curtest);
if (socktype == NULL)
printf("# %s(): %s\n", func, strerror(error));
else if (rest == NULL)
printf("# %s(%s): %s\n", func, socktype,
strerror(error));
else
printf("# %s(%s, %s): %s\n", func, socktype, rest,
strerror(error));
exit(-1);
}
static void
fail_assertion(const char *func, const char *socktype, const char *rest,
const char *assertion)
{
printf("not ok %d - %s\n", curtest, assertion);
if (socktype == NULL)
printf("# %s(): assertion %s failed\n", func,
assertion);
else if (rest == NULL)
printf("# %s(%s): assertion %s failed\n", func,
socktype, assertion);
else
printf("# %s(%s, %s): assertion %s failed\n", func,
socktype, rest, assertion);
exit(-1);
}
static void
test_evfilt_read(int kq, int fd[2], const char *socktype)
{
struct timespec ts;
struct kevent ke;
ssize_t len;
char ch;
int i;
EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD");
OK("EVFILT_READ, EV_ADD");
ts.tv_sec = 0;
ts.tv_nsec = 0;
i = kevent(kq, NULL, 0, &ke, 1, &ts);
if (i == -1)
fail(errno, "kevent", socktype, "EVFILT_READ");
OK("EVFILT_READ");
if (i != 0)
fail_assertion("kevent", socktype, "EVFILT_READ",
"empty socket unreadable");
OK("empty socket unreadable");
ch = 'a';
len = write(fd[1], &ch, sizeof(ch));
if (len == -1)
fail(errno, "write", socktype, NULL);
OK("write one byte");
if (len != sizeof(ch))
fail_assertion("write", socktype, NULL, "write length");
OK("write one byte length");
ts.tv_sec = 0;
ts.tv_nsec = 0;
i = kevent(kq, NULL, 0, &ke, 1, &ts);
if (i == -1)
fail(errno, "kevent", socktype, "EVFILT_READ");
OK("EVFILT_READ");
if (i != 1)
fail_assertion("kevent", socktype, "EVFILT_READ",
"non-empty socket unreadable");
OK("non-empty socket unreadable");
len = read(fd[0], &ch, sizeof(ch));
if (len == -1)
fail(errno, "read", socktype, NULL);
OK("read one byte");
if (len != sizeof(ch))
fail_assertion("read", socktype, NULL, "read length");
OK("read one byte length");
ts.tv_sec = 0;
ts.tv_nsec = 0;
i = kevent(kq, NULL, 0, &ke, 1, &ts);
if (i == -1)
fail(errno, "kevent", socktype, "EVFILT_READ");
OK("EVFILT_READ");
if (i != 0)
fail_assertion("kevent", socktype, "EVFILT_READ",
"empty socket unreadable");
OK("empty socket unreadable");
EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL);
if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE");
OK("EVFILT_READ, EV_DELETE");
}
static void
test_evfilt_write(int kq, int fd[2], const char *socktype)
{
struct timespec ts;
struct kevent ke;
ssize_t len;
char ch;
int i;
EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD");
OK("EVFILE_WRITE, EV_ADD");
ts.tv_sec = 0;
ts.tv_nsec = 0;
i = kevent(kq, NULL, 0, &ke, 1, &ts);
if (i == -1)
fail(errno, "kevent", socktype, "EVFILT_WRITE");
OK("EVFILE_WRITE");
if (i != 1)
fail_assertion("kevent", socktype, "EVFILT_WRITE",
"empty socket unwritable");
OK("empty socket unwritable");
ch = 'a';
while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {};
if (len == -1 && errno != EAGAIN && errno != ENOBUFS)
fail(errno, "write", socktype, NULL);
OK("write");
if (len != -1 && len != sizeof(ch))
fail_assertion("write", socktype, NULL, "write length");
OK("write length");
ts.tv_sec = 0;
ts.tv_nsec = 0;
i = kevent(kq, NULL, 0, &ke, 1, &ts);
if (i == -1)
fail(errno, "kevent", socktype, "EVFILT_WRITE");
OK("EVFILT_WRITE");
if (i != 0)
fail_assertion("kevent", socktype, "EVFILT_WRITE",
"full socket writable");
OK("full socket writable");
EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE");
OK("EVFILT_WRITE, EV_DELETE");
}
int
main(void)
{
int kq, sv[2];
printf("1..49\n");
kq = kqueue();
if (kq == -1)
fail(errno, "kqueue", NULL, NULL);
OK("kqueue()");
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);
OK("socketpair() 1");
if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
OK("fcntl() 1");
if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
OK("fnctl() 2");
test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM");
if (close(sv[0]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");
OK("close() 1");
if (close(sv[1]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");
OK("close() 2");
#if 0
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);
if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM");
if (close(sv[0]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");
if (close(sv[1]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");
#endif
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);
OK("socketpair() 2");
if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
OK("fcntl() 3");
if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
OK("fcntl() 4");
test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM");
if (close(sv[0]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");
OK("close() 3");
if (close(sv[1]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");
OK("close() 4");
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);
OK("socketpair() 3");
if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
OK("fcntl() 5");
if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
OK("fcntl() 6");
test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM");
if (close(sv[0]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");
OK("close() 5");
if (close(sv[1]) == -1)
fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");
OK("close() 6");
if (close(kq) == -1)
fail(errno, "close", "kq", NULL);
OK("close() 7");
return (0);
}