xref: /netbsd-src/tests/kernel/kqueue/t_empty.c (revision 39896d44a90e8ce157d6be66da58db2f2ba9afb8)
1*39896d44Srin /* $NetBSD: t_empty.c,v 1.2 2024/08/23 07:13:50 rin Exp $ */
2d5b88446Sthorpej 
3d5b88446Sthorpej /*-
4d5b88446Sthorpej  * Copyright (c) 2021 The NetBSD Foundation, Inc.
5d5b88446Sthorpej  * All rights reserved.
6d5b88446Sthorpej  *
7d5b88446Sthorpej  * Redistribution and use in source and binary forms, with or without
8d5b88446Sthorpej  * modification, are permitted provided that the following conditions
9d5b88446Sthorpej  * are met:
10d5b88446Sthorpej  * 1. Redistributions of source code must retain the above copyright
11d5b88446Sthorpej  *    notice, this list of conditions and the following disclaimer.
12d5b88446Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
13d5b88446Sthorpej  *    notice, this list of conditions and the following disclaimer in the
14d5b88446Sthorpej  *    documentation and/or other materials provided with the distribution.
15d5b88446Sthorpej  *
16d5b88446Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17d5b88446Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18d5b88446Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19d5b88446Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20d5b88446Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21d5b88446Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22d5b88446Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23d5b88446Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24d5b88446Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25d5b88446Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26d5b88446Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
27d5b88446Sthorpej  */
28d5b88446Sthorpej 
29d5b88446Sthorpej #include <sys/cdefs.h>
30*39896d44Srin __RCSID("$NetBSD: t_empty.c,v 1.2 2024/08/23 07:13:50 rin Exp $");
31d5b88446Sthorpej 
32d5b88446Sthorpej #include <sys/event.h>
33d5b88446Sthorpej #include <sys/socket.h>
34d5b88446Sthorpej #include <sys/time.h>
35d5b88446Sthorpej #include <sys/types.h>
36d5b88446Sthorpej 
37d5b88446Sthorpej #include <netinet/in.h>
38d5b88446Sthorpej 
39d5b88446Sthorpej #include <err.h>
40d5b88446Sthorpej #include <errno.h>
41d5b88446Sthorpej #include <fcntl.h>
42d5b88446Sthorpej #include <stdbool.h>
43d5b88446Sthorpej #include <stdio.h>
44d5b88446Sthorpej #include <stdlib.h>
45d5b88446Sthorpej #include <unistd.h>
46d5b88446Sthorpej 
47d5b88446Sthorpej #include <atf-c.h>
48d5b88446Sthorpej 
49d5b88446Sthorpej static void
50d5b88446Sthorpej test_empty(int readfd, int writefd, bool is_tcp)
51d5b88446Sthorpej {
52d5b88446Sthorpej 	struct timespec ts = { 0, 0 };
53d5b88446Sthorpej 	struct kevent event;
54d5b88446Sthorpej 	int kq, error, sndbufsize;
55d5b88446Sthorpej 	char buf[1024] = { 0 };
56d5b88446Sthorpej 	ssize_t rv;
57d5b88446Sthorpej 
58d5b88446Sthorpej 	ATF_REQUIRE((kq = kqueue()) >= 0);
59d5b88446Sthorpej 
60d5b88446Sthorpej 	EV_SET(&event, writefd, EVFILT_EMPTY, EV_ADD, 0, 0, NULL);
61d5b88446Sthorpej 	ATF_REQUIRE(kevent(kq, &event, 1, NULL, 0, NULL) == 0);
62d5b88446Sthorpej 
63d5b88446Sthorpej 	/* Check that EMPTY is true. */
64d5b88446Sthorpej 	memset(&event, 0, sizeof(event));
65d5b88446Sthorpej 	ATF_REQUIRE(kevent(kq, NULL, 0, &event, 1, &ts) == 1);
66d5b88446Sthorpej 	ATF_REQUIRE(event.ident == (uintptr_t)writefd);
67d5b88446Sthorpej 	ATF_REQUIRE(event.filter == EVFILT_EMPTY);
68d5b88446Sthorpej 
69d5b88446Sthorpej 	if (is_tcp) {
70d5b88446Sthorpej 		/*
71d5b88446Sthorpej 		 * Get the write socket buffer size so that we can set
72d5b88446Sthorpej 		 * the read socket buffer size to something larger
73d5b88446Sthorpej 		 * later on.
74d5b88446Sthorpej 		 */
75d5b88446Sthorpej 		socklen_t slen = sizeof(sndbufsize);
76d5b88446Sthorpej 		ATF_REQUIRE(getsockopt(writefd, SOL_SOCKET,
77d5b88446Sthorpej 		    SO_SNDBUF, &sndbufsize, &slen) == 0);
78d5b88446Sthorpej 
79d5b88446Sthorpej 		/*
80d5b88446Sthorpej 		 * Set the receive buffer size to 1, slamming shut
81d5b88446Sthorpej 		 * the TCP receive window, thus trapping all of the
82d5b88446Sthorpej 		 * data in the sender's queue.
83d5b88446Sthorpej 		 */
84d5b88446Sthorpej 		int val = 1;
85d5b88446Sthorpej 		ATF_REQUIRE(setsockopt(readfd, SOL_SOCKET,
86d5b88446Sthorpej 		    SO_RCVBUF, &val, sizeof(val)) == 0);
87d5b88446Sthorpej 	}
88d5b88446Sthorpej 
89d5b88446Sthorpej 	/* Write until the write buffer is full. */
90d5b88446Sthorpej 	for (rv = 0; rv != -1;) {
91d5b88446Sthorpej 		rv = write(writefd, buf, sizeof(buf));
92d5b88446Sthorpej 		error = errno;
93d5b88446Sthorpej 		ATF_REQUIRE(rv > 0 || (rv == -1 && error == EAGAIN));
94d5b88446Sthorpej 	}
95d5b88446Sthorpej 
96d5b88446Sthorpej 	/* Check that EMPTY is false. */
97d5b88446Sthorpej 	ATF_REQUIRE(kevent(kq, NULL, 0, &event, 1, &ts) == 0);
98d5b88446Sthorpej 
99d5b88446Sthorpej 	if (is_tcp) {
100d5b88446Sthorpej 		/*
101d5b88446Sthorpej 		 * Set the receive buffer size to something larger than
102d5b88446Sthorpej 		 * the sender's send buffer.
103d5b88446Sthorpej 		 */
104d5b88446Sthorpej 		int val = sndbufsize + 128;
105d5b88446Sthorpej 		ATF_REQUIRE(setsockopt(readfd, SOL_SOCKET,
106d5b88446Sthorpej 		    SO_RCVBUF, &val, sizeof(val)) == 0);
107d5b88446Sthorpej 	}
108d5b88446Sthorpej 
109d5b88446Sthorpej 	/* Read all of the data that's available. */
110d5b88446Sthorpej 	for (rv = 0; rv != -1;) {
111d5b88446Sthorpej 		rv = read(readfd, buf, sizeof(buf));
112d5b88446Sthorpej 		error = errno;
113d5b88446Sthorpej 		ATF_REQUIRE(rv > 0 || (rv == -1 && error == EAGAIN));
114d5b88446Sthorpej 	}
115d5b88446Sthorpej 
116d5b88446Sthorpej 	/*
117d5b88446Sthorpej 	 * Check that EMPTY is true.  Check a few times (TCP might
118d5b88446Sthorpej 	 * not drain immediately).
119d5b88446Sthorpej 	 */
120d5b88446Sthorpej 	if (is_tcp) {
121d5b88446Sthorpej 		for (rv = 0; rv < 5; rv++) {
122d5b88446Sthorpej 			if (kevent(kq, NULL, 0, &event, 1, &ts) == 1) {
123d5b88446Sthorpej 				break;
124d5b88446Sthorpej 			}
125d5b88446Sthorpej 		}
126d5b88446Sthorpej 		sleep(1);
127d5b88446Sthorpej 	}
128d5b88446Sthorpej 	memset(&event, 0, sizeof(event));
129d5b88446Sthorpej 	ATF_REQUIRE(kevent(kq, NULL, 0, &event, 1, &ts) == 1);
130d5b88446Sthorpej 	ATF_REQUIRE(event.ident == (uintptr_t)writefd);
131d5b88446Sthorpej 	ATF_REQUIRE(event.filter == EVFILT_EMPTY);
132d5b88446Sthorpej }
133d5b88446Sthorpej 
134d5b88446Sthorpej ATF_TC(sock_tcp);
135d5b88446Sthorpej ATF_TC_HEAD(sock_tcp, tc)
136d5b88446Sthorpej {
137d5b88446Sthorpej 	atf_tc_set_md_var(tc, "descr",
138d5b88446Sthorpej 	    "Test EVFILT_EMPTY with TCP sockets.");
139d5b88446Sthorpej }
140d5b88446Sthorpej 
141d5b88446Sthorpej ATF_TC_BODY(sock_tcp, tc)
142d5b88446Sthorpej {
143d5b88446Sthorpej 	int readsock, writesock;
144d5b88446Sthorpej 	socklen_t slen;
145d5b88446Sthorpej 
146d5b88446Sthorpej 	ATF_REQUIRE((readsock =
147d5b88446Sthorpej 	    socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)) != -1);
148d5b88446Sthorpej 	ATF_REQUIRE((writesock =
149d5b88446Sthorpej 	    socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)) != -1);
150d5b88446Sthorpej 
151d5b88446Sthorpej 	struct sockaddr_in sin = {
152d5b88446Sthorpej 		.sin_len = sizeof(sin),
153d5b88446Sthorpej 		.sin_family = AF_INET,
154d5b88446Sthorpej 		.sin_port = 0,		/* no need to swap 0 */
155d5b88446Sthorpej 		.sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
156d5b88446Sthorpej 	};
157d5b88446Sthorpej 	ATF_REQUIRE(bind(readsock, (struct sockaddr *)&sin,
158d5b88446Sthorpej 	    sizeof(sin)) == 0);
159d5b88446Sthorpej 	ATF_REQUIRE(listen(readsock, 1) == 0);
160d5b88446Sthorpej 	slen = sizeof(sin);
161d5b88446Sthorpej 	ATF_REQUIRE(getsockname(readsock, (struct sockaddr *)&sin, &slen) == 0);
162d5b88446Sthorpej 
163d5b88446Sthorpej 	ATF_REQUIRE_ERRNO(EINPROGRESS,
164d5b88446Sthorpej 	    connect(writesock, (struct sockaddr *)&sin, sizeof(sin)) == -1);
165d5b88446Sthorpej 
166*39896d44Srin 	/* XXX Avoid race between connect(2) and accept(2). */
167*39896d44Srin 	sleep(1);
168*39896d44Srin 
169d5b88446Sthorpej 	slen = sizeof(sin);
170d5b88446Sthorpej 	ATF_REQUIRE((readsock = accept(readsock, (struct sockaddr *)&sin,
171d5b88446Sthorpej 	    &slen)) != -1);
172d5b88446Sthorpej 
173d5b88446Sthorpej 	test_empty(readsock, writesock, true);
174d5b88446Sthorpej }
175d5b88446Sthorpej 
176d5b88446Sthorpej ATF_TP_ADD_TCS(tp)
177d5b88446Sthorpej {
178d5b88446Sthorpej 	ATF_TP_ADD_TC(tp, sock_tcp);
179d5b88446Sthorpej 
180d5b88446Sthorpej 	return atf_no_error();
181d5b88446Sthorpej }
182