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