162967fb0SRobert Watson /*- 262967fb0SRobert Watson * Copyright (c) 2004 Robert N. M. Watson 362967fb0SRobert Watson * All rights reserved. 462967fb0SRobert Watson * 562967fb0SRobert Watson * Redistribution and use in source and binary forms, with or without 662967fb0SRobert Watson * modification, are permitted provided that the following conditions 762967fb0SRobert Watson * are met: 862967fb0SRobert Watson * 1. Redistributions of source code must retain the above copyright 962967fb0SRobert Watson * notice, this list of conditions and the following disclaimer. 1062967fb0SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1162967fb0SRobert Watson * notice, this list of conditions and the following disclaimer in the 1262967fb0SRobert Watson * documentation and/or other materials provided with the distribution. 1362967fb0SRobert Watson * 1462967fb0SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1562967fb0SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1662967fb0SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1762967fb0SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1862967fb0SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1962967fb0SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2062967fb0SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2162967fb0SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2262967fb0SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2362967fb0SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2462967fb0SRobert Watson * SUCH DAMAGE. 2562967fb0SRobert Watson * 2662967fb0SRobert Watson * $FreeBSD$ 2762967fb0SRobert Watson */ 2862967fb0SRobert Watson 2962967fb0SRobert Watson #include <sys/types.h> 3062967fb0SRobert Watson #include <sys/event.h> 3162967fb0SRobert Watson #include <sys/socket.h> 3262967fb0SRobert Watson #include <sys/time.h> 3362967fb0SRobert Watson 3462967fb0SRobert Watson #include <errno.h> 3562967fb0SRobert Watson #include <fcntl.h> 3662967fb0SRobert Watson #include <stdio.h> 3762967fb0SRobert Watson #include <stdlib.h> 3862967fb0SRobert Watson #include <string.h> 3962967fb0SRobert Watson #include <unistd.h> 4062967fb0SRobert Watson 4162967fb0SRobert Watson /*- 4262967fb0SRobert Watson * This test uses UNIX domain socket pairs to perform some basic exercising 4362967fb0SRobert Watson * of kqueue functionality on sockets. In particular, testing that for read 4462967fb0SRobert Watson * and write filters, we see the correct detection of whether reads and 4562967fb0SRobert Watson * writes should actually be able to occur. 4662967fb0SRobert Watson * 4762967fb0SRobert Watson * TODO: 4862967fb0SRobert Watson * - Test read/write filters for listen/accept sockets. 4962967fb0SRobert Watson * - Handle the XXXRW below regarding datagram sockets. 5062967fb0SRobert Watson * - Test that watermark/buffer size "data" fields returned by kqueue are 5162967fb0SRobert Watson * correct. 5262967fb0SRobert Watson * - Check that kqueue does something sensible when the remote endpoing is 5362967fb0SRobert Watson * closed. 5462967fb0SRobert Watson */ 5562967fb0SRobert Watson 5662967fb0SRobert Watson static void 5762967fb0SRobert Watson fail(int error, const char *func, const char *socktype, const char *rest) 5862967fb0SRobert Watson { 5962967fb0SRobert Watson 6062967fb0SRobert Watson fprintf(stderr, "FAIL\n"); 6162967fb0SRobert Watson 6262967fb0SRobert Watson if (socktype == NULL) 6362967fb0SRobert Watson fprintf(stderr, "%s(): %s\n", func, strerror(error)); 6462967fb0SRobert Watson else if (rest == NULL) 6562967fb0SRobert Watson fprintf(stderr, "%s(%s): %s\n", func, socktype, 6662967fb0SRobert Watson strerror(error)); 6762967fb0SRobert Watson else 6862967fb0SRobert Watson fprintf(stderr, "%s(%s, %s): %s\n", func, socktype, rest, 6962967fb0SRobert Watson strerror(error)); 7062967fb0SRobert Watson exit(-1); 7162967fb0SRobert Watson } 7262967fb0SRobert Watson 7362967fb0SRobert Watson static void 7462967fb0SRobert Watson fail_assertion(const char *func, const char *socktype, const char *rest, 7562967fb0SRobert Watson const char *assertion) 7662967fb0SRobert Watson { 7762967fb0SRobert Watson 7862967fb0SRobert Watson fprintf(stderr, "FAIL\n"); 7962967fb0SRobert Watson 8062967fb0SRobert Watson if (socktype == NULL) 8162967fb0SRobert Watson fprintf(stderr, "%s(): assertion %s failed\n", func, 8262967fb0SRobert Watson assertion); 8362967fb0SRobert Watson else if (rest == NULL) 8462967fb0SRobert Watson fprintf(stderr, "%s(%s): assertion %s failed\n", func, 8562967fb0SRobert Watson socktype, assertion); 8662967fb0SRobert Watson else 8762967fb0SRobert Watson fprintf(stderr, "%s(%s, %s): assertion %s failed\n", func, 8862967fb0SRobert Watson socktype, rest, assertion); 8962967fb0SRobert Watson exit(-1); 9062967fb0SRobert Watson } 9162967fb0SRobert Watson 9262967fb0SRobert Watson /* 9362967fb0SRobert Watson * Test read kevent on a socket pair: check to make sure endpoint 0 isn't 9462967fb0SRobert Watson * readable when we start, then write to endpoint 1 and confirm that endpoint 9562967fb0SRobert Watson * 0 is now readable. Drain the write, then check that it's not readable 9662967fb0SRobert Watson * again. Use non-blocking kqueue operations and socket operations. 9762967fb0SRobert Watson */ 9862967fb0SRobert Watson static void 9962967fb0SRobert Watson test_evfilt_read(int kq, int fd[2], const char *socktype) 10062967fb0SRobert Watson { 10162967fb0SRobert Watson struct timespec ts; 10262967fb0SRobert Watson struct kevent ke; 10362967fb0SRobert Watson ssize_t len; 10462967fb0SRobert Watson char ch; 10562967fb0SRobert Watson int i; 10662967fb0SRobert Watson 10762967fb0SRobert Watson EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); 10862967fb0SRobert Watson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 10962967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD"); 11062967fb0SRobert Watson 11162967fb0SRobert Watson /* 11262967fb0SRobert Watson * Confirm not readable to begin with, no I/O yet. 11362967fb0SRobert Watson */ 11462967fb0SRobert Watson ts.tv_sec = 0; 11562967fb0SRobert Watson ts.tv_nsec = 0; 11662967fb0SRobert Watson i = kevent(kq, NULL, 0, &ke, 1, &ts); 11762967fb0SRobert Watson if (i == -1) 11862967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_READ"); 11962967fb0SRobert Watson if (i != 0) 12062967fb0SRobert Watson fail_assertion("kevent", socktype, "EVFILT_READ", 12162967fb0SRobert Watson "empty socket unreadable"); 12262967fb0SRobert Watson 12362967fb0SRobert Watson /* 12462967fb0SRobert Watson * Write a byte to one end. 12562967fb0SRobert Watson */ 12662967fb0SRobert Watson ch = 'a'; 12762967fb0SRobert Watson len = write(fd[1], &ch, sizeof(ch)); 12862967fb0SRobert Watson if (len == -1) 12962967fb0SRobert Watson fail(errno, "write", socktype, NULL); 13062967fb0SRobert Watson if (len != sizeof(ch)) 13162967fb0SRobert Watson fail_assertion("write", socktype, NULL, "write length"); 13262967fb0SRobert Watson 13362967fb0SRobert Watson /* 13462967fb0SRobert Watson * Other end should now be readable. 13562967fb0SRobert Watson */ 13662967fb0SRobert Watson ts.tv_sec = 0; 13762967fb0SRobert Watson ts.tv_nsec = 0; 13862967fb0SRobert Watson i = kevent(kq, NULL, 0, &ke, 1, &ts); 13962967fb0SRobert Watson if (i == -1) 14062967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_READ"); 14162967fb0SRobert Watson if (i != 1) 14262967fb0SRobert Watson fail_assertion("kevent", socktype, "EVFILT_READ", 14362967fb0SRobert Watson "non-empty socket unreadable"); 14462967fb0SRobert Watson 14562967fb0SRobert Watson /* 14662967fb0SRobert Watson * Read a byte to clear the readable state. 14762967fb0SRobert Watson */ 14862967fb0SRobert Watson len = read(fd[0], &ch, sizeof(ch)); 14962967fb0SRobert Watson if (len == -1) 15062967fb0SRobert Watson fail(errno, "read", socktype, NULL); 15162967fb0SRobert Watson if (len != sizeof(ch)) 15262967fb0SRobert Watson fail_assertion("read", socktype, NULL, "read length"); 15362967fb0SRobert Watson 15462967fb0SRobert Watson /* 15562967fb0SRobert Watson * Now re-check for readability. 15662967fb0SRobert Watson */ 15762967fb0SRobert Watson ts.tv_sec = 0; 15862967fb0SRobert Watson ts.tv_nsec = 0; 15962967fb0SRobert Watson i = kevent(kq, NULL, 0, &ke, 1, &ts); 16062967fb0SRobert Watson if (i == -1) 16162967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_READ"); 16262967fb0SRobert Watson if (i != 0) 16362967fb0SRobert Watson fail_assertion("kevent", socktype, "EVFILT_READ", 16462967fb0SRobert Watson "empty socket unreadable"); 16562967fb0SRobert Watson 16662967fb0SRobert Watson EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL); 16762967fb0SRobert Watson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 16862967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE"); 16962967fb0SRobert Watson } 17062967fb0SRobert Watson 17162967fb0SRobert Watson static void 17262967fb0SRobert Watson test_evfilt_write(int kq, int fd[2], const char *socktype) 17362967fb0SRobert Watson { 17462967fb0SRobert Watson struct timespec ts; 17562967fb0SRobert Watson struct kevent ke; 17662967fb0SRobert Watson ssize_t len; 17762967fb0SRobert Watson char ch; 17862967fb0SRobert Watson int i; 17962967fb0SRobert Watson 18062967fb0SRobert Watson EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL); 18162967fb0SRobert Watson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 18262967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD"); 18362967fb0SRobert Watson 18462967fb0SRobert Watson /* 18562967fb0SRobert Watson * Confirm writable to begin with, no I/O yet. 18662967fb0SRobert Watson */ 18762967fb0SRobert Watson ts.tv_sec = 0; 18862967fb0SRobert Watson ts.tv_nsec = 0; 18962967fb0SRobert Watson i = kevent(kq, NULL, 0, &ke, 1, &ts); 19062967fb0SRobert Watson if (i == -1) 19162967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_WRITE"); 19262967fb0SRobert Watson if (i != 1) 19362967fb0SRobert Watson fail_assertion("kevent", socktype, "EVFILT_WRITE", 19462967fb0SRobert Watson "empty socket unwritable"); 19562967fb0SRobert Watson 19662967fb0SRobert Watson /* 19762967fb0SRobert Watson * Write bytes into the socket until we can't write anymore. 19862967fb0SRobert Watson */ 19962967fb0SRobert Watson ch = 'a'; 20062967fb0SRobert Watson while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {}; 20162967fb0SRobert Watson if (len == -1 && errno != EAGAIN && errno != ENOBUFS) 20262967fb0SRobert Watson fail(errno, "write", socktype, NULL); 20362967fb0SRobert Watson if (len != -1 && len != sizeof(ch)) 20462967fb0SRobert Watson fail_assertion("write", socktype, NULL, "write length"); 20562967fb0SRobert Watson 20662967fb0SRobert Watson /* 20762967fb0SRobert Watson * Check to make sure the socket is no longer writable. 20862967fb0SRobert Watson */ 20962967fb0SRobert Watson ts.tv_sec = 0; 21062967fb0SRobert Watson ts.tv_nsec = 0; 21162967fb0SRobert Watson i = kevent(kq, NULL, 0, &ke, 1, &ts); 21262967fb0SRobert Watson if (i == -1) 21362967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_WRITE"); 21462967fb0SRobert Watson if (i != 0) 21562967fb0SRobert Watson fail_assertion("kevent", socktype, "EVFILT_WRITE", 21662967fb0SRobert Watson "full socket writable"); 21762967fb0SRobert Watson 21862967fb0SRobert Watson EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 21962967fb0SRobert Watson if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) 22062967fb0SRobert Watson fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE"); 22162967fb0SRobert Watson } 22262967fb0SRobert Watson 22362967fb0SRobert Watson /* 22462967fb0SRobert Watson * Basic registration exercise for kqueue(2). Create several types/brands of 22562967fb0SRobert Watson * sockets, and confirm that we can register for various events on them. 22662967fb0SRobert Watson */ 22762967fb0SRobert Watson int 22862967fb0SRobert Watson main(int argc, char *argv[]) 22962967fb0SRobert Watson { 23062967fb0SRobert Watson int i, kq, sv[2]; 23162967fb0SRobert Watson 23262967fb0SRobert Watson kq = kqueue(); 23362967fb0SRobert Watson if (kq == -1) 23462967fb0SRobert Watson fail(errno, "kqueue", NULL, NULL); 23562967fb0SRobert Watson 23662967fb0SRobert Watson /* 23762967fb0SRobert Watson * Create a UNIX domain datagram socket, and attach/test/detach a 23862967fb0SRobert Watson * read filter on it. 23962967fb0SRobert Watson */ 24062967fb0SRobert Watson if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) 24162967fb0SRobert Watson fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); 24262967fb0SRobert Watson 24362967fb0SRobert Watson i = O_NONBLOCK; 24462967fb0SRobert Watson if (fcntl(sv[0], F_SETFL, &i) != 0) 24562967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 24662967fb0SRobert Watson if (fcntl(sv[1], F_SETFL, &i) != 0) 24762967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 24862967fb0SRobert Watson 24962967fb0SRobert Watson test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM"); 25062967fb0SRobert Watson 25162967fb0SRobert Watson if (close(sv[0]) == -1) 25262967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); 25362967fb0SRobert Watson if (close(sv[1]) == -1) 25462967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); 25562967fb0SRobert Watson 25662967fb0SRobert Watson #if 0 25762967fb0SRobert Watson /* 25862967fb0SRobert Watson * XXXRW: We disable the write test in the case of datagram sockets, 25962967fb0SRobert Watson * as kqueue can't tell when the remote socket receive buffer is 26062967fb0SRobert Watson * full, whereas the UNIX domain socket implementation can tell and 26162967fb0SRobert Watson * returns ENOBUFS. 26262967fb0SRobert Watson */ 26362967fb0SRobert Watson /* 26462967fb0SRobert Watson * Create a UNIX domain datagram socket, and attach/test/detach a 26562967fb0SRobert Watson * write filter on it. 26662967fb0SRobert Watson */ 26762967fb0SRobert Watson if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) 26862967fb0SRobert Watson fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); 26962967fb0SRobert Watson 27062967fb0SRobert Watson i = O_NONBLOCK; 27162967fb0SRobert Watson if (fcntl(sv[0], F_SETFL, &i) != 0) 27262967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 27362967fb0SRobert Watson if (fcntl(sv[1], F_SETFL, &i) != 0) 27462967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); 27562967fb0SRobert Watson 27662967fb0SRobert Watson test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM"); 27762967fb0SRobert Watson 27862967fb0SRobert Watson if (close(sv[0]) == -1) 27962967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); 28062967fb0SRobert Watson if (close(sv[1]) == -1) 28162967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); 28262967fb0SRobert Watson #endif 28362967fb0SRobert Watson 28462967fb0SRobert Watson /* 28562967fb0SRobert Watson * Create a UNIX domain stream socket, and attach/test/detach a 28662967fb0SRobert Watson * read filter on it. 28762967fb0SRobert Watson */ 28862967fb0SRobert Watson if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) 28962967fb0SRobert Watson fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); 29062967fb0SRobert Watson 29162967fb0SRobert Watson i = O_NONBLOCK; 29262967fb0SRobert Watson if (fcntl(sv[0], F_SETFL, &i) != 0) 29362967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 29462967fb0SRobert Watson if (fcntl(sv[1], F_SETFL, &i) != 0) 29562967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 29662967fb0SRobert Watson 29762967fb0SRobert Watson test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM"); 29862967fb0SRobert Watson 29962967fb0SRobert Watson if (close(sv[0]) == -1) 30062967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); 30162967fb0SRobert Watson if (close(sv[1]) == -1) 30262967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); 30362967fb0SRobert Watson 30462967fb0SRobert Watson /* 30562967fb0SRobert Watson * Create a UNIX domain stream socket, and attach/test/detach a 30662967fb0SRobert Watson * write filter on it. 30762967fb0SRobert Watson */ 30862967fb0SRobert Watson if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) 30962967fb0SRobert Watson fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); 31062967fb0SRobert Watson 31162967fb0SRobert Watson i = O_NONBLOCK; 31262967fb0SRobert Watson if (fcntl(sv[0], F_SETFL, &i) != 0) 31362967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 31462967fb0SRobert Watson if (fcntl(sv[1], F_SETFL, &i) != 0) 31562967fb0SRobert Watson fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); 31662967fb0SRobert Watson 31762967fb0SRobert Watson test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM"); 31862967fb0SRobert Watson 31962967fb0SRobert Watson if (close(sv[0]) == -1) 32062967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); 32162967fb0SRobert Watson if (close(sv[1]) == -1) 32262967fb0SRobert Watson fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); 32362967fb0SRobert Watson 32462967fb0SRobert Watson if (close(kq) == -1) 32562967fb0SRobert Watson fail(errno, "close", "kq", NULL); 32662967fb0SRobert Watson 32762967fb0SRobert Watson printf("PASS\n"); 32862967fb0SRobert Watson return (0); 32962967fb0SRobert Watson } 330