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/10/tests/sys/kqueue/libkqueue/read.c 305467 2016-09-06 08:45:29Z ngie $
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    /*
128     * Write to the socket before adding the event. This way we can verify that
129     * enabling a triggered kevent causes the event to be returned immediately.
130     */
131    kevent_socket_fill();
132
133    /* Add a disabled event. */
134    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]);
135    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
136        err(1, "%s", test_id);
137
138    test_no_kevents();
139
140    /* Re-enable the knote, then see if an event is generated */
141    kev.flags = EV_ENABLE;
142    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
143        err(1, "%s", test_id);
144    kev.flags = EV_ADD;
145    kev.data = 1;
146    kevent_cmp(&kev, kevent_get(kqfd));
147
148    kevent_socket_drain();
149
150    kev.flags = EV_DELETE;
151    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
152        err(1, "%s", test_id);
153
154    success();
155}
156
157void
158test_kevent_socket_del(void)
159{
160    const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
161    struct kevent kev;
162
163    test_begin(test_id);
164
165    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
166    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
167        err(1, "%s", test_id);
168
169    kevent_socket_fill();
170    test_no_kevents();
171    kevent_socket_drain();
172
173    success();
174}
175
176void
177test_kevent_socket_oneshot(void)
178{
179    const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
180    struct kevent kev;
181
182    test_begin(test_id);
183
184    /* Re-add the watch and make sure no events are pending */
185    puts("-- re-adding knote");
186    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
187    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
188        err(1, "%s", test_id);
189    test_no_kevents();
190
191    puts("-- getting one event");
192    kevent_socket_fill();
193    kev.data = 1;
194    kevent_cmp(&kev, kevent_get(kqfd));
195
196    puts("-- checking knote disabled");
197    test_no_kevents();
198
199    /* Try to delete the knote, it should already be deleted */
200    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
201    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
202        err(1, "%s", test_id);
203
204    kevent_socket_drain();
205
206    success();
207}
208
209
210#if HAVE_EV_DISPATCH
211void
212test_kevent_socket_dispatch(void)
213{
214    const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
215
216    test_begin(test_id);
217
218    struct kevent kev;
219
220    /* Re-add the watch and make sure no events are pending */
221    puts("-- re-adding knote");
222    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
223    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
224        err(1, "%s", test_id);
225    test_no_kevents();
226
227    /* The event will occur only once, even though EV_CLEAR is not
228       specified. */
229    kevent_socket_fill();
230    kev.data = 1;
231    kevent_cmp(&kev, kevent_get(kqfd));
232    test_no_kevents();
233
234    /* Since the knote is disabled, the EV_DELETE operation succeeds. */
235    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
236    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
237        err(1, "%s", test_id);
238
239    kevent_socket_drain();
240
241    success();
242}
243#endif  /* HAVE_EV_DISPATCH */
244
245#if BROKEN
246void
247test_kevent_socket_lowat(void)
248{
249    const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
250    struct kevent kev;
251
252    test_begin(test_id);
253
254    /* Re-add the watch and make sure no events are pending */
255    puts("-- re-adding knote, setting low watermark to 2 bytes");
256    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
257    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
258        err(1, "%s", test_id);
259    test_no_kevents();
260
261    puts("-- checking that one byte does not trigger an event..");
262    kevent_socket_fill();
263    test_no_kevents();
264
265    puts("-- checking that two bytes triggers an event..");
266    kevent_socket_fill();
267    if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
268        err(1, "%s", test_id);
269    KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
270    test_no_kevents();
271
272    kevent_socket_drain();
273    kevent_socket_drain();
274
275    success();
276}
277#endif
278
279void
280test_kevent_socket_eof(void)
281{
282    const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
283    struct kevent kev;
284
285    test_begin(test_id);
286
287    /* Re-add the watch and make sure no events are pending */
288    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
289    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
290        err(1, "%s", test_id);
291    test_no_kevents();
292
293    if (close(sockfd[1]) < 0)
294        err(1, "close(2)");
295
296    kev.flags |= EV_EOF;
297    kevent_cmp(&kev, kevent_get(kqfd));
298
299    /* Delete the watch */
300    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
301    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
302        err(1, "%s", test_id);
303
304    success();
305}
306
307void
308test_evfilt_read()
309{
310    /* Create a connected pair of full-duplex sockets for testing socket events */
311    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
312        abort();
313
314    kqfd = kqueue();
315    test_kevent_socket_add();
316    test_kevent_socket_del();
317    test_kevent_socket_get();
318    test_kevent_socket_disable_and_enable();
319    test_kevent_socket_oneshot();
320    test_kevent_socket_clear();
321#if HAVE_EV_DISPATCH
322    test_kevent_socket_dispatch();
323#endif
324    test_kevent_socket_eof();
325    close(kqfd);
326}
327