xref: /freebsd/tools/regression/sockets/kqueue/kqueue.c (revision 62967fb0bb976543e273aea673e1d7a917043b9c)
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