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