Path: blob/main/tools/regression/sockets/kqueue/kqueue.c
48254 views
/*-1* Copyright (c) 2004 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/types.h>27#include <sys/event.h>28#include <sys/socket.h>29#include <sys/time.h>3031#include <errno.h>32#include <fcntl.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <unistd.h>3738static int curtest = 1;3940/*-41* This test uses UNIX domain socket pairs to perform some basic exercising42* of kqueue functionality on sockets. In particular, testing that for read43* and write filters, we see the correct detection of whether reads and44* writes should actually be able to occur.45*46* TODO:47* - Test read/write filters for listen/accept sockets.48* - Handle the XXXRW below regarding datagram sockets.49* - Test that watermark/buffer size "data" fields returned by kqueue are50* correct.51* - Check that kqueue does something sensible when the remote endpoing is52* closed.53*/5455#define OK(testname) printf("ok %d - %s\n", curtest, testname); \56curtest++;5758static void59fail(int error, const char *func, const char *socktype, const char *rest)60{6162printf("not ok %d\n", curtest);6364if (socktype == NULL)65printf("# %s(): %s\n", func, strerror(error));66else if (rest == NULL)67printf("# %s(%s): %s\n", func, socktype,68strerror(error));69else70printf("# %s(%s, %s): %s\n", func, socktype, rest,71strerror(error));72exit(-1);73}7475static void76fail_assertion(const char *func, const char *socktype, const char *rest,77const char *assertion)78{7980printf("not ok %d - %s\n", curtest, assertion);8182if (socktype == NULL)83printf("# %s(): assertion %s failed\n", func,84assertion);85else if (rest == NULL)86printf("# %s(%s): assertion %s failed\n", func,87socktype, assertion);88else89printf("# %s(%s, %s): assertion %s failed\n", func,90socktype, rest, assertion);91exit(-1);92}9394/*95* Test read kevent on a socket pair: check to make sure endpoint 0 isn't96* readable when we start, then write to endpoint 1 and confirm that endpoint97* 0 is now readable. Drain the write, then check that it's not readable98* again. Use non-blocking kqueue operations and socket operations.99*/100static void101test_evfilt_read(int kq, int fd[2], const char *socktype)102{103struct timespec ts;104struct kevent ke;105ssize_t len;106char ch;107int i;108109EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL);110if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)111fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD");112OK("EVFILT_READ, EV_ADD");113114/*115* Confirm not readable to begin with, no I/O yet.116*/117ts.tv_sec = 0;118ts.tv_nsec = 0;119i = kevent(kq, NULL, 0, &ke, 1, &ts);120if (i == -1)121fail(errno, "kevent", socktype, "EVFILT_READ");122OK("EVFILT_READ");123if (i != 0)124fail_assertion("kevent", socktype, "EVFILT_READ",125"empty socket unreadable");126OK("empty socket unreadable");127128/*129* Write a byte to one end.130*/131ch = 'a';132len = write(fd[1], &ch, sizeof(ch));133if (len == -1)134fail(errno, "write", socktype, NULL);135OK("write one byte");136if (len != sizeof(ch))137fail_assertion("write", socktype, NULL, "write length");138OK("write one byte length");139140/*141* Other end should now be readable.142*/143ts.tv_sec = 0;144ts.tv_nsec = 0;145i = kevent(kq, NULL, 0, &ke, 1, &ts);146if (i == -1)147fail(errno, "kevent", socktype, "EVFILT_READ");148OK("EVFILT_READ");149if (i != 1)150fail_assertion("kevent", socktype, "EVFILT_READ",151"non-empty socket unreadable");152OK("non-empty socket unreadable");153154/*155* Read a byte to clear the readable state.156*/157len = read(fd[0], &ch, sizeof(ch));158if (len == -1)159fail(errno, "read", socktype, NULL);160OK("read one byte");161if (len != sizeof(ch))162fail_assertion("read", socktype, NULL, "read length");163OK("read one byte length");164165/*166* Now re-check for readability.167*/168ts.tv_sec = 0;169ts.tv_nsec = 0;170i = kevent(kq, NULL, 0, &ke, 1, &ts);171if (i == -1)172fail(errno, "kevent", socktype, "EVFILT_READ");173OK("EVFILT_READ");174if (i != 0)175fail_assertion("kevent", socktype, "EVFILT_READ",176"empty socket unreadable");177OK("empty socket unreadable");178179EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL);180if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)181fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE");182OK("EVFILT_READ, EV_DELETE");183}184185static void186test_evfilt_write(int kq, int fd[2], const char *socktype)187{188struct timespec ts;189struct kevent ke;190ssize_t len;191char ch;192int i;193194EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL);195if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)196fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD");197OK("EVFILE_WRITE, EV_ADD");198199/*200* Confirm writable to begin with, no I/O yet.201*/202ts.tv_sec = 0;203ts.tv_nsec = 0;204i = kevent(kq, NULL, 0, &ke, 1, &ts);205if (i == -1)206fail(errno, "kevent", socktype, "EVFILT_WRITE");207OK("EVFILE_WRITE");208if (i != 1)209fail_assertion("kevent", socktype, "EVFILT_WRITE",210"empty socket unwritable");211OK("empty socket unwritable");212213/*214* Write bytes into the socket until we can't write anymore.215*/216ch = 'a';217while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {};218if (len == -1 && errno != EAGAIN && errno != ENOBUFS)219fail(errno, "write", socktype, NULL);220OK("write");221if (len != -1 && len != sizeof(ch))222fail_assertion("write", socktype, NULL, "write length");223OK("write length");224225/*226* Check to make sure the socket is no longer writable.227*/228ts.tv_sec = 0;229ts.tv_nsec = 0;230i = kevent(kq, NULL, 0, &ke, 1, &ts);231if (i == -1)232fail(errno, "kevent", socktype, "EVFILT_WRITE");233OK("EVFILT_WRITE");234if (i != 0)235fail_assertion("kevent", socktype, "EVFILT_WRITE",236"full socket writable");237OK("full socket writable");238239EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL);240if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)241fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE");242OK("EVFILT_WRITE, EV_DELETE");243}244245/*246* Basic registration exercise for kqueue(2). Create several types/brands of247* sockets, and confirm that we can register for various events on them.248*/249int250main(void)251{252int kq, sv[2];253254printf("1..49\n");255256kq = kqueue();257if (kq == -1)258fail(errno, "kqueue", NULL, NULL);259OK("kqueue()");260261/*262* Create a UNIX domain datagram socket, and attach/test/detach a263* read filter on it.264*/265if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)266fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);267OK("socketpair() 1");268269if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)270fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");271OK("fcntl() 1");272if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)273fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");274OK("fnctl() 2");275276test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM");277278if (close(sv[0]) == -1)279fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");280OK("close() 1");281if (close(sv[1]) == -1)282fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");283OK("close() 2");284285#if 0286/*287* XXXRW: We disable the write test in the case of datagram sockets,288* as kqueue can't tell when the remote socket receive buffer is289* full, whereas the UNIX domain socket implementation can tell and290* returns ENOBUFS.291*/292/*293* Create a UNIX domain datagram socket, and attach/test/detach a294* write filter on it.295*/296if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)297fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);298299if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)300fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");301if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)302fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");303304test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM");305306if (close(sv[0]) == -1)307fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");308if (close(sv[1]) == -1)309fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");310#endif311312/*313* Create a UNIX domain stream socket, and attach/test/detach a314* read filter on it.315*/316if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)317fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);318OK("socketpair() 2");319320if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)321fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");322OK("fcntl() 3");323if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)324fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");325OK("fcntl() 4");326327test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM");328329if (close(sv[0]) == -1)330fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");331OK("close() 3");332if (close(sv[1]) == -1)333fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");334OK("close() 4");335336/*337* Create a UNIX domain stream socket, and attach/test/detach a338* write filter on it.339*/340if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)341fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);342OK("socketpair() 3");343344if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)345fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");346OK("fcntl() 5");347if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)348fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");349OK("fcntl() 6");350351test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM");352353if (close(sv[0]) == -1)354fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");355OK("close() 5");356if (close(sv[1]) == -1)357fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");358OK("close() 6");359360if (close(kq) == -1)361fail(errno, "close", "kq", NULL);362OK("close() 7");363364return (0);365}366367368