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