1134236Srwatson/*- 2134236Srwatson * Copyright (c) 2004 Robert N. M. Watson 3134236Srwatson * All rights reserved. 4134236Srwatson * 5134236Srwatson * Redistribution and use in source and binary forms, with or without 6134236Srwatson * modification, are permitted provided that the following conditions 7134236Srwatson * are met: 8134236Srwatson * 1. Redistributions of source code must retain the above copyright 9134236Srwatson * notice, this list of conditions and the following disclaimer. 10134236Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11134236Srwatson * notice, this list of conditions and the following disclaimer in the 12134236Srwatson * documentation and/or other materials provided with the distribution. 13134236Srwatson * 14134236Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15134236Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16134236Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17134236Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18134236Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19134236Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20134236Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21134236Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22134236Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23134236Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24134236Srwatson * SUCH DAMAGE. 25134236Srwatson * 26134236Srwatson * $FreeBSD$ 27134236Srwatson */ 28134236Srwatson 29134236Srwatson#include <sys/types.h> 30134236Srwatson#include <sys/event.h> 31134236Srwatson#include <sys/socket.h> 32134236Srwatson#include <sys/time.h> 33134236Srwatson 34134236Srwatson#include <errno.h> 35134236Srwatson#include <fcntl.h> 36134236Srwatson#include <stdio.h> 37134236Srwatson#include <stdlib.h> 38134236Srwatson#include <string.h> 39134236Srwatson#include <unistd.h> 40134236Srwatson 41137587Snikstatic int curtest = 1; 42137587Snik 43134236Srwatson/*- 44134236Srwatson * This test uses UNIX domain socket pairs to perform some basic exercising 45134236Srwatson * of kqueue functionality on sockets. In particular, testing that for read 46134236Srwatson * and write filters, we see the correct detection of whether reads and 47134236Srwatson * writes should actually be able to occur. 48134236Srwatson * 49134236Srwatson * TODO: 50134236Srwatson * - Test read/write filters for listen/accept sockets. 51134236Srwatson * - Handle the XXXRW below regarding datagram sockets. 52134236Srwatson * - Test that watermark/buffer size "data" fields returned by kqueue are 53134236Srwatson * correct. 54134236Srwatson * - Check that kqueue does something sensible when the remote endpoing is 55134236Srwatson * closed. 56134236Srwatson */ 57134236Srwatson 58137587Snik#define OK(testname) printf("ok %d - %s\n", curtest, testname); \ 59137587Snik curtest++; 60137587Snik 61134236Srwatsonstatic void 62134236Srwatsonfail(int error, const char *func, const char *socktype, const char *rest) 63134236Srwatson{ 64134236Srwatson 65137587Snik printf("not ok %d\n", curtest); 66134236Srwatson 67134236Srwatson if (socktype == NULL) 68137587Snik printf("# %s(): %s\n", func, strerror(error)); 69134236Srwatson else if (rest == NULL) 70137587Snik printf("# %s(%s): %s\n", func, socktype, 71134236Srwatson strerror(error)); 72134236Srwatson else 73137587Snik printf("# %s(%s, %s): %s\n", func, socktype, rest, 74134236Srwatson strerror(error)); 75134236Srwatson exit(-1); 76134236Srwatson} 77134236Srwatson 78134236Srwatsonstatic void 79134236Srwatsonfail_assertion(const char *func, const char *socktype, const char *rest, 80134236Srwatson const char *assertion) 81134236Srwatson{ 82134236Srwatson 83137587Snik printf("not ok %d - %s\n", curtest, assertion); 84134236Srwatson 85134236Srwatson if (socktype == NULL) 86137587Snik printf("# %s(): assertion %s failed\n", func, 87134236Srwatson assertion); 88134236Srwatson else if (rest == NULL) 89137587Snik printf("# %s(%s): assertion %s failed\n", func, 90134236Srwatson socktype, assertion); 91134236Srwatson else 92137587Snik printf("# %s(%s, %s): assertion %s failed\n", func, 93134236Srwatson socktype, rest, assertion); 94134236Srwatson exit(-1); 95134236Srwatson} 96134236Srwatson 97134236Srwatson/* 98134236Srwatson * Test read kevent on a socket pair: check to make sure endpoint 0 isn't 99134236Srwatson * readable when we start, then write to endpoint 1 and confirm that endpoint 100134236Srwatson * 0 is now readable. Drain the write, then check that it's not readable 101134236Srwatson * again. Use non-blocking kqueue operations and socket operations. 102134236Srwatson */ 103134236Srwatsonstatic void 104134236Srwatsontest_evfilt_read(int kq, int fd[2], const char *socktype) 105134236Srwatson{ 106134236Srwatson struct timespec ts; 107134236Srwatson struct kevent ke; 108134236Srwatson ssize_t len; 109134236Srwatson char ch; 110134236Srwatson int i; 111134236Srwatson 112134236Srwatson EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); 113134236Srwatson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 114134236Srwatson fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD"); 115137587Snik OK("EVFILT_READ, EV_ADD"); 116134236Srwatson 117134236Srwatson /* 118134236Srwatson * Confirm not readable to begin with, no I/O yet. 119134236Srwatson */ 120134236Srwatson ts.tv_sec = 0; 121134236Srwatson ts.tv_nsec = 0; 122134236Srwatson i = kevent(kq, NULL, 0, &ke, 1, &ts); 123134236Srwatson if (i == -1) 124134236Srwatson fail(errno, "kevent", socktype, "EVFILT_READ"); 125137587Snik OK("EVFILT_READ"); 126134236Srwatson if (i != 0) 127134236Srwatson fail_assertion("kevent", socktype, "EVFILT_READ", 128134236Srwatson "empty socket unreadable"); 129137587Snik OK("empty socket unreadable"); 130134236Srwatson 131134236Srwatson /* 132134236Srwatson * Write a byte to one end. 133134236Srwatson */ 134134236Srwatson ch = 'a'; 135134236Srwatson len = write(fd[1], &ch, sizeof(ch)); 136134236Srwatson if (len == -1) 137134236Srwatson fail(errno, "write", socktype, NULL); 138137587Snik OK("write one byte"); 139134236Srwatson if (len != sizeof(ch)) 140134236Srwatson fail_assertion("write", socktype, NULL, "write length"); 141137587Snik OK("write one byte length"); 142134236Srwatson 143134236Srwatson /* 144134236Srwatson * Other end should now be readable. 145134236Srwatson */ 146134236Srwatson ts.tv_sec = 0; 147134236Srwatson ts.tv_nsec = 0; 148134236Srwatson i = kevent(kq, NULL, 0, &ke, 1, &ts); 149134236Srwatson if (i == -1) 150134236Srwatson fail(errno, "kevent", socktype, "EVFILT_READ"); 151137587Snik OK("EVFILT_READ"); 152134236Srwatson if (i != 1) 153134236Srwatson fail_assertion("kevent", socktype, "EVFILT_READ", 154134236Srwatson "non-empty socket unreadable"); 155137587Snik OK("non-empty socket unreadable"); 156134236Srwatson 157134236Srwatson /* 158134236Srwatson * Read a byte to clear the readable state. 159134236Srwatson */ 160134236Srwatson len = read(fd[0], &ch, sizeof(ch)); 161134236Srwatson if (len == -1) 162134236Srwatson fail(errno, "read", socktype, NULL); 163137587Snik OK("read one byte"); 164134236Srwatson if (len != sizeof(ch)) 165134236Srwatson fail_assertion("read", socktype, NULL, "read length"); 166137587Snik OK("read one byte length"); 167134236Srwatson 168134236Srwatson /* 169134236Srwatson * Now re-check for readability. 170134236Srwatson */ 171134236Srwatson ts.tv_sec = 0; 172134236Srwatson ts.tv_nsec = 0; 173134236Srwatson i = kevent(kq, NULL, 0, &ke, 1, &ts); 174134236Srwatson if (i == -1) 175134236Srwatson fail(errno, "kevent", socktype, "EVFILT_READ"); 176137587Snik OK("EVFILT_READ"); 177134236Srwatson if (i != 0) 178134236Srwatson fail_assertion("kevent", socktype, "EVFILT_READ", 179134236Srwatson "empty socket unreadable"); 180137587Snik OK("empty socket unreadable"); 181134236Srwatson 182134236Srwatson EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL); 183134236Srwatson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 184134236Srwatson fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE"); 185137587Snik OK("EVFILT_READ, EV_DELETE"); 186134236Srwatson} 187134236Srwatson 188134236Srwatsonstatic void 189134236Srwatsontest_evfilt_write(int kq, int fd[2], const char *socktype) 190134236Srwatson{ 191134236Srwatson struct timespec ts; 192134236Srwatson struct kevent ke; 193134236Srwatson ssize_t len; 194134236Srwatson char ch; 195134236Srwatson int i; 196134236Srwatson 197134236Srwatson EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL); 198134236Srwatson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 199134236Srwatson fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD"); 200137587Snik OK("EVFILE_WRITE, EV_ADD"); 201134236Srwatson 202134236Srwatson /* 203134236Srwatson * Confirm writable to begin with, no I/O yet. 204134236Srwatson */ 205134236Srwatson ts.tv_sec = 0; 206134236Srwatson ts.tv_nsec = 0; 207134236Srwatson i = kevent(kq, NULL, 0, &ke, 1, &ts); 208134236Srwatson if (i == -1) 209134236Srwatson fail(errno, "kevent", socktype, "EVFILT_WRITE"); 210137587Snik OK("EVFILE_WRITE"); 211134236Srwatson if (i != 1) 212134236Srwatson fail_assertion("kevent", socktype, "EVFILT_WRITE", 213134236Srwatson "empty socket unwritable"); 214137587Snik OK("empty socket unwritable"); 215134236Srwatson 216134236Srwatson /* 217134236Srwatson * Write bytes into the socket until we can't write anymore. 218134236Srwatson */ 219134236Srwatson ch = 'a'; 220134236Srwatson while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {}; 221134236Srwatson if (len == -1 && errno != EAGAIN && errno != ENOBUFS) 222134236Srwatson fail(errno, "write", socktype, NULL); 223137587Snik OK("write"); 224134236Srwatson if (len != -1 && len != sizeof(ch)) 225134236Srwatson fail_assertion("write", socktype, NULL, "write length"); 226137587Snik OK("write length"); 227134236Srwatson 228134236Srwatson /* 229134236Srwatson * Check to make sure the socket is no longer writable. 230134236Srwatson */ 231134236Srwatson ts.tv_sec = 0; 232134236Srwatson ts.tv_nsec = 0; 233134236Srwatson i = kevent(kq, NULL, 0, &ke, 1, &ts); 234134236Srwatson if (i == -1) 235134236Srwatson fail(errno, "kevent", socktype, "EVFILT_WRITE"); 236137587Snik OK("EVFILT_WRITE"); 237134236Srwatson if (i != 0) 238134236Srwatson fail_assertion("kevent", socktype, "EVFILT_WRITE", 239134236Srwatson "full socket writable"); 240137587Snik OK("full socket writable"); 241134236Srwatson 242134236Srwatson EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 243134236Srwatson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 244134236Srwatson fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE"); 245137587Snik OK("EVFILT_WRITE, EV_DELETE"); 246134236Srwatson} 247134236Srwatson 248134236Srwatson/* 249134236Srwatson * Basic registration exercise for kqueue(2). Create several types/brands of 250134236Srwatson * sockets, and confirm that we can register for various events on them. 251134236Srwatson */ 252134236Srwatsonint 253134236Srwatsonmain(int argc, char *argv[]) 254134236Srwatson{ 255134236Srwatson int i, kq, sv[2]; 256134236Srwatson 257137587Snik printf("1..49\n"); 258137587Snik 259134236Srwatson kq = kqueue(); 260134236Srwatson if (kq == -1) 261134236Srwatson fail(errno, "kqueue", NULL, NULL); 262137587Snik OK("kqueue()"); 263134236Srwatson 264134236Srwatson /* 265134236Srwatson * Create a UNIX domain datagram socket, and attach/test/detach a 266134236Srwatson * read filter on it. 267134236Srwatson */ 268134236Srwatson if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) 269134236Srwatson fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); 270137587Snik OK("socketpair() 1"); 271134236Srwatson 272134662Srwatson if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) 273134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 274137587Snik OK("fcntl() 1"); 275134662Srwatson if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) 276134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 277137587Snik OK("fnctl() 2"); 278134236Srwatson 279134236Srwatson test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM"); 280134236Srwatson 281134236Srwatson if (close(sv[0]) == -1) 282134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); 283137587Snik OK("close() 1"); 284134236Srwatson if (close(sv[1]) == -1) 285134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); 286137587Snik OK("close() 2"); 287134236Srwatson 288134236Srwatson#if 0 289134236Srwatson /* 290134236Srwatson * XXXRW: We disable the write test in the case of datagram sockets, 291134236Srwatson * as kqueue can't tell when the remote socket receive buffer is 292134236Srwatson * full, whereas the UNIX domain socket implementation can tell and 293134236Srwatson * returns ENOBUFS. 294134236Srwatson */ 295134236Srwatson /* 296134236Srwatson * Create a UNIX domain datagram socket, and attach/test/detach a 297134236Srwatson * write filter on it. 298134236Srwatson */ 299134236Srwatson if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) 300134236Srwatson fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); 301134236Srwatson 302134662Srwatson if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) 303134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 304134662Srwatson if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) 305134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 306134236Srwatson 307134236Srwatson test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM"); 308134236Srwatson 309134236Srwatson if (close(sv[0]) == -1) 310134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); 311134236Srwatson if (close(sv[1]) == -1) 312134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); 313134236Srwatson#endif 314134236Srwatson 315134236Srwatson /* 316134236Srwatson * Create a UNIX domain stream socket, and attach/test/detach a 317134236Srwatson * read filter on it. 318134236Srwatson */ 319134236Srwatson if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) 320134236Srwatson fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); 321137587Snik OK("socketpair() 2"); 322134236Srwatson 323134662Srwatson if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) 324134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 325137587Snik OK("fcntl() 3"); 326134662Srwatson if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) 327134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 328137587Snik OK("fcntl() 4"); 329134236Srwatson 330134236Srwatson test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM"); 331134236Srwatson 332134236Srwatson if (close(sv[0]) == -1) 333134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); 334137587Snik OK("close() 3"); 335134236Srwatson if (close(sv[1]) == -1) 336134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); 337137587Snik OK("close() 4"); 338134236Srwatson 339134236Srwatson /* 340134236Srwatson * Create a UNIX domain stream socket, and attach/test/detach a 341134236Srwatson * write filter on it. 342134236Srwatson */ 343134236Srwatson if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) 344134236Srwatson fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); 345137587Snik OK("socketpair() 3"); 346134236Srwatson 347134662Srwatson if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) 348134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 349137587Snik OK("fcntl() 5"); 350134662Srwatson if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) 351134236Srwatson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 352137587Snik OK("fcntl() 6"); 353134236Srwatson 354134236Srwatson test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM"); 355134236Srwatson 356134236Srwatson if (close(sv[0]) == -1) 357134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); 358137587Snik OK("close() 5"); 359134236Srwatson if (close(sv[1]) == -1) 360134236Srwatson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); 361137587Snik OK("close() 6"); 362134236Srwatson 363134236Srwatson if (close(kq) == -1) 364134236Srwatson fail(errno, "close", "kq", NULL); 365137587Snik OK("close() 7"); 366134236Srwatson 367134236Srwatson return (0); 368134236Srwatson} 369