1/*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "common.h"
18
19static int sockfd[2];
20
21static void
22kevent_socket_drain(void)
23{
24    char buf[1];
25
26    /* Drain the read buffer, then make sure there are no more events. */
27    puts("draining the read buffer");
28    if (read(sockfd[0], &buf[0], 1) < 1)
29        err(1, "read(2)");
30}
31
32static void
33kevent_socket_fill(void)
34{
35  puts("filling the read buffer");
36    if (write(sockfd[1], ".", 1) < 1)
37        err(1, "write(2)");
38}
39
40
41static void
42test_kevent_socket_add(void)
43{
44    const char *test_id = "kevent(EVFILT_READ, EV_ADD)";
45    struct kevent kev;
46
47    test_begin(test_id);
48    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
49    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
50        err(1, "%s", test_id);
51
52    success();
53}
54
55static void
56test_kevent_socket_get(void)
57{
58    const char *test_id = "kevent(EVFILT_READ) wait";
59    struct kevent kev;
60
61    test_begin(test_id);
62
63    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
64    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
65        err(1, "%s", test_id);
66
67    kevent_socket_fill();
68
69    kev.data = 1;
70    kevent_cmp(&kev, kevent_get(kqfd));
71
72    kevent_socket_drain();
73    test_no_kevents();
74
75    kev.flags = EV_DELETE;
76    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
77        err(1, "%s", test_id);
78
79    success();
80}
81
82static void
83test_kevent_socket_clear(void)
84{
85    const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)";
86    struct kevent kev;
87
88    test_begin(test_id);
89
90    test_no_kevents();
91
92    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
93    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
94        err(1, "%s", test_id);
95
96    kevent_socket_fill();
97    kevent_socket_fill();
98
99    kev.data = 2;
100    kevent_cmp(&kev, kevent_get(kqfd));
101
102    /* We filled twice, but drain once. Edge-triggered would not generate
103       additional events.
104     */
105    kevent_socket_drain();
106    test_no_kevents();
107
108    kevent_socket_drain();
109    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
110    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
111        err(1, "%s", test_id);
112
113    success();
114}
115
116static void
117test_kevent_socket_disable_and_enable(void)
118{
119    const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)";
120    struct kevent kev;
121
122    test_begin(test_id);
123
124    /*
125     * Write to the socket before adding the event. This way we can verify that
126     * enabling a triggered kevent causes the event to be returned immediately.
127     */
128    kevent_socket_fill();
129
130    /* Add a disabled event. */
131    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]);
132    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
133        err(1, "%s", test_id);
134
135    test_no_kevents();
136
137    /* Re-enable the knote, then see if an event is generated */
138    kev.flags = EV_ENABLE;
139    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
140        err(1, "%s", test_id);
141    kev.flags = EV_ADD;
142    kev.data = 1;
143    kevent_cmp(&kev, kevent_get(kqfd));
144
145    kevent_socket_drain();
146
147    kev.flags = EV_DELETE;
148    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
149        err(1, "%s", test_id);
150
151    success();
152}
153
154static void
155test_kevent_socket_del(void)
156{
157    const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
158    struct kevent kev;
159
160    test_begin(test_id);
161
162    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
163    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
164        err(1, "%s", test_id);
165
166    kevent_socket_fill();
167    test_no_kevents();
168    kevent_socket_drain();
169
170    success();
171}
172
173static void
174test_kevent_socket_oneshot(void)
175{
176    const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
177    struct kevent kev;
178
179    test_begin(test_id);
180
181    /* Re-add the watch and make sure no events are pending */
182    puts("-- re-adding knote");
183    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
184    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
185        err(1, "%s", test_id);
186    test_no_kevents();
187
188    puts("-- getting one event");
189    kevent_socket_fill();
190    kev.data = 1;
191    kevent_cmp(&kev, kevent_get(kqfd));
192
193    puts("-- checking knote disabled");
194    test_no_kevents();
195
196    /* Try to delete the knote, it should already be deleted */
197    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
198    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
199        err(1, "%s", test_id);
200
201    kevent_socket_drain();
202
203    success();
204}
205
206
207#if HAVE_EV_DISPATCH
208static void
209test_kevent_socket_dispatch(void)
210{
211    const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
212
213    test_begin(test_id);
214
215    struct kevent kev;
216
217    /* Re-add the watch and make sure no events are pending */
218    puts("-- re-adding knote");
219    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
220    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
221        err(1, "%s", test_id);
222    test_no_kevents();
223
224    /* The event will occur only once, even though EV_CLEAR is not
225       specified. */
226    kevent_socket_fill();
227    kev.data = 1;
228    kevent_cmp(&kev, kevent_get(kqfd));
229    test_no_kevents();
230
231    /* Since the knote is disabled, the EV_DELETE operation succeeds. */
232    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
233    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
234        err(1, "%s", test_id);
235
236    kevent_socket_drain();
237
238    success();
239}
240#endif  /* HAVE_EV_DISPATCH */
241
242#if BROKEN
243static void
244test_kevent_socket_lowat(void)
245{
246    const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
247    struct kevent kev;
248
249    test_begin(test_id);
250
251    /* Re-add the watch and make sure no events are pending */
252    puts("-- re-adding knote, setting low watermark to 2 bytes");
253    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
254    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
255        err(1, "%s", test_id);
256    test_no_kevents();
257
258    puts("-- checking that one byte does not trigger an event..");
259    kevent_socket_fill();
260    test_no_kevents();
261
262    puts("-- checking that two bytes triggers an event..");
263    kevent_socket_fill();
264    if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
265        err(1, "%s", test_id);
266    KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
267    test_no_kevents();
268
269    kevent_socket_drain();
270    kevent_socket_drain();
271
272    success();
273}
274#endif
275
276static void
277test_kevent_socket_eof(void)
278{
279    const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
280    struct kevent kev;
281
282    test_begin(test_id);
283
284    /* Re-add the watch and make sure no events are pending */
285    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
286    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
287        err(1, "%s", test_id);
288    test_no_kevents();
289
290    if (close(sockfd[1]) < 0)
291        err(1, "close(2)");
292
293    kev.flags |= EV_EOF;
294    kevent_cmp(&kev, kevent_get(kqfd));
295
296    /* Delete the watch */
297    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
298    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
299        err(1, "%s", test_id);
300
301    success();
302}
303
304void
305test_evfilt_read(void)
306{
307    /* Create a connected pair of full-duplex sockets for testing socket events */
308    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
309        abort();
310
311    kqfd = kqueue();
312    test_kevent_socket_add();
313    test_kevent_socket_del();
314    test_kevent_socket_get();
315    test_kevent_socket_disable_and_enable();
316    test_kevent_socket_oneshot();
317    test_kevent_socket_clear();
318#if HAVE_EV_DISPATCH
319    test_kevent_socket_dispatch();
320#endif
321    test_kevent_socket_eof();
322    close(kqfd);
323}
324