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