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 <arpa/inet.h>
18#include <sys/socket.h>
19#include "common.h"
20
21static int __thread kqfd;
22static int __thread 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    if (read(sockfd[0], &buf[0], 1) < 1)
31        die("read(2)");
32}
33
34static void
35kevent_socket_fill(void)
36{
37    if (write(sockfd[1], ".", 1) < 1)
38        die("write(2)");
39}
40
41
42void
43test_kevent_socket_add(void)
44{
45    struct kevent kev;
46
47    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
48}
49
50void
51test_kevent_socket_add_without_ev_add(void)
52{
53    struct kevent kev;
54
55    /* Try to add a kevent without specifying EV_ADD */
56    EV_SET(&kev, sockfd[0], EVFILT_READ, 0, 0, 0, &sockfd[0]);
57    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
58        die("kevent should have failed");
59
60    kevent_socket_fill();
61    test_no_kevents(kqfd);
62    kevent_socket_drain();
63
64    /* Try to delete a kevent which does not exist */
65    kev.flags = EV_DELETE;
66    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
67        die("kevent should have failed");
68}
69
70void
71test_kevent_socket_get(void)
72{
73    struct kevent kev;
74
75    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
76    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
77        die("kevent");
78
79    kevent_socket_fill();
80
81    kev.data = 1;
82    kevent_cmp(&kev, kevent_get(kqfd));
83
84    kevent_socket_drain();
85    test_no_kevents(kqfd);
86
87    kev.flags = EV_DELETE;
88    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
89        die("kevent");
90}
91
92void
93test_kevent_socket_clear(void)
94{
95    struct kevent kev;
96
97    test_no_kevents(kqfd);
98    kevent_socket_drain();
99
100    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
101    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
102        die("kevent");
103
104    kevent_socket_fill();
105    kevent_socket_fill();
106
107/* Solaris does not offer a way to get the amount of data pending */
108#if defined(__sun__)
109    kev.data = 1;
110#else
111    kev.data = 2;
112#endif
113    kevent_cmp(&kev, kevent_get(kqfd));
114
115    /* We filled twice, but drain once. Edge-triggered would not generate
116       additional events.
117     */
118    kevent_socket_drain();
119    test_no_kevents(kqfd);
120
121    kevent_socket_drain();
122    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
123    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
124        die("kevent");
125}
126
127void
128test_kevent_socket_disable_and_enable(void)
129{
130    struct kevent kev;
131
132    /* Add an event, then disable it. */
133    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
134    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
135        die("kevent");
136    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DISABLE, 0, 0, &sockfd[0]);
137    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
138        die("kevent");
139
140    kevent_socket_fill();
141    test_no_kevents(kqfd);
142
143    /* Re-enable the knote, then see if an event is generated */
144    kev.flags = EV_ENABLE;
145    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
146        die("kevent");
147    kev.flags = EV_ADD;
148    kev.data = 1;
149    kevent_cmp(&kev, kevent_get(kqfd));
150
151    kevent_socket_drain();
152
153    kev.flags = EV_DELETE;
154    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
155        die("kevent");
156}
157
158void
159test_kevent_socket_del(void)
160{
161    struct kevent kev;
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        die("kevent");
166
167    kevent_socket_fill();
168    test_no_kevents(kqfd);
169    kevent_socket_drain();
170}
171
172void
173test_kevent_socket_oneshot(void)
174{
175    struct kevent kev;
176
177    /* Re-add the watch and make sure no events are pending */
178    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
179    test_no_kevents(kqfd);
180
181    kevent_socket_fill();
182    kev.data = 1;
183    kevent_cmp(&kev, kevent_get(kqfd));
184
185    test_no_kevents(kqfd);
186
187    /* Verify that the event has been deleted */
188    kevent_socket_fill();
189    test_no_kevents(kqfd);
190    kevent_socket_drain();
191}
192
193/*
194 * Test if the data field returns 1 when a listen(2) socket has
195 * a pending connection.
196 */
197void
198test_kevent_socket_listen_backlog(void)
199{
200    struct kevent kev;
201    struct sockaddr_in sain;
202    socklen_t sa_len = sizeof(sain);
203    int one = 1;
204    const short port = 14973;
205    int clnt, srvr;
206
207    /* Create a passive socket */
208    memset(&sain, 0, sizeof(sain));
209    sain.sin_family = AF_INET;
210    sain.sin_port = htons(port);
211    if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0) abort();
212    if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR,
213                (char *) &one, sizeof(one)) != 0) abort();
214    if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) abort();
215    if (listen(srvr, 100) < 0) abort();
216
217    /* Watch for events on the socket */
218    test_no_kevents(kqfd);
219    kevent_add(kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
220    test_no_kevents(kqfd);
221
222    /* Simulate a client connecting to the server */
223    sain.sin_family = AF_INET;
224    sain.sin_port = htons(port);
225    sain.sin_addr.s_addr = inet_addr("127.0.0.1");
226    if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0) abort();
227    if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0) abort();
228
229    /* Verify that data=1 */
230    kev.data = 1;
231    kevent_cmp(&kev, kevent_get(kqfd));
232    test_no_kevents(kqfd);
233}
234
235#if HAVE_EV_DISPATCH
236void
237test_kevent_socket_dispatch(void)
238{
239    struct kevent kev;
240
241    /* Re-add the watch and make sure no events are pending */
242    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
243    test_no_kevents(kqfd);
244
245    /* The event will occur only once, even though EV_CLEAR is not
246       specified. */
247    kevent_socket_fill();
248    kev.data = 1;
249    kevent_cmp(&kev, kevent_get(kqfd));
250    test_no_kevents(kqfd);
251
252    /* Re-enable the kevent */
253    /* FIXME- is EV_DISPATCH needed when rearming ? */
254    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_ENABLE | EV_DISPATCH, 0, 0, &sockfd[0]);
255    kev.data = 1;
256    kev.flags = EV_ADD | EV_DISPATCH;   /* FIXME: may not be portable */
257    kevent_cmp(&kev, kevent_get(kqfd));
258    test_no_kevents(kqfd);
259
260    /* Since the knote is disabled, the EV_DELETE operation succeeds. */
261    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
262
263    kevent_socket_drain();
264}
265#endif  /* HAVE_EV_DISPATCH */
266
267#if BROKEN_ON_LINUX
268void
269test_kevent_socket_lowat(void)
270{
271    struct kevent kev;
272
273    test_begin(test_id);
274
275    /* Re-add the watch and make sure no events are pending */
276    puts("-- re-adding knote, setting low watermark to 2 bytes");
277    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
278    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
279        die("%s", test_id);
280    test_no_kevents();
281
282    puts("-- checking that one byte does not trigger an event..");
283    kevent_socket_fill();
284    test_no_kevents();
285
286    puts("-- checking that two bytes triggers an event..");
287    kevent_socket_fill();
288    if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
289        die("%s", test_id);
290    KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
291    test_no_kevents();
292
293    kevent_socket_drain();
294    kevent_socket_drain();
295}
296#endif
297
298void
299test_kevent_socket_eof(void)
300{
301    struct kevent kev;
302
303    /* Re-add the watch and make sure no events are pending */
304    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
305    test_no_kevents(kqfd);
306
307    if (close(sockfd[1]) < 0)
308        die("close(2)");
309
310    kev.flags |= EV_EOF;
311    kevent_cmp(&kev, kevent_get(kqfd));
312
313    /* Delete the watch */
314    kevent_add(kqfd, &kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
315}
316
317void
318test_evfilt_read(int _kqfd)
319{
320    /* Create a connected pair of full-duplex sockets for testing socket events */
321    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
322        die("socketpair");
323
324    kqfd = _kqfd;
325    test(kevent_socket_add);
326    test(kevent_socket_del);
327    test(kevent_socket_add_without_ev_add);
328    test(kevent_socket_get);
329    test(kevent_socket_disable_and_enable);
330    test(kevent_socket_oneshot);
331    test(kevent_socket_clear);
332#if HAVE_EV_DISPATCH
333    test(kevent_socket_dispatch);
334#endif
335    test(kevent_socket_listen_backlog);
336    test(kevent_socket_eof);
337    close(sockfd[0]);
338    close(sockfd[1]);
339}
340