2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2019 Bjoern A. Zeeb
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/socket.h>
32 #include <netinet/in.h>
38 ATF_TC_WITHOUT_HEAD(socket_afinet);
39 ATF_TC_BODY(socket_afinet, tc)
43 sd = socket(PF_INET, SOCK_DGRAM, 0);
49 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero);
50 ATF_TC_BODY(socket_afinet_bind_zero, tc)
53 struct sockaddr_in sin;
55 if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
56 atf_tc_skip("doesn't work when mac_portacl(4) loaded (https://bugs.freebsd.org/238781)");
58 sd = socket(PF_INET, SOCK_DGRAM, 0);
61 bzero(&sin, sizeof(sin));
63 * For AF_INET we do not check the family in in_pcbbind_setup(9),
64 * sa_len gets set from the syscall argument in getsockaddr(9),
67 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
73 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok);
74 ATF_TC_BODY(socket_afinet_bind_ok, tc)
77 struct sockaddr_in sin;
79 sd = socket(PF_INET, SOCK_DGRAM, 0);
82 bzero(&sin, sizeof(sin));
83 sin.sin_family = AF_INET;
84 sin.sin_len = sizeof(sin);
85 sin.sin_port = htons(6666);
86 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
87 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
93 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup);
94 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc)
97 struct sockaddr_in sin;
101 /* Verify that we don't expose POLLRDHUP if not requested. */
104 ss = socket(PF_INET, SOCK_STREAM, 0);
106 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
108 bzero(&sin, sizeof(sin));
109 sin.sin_family = AF_INET;
110 sin.sin_len = sizeof(sin);
111 sin.sin_port = htons(6666);
112 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
113 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
118 /* Client connects, server accepts. */
119 cs = socket(PF_INET, SOCK_STREAM, 0);
121 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
123 ss2 = accept(ss, NULL, NULL);
126 /* Server can write, sees only POLLOUT. */
128 pfd.events = POLLIN | POLLOUT;
129 rc = poll(&pfd, 1, 0);
131 ATF_CHECK_EQ(POLLOUT, pfd.revents);
133 /* Client closes socket! */
138 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask.
139 * Need non-zero timeout to wait for the FIN to arrive and trigger the
140 * socket to become readable.
144 rc = poll(&pfd, 1, 60000);
146 ATF_CHECK_EQ(POLLIN, pfd.revents);
152 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup);
153 ATF_TC_BODY(socket_afinet_poll_rdhup, tc)
156 struct sockaddr_in sin;
161 /* Verify that server sees POLLRDHUP if it asks for it. */
164 ss = socket(PF_INET, SOCK_STREAM, 0);
166 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
168 bzero(&sin, sizeof(sin));
169 sin.sin_family = AF_INET;
170 sin.sin_len = sizeof(sin);
171 sin.sin_port = htons(6666);
172 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
173 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
178 /* Client connects, server accepts. */
179 cs = socket(PF_INET, SOCK_STREAM, 0);
181 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
183 ss2 = accept(ss, NULL, NULL);
186 /* Server can write, so sees POLLOUT. */
188 pfd.events = POLLIN | POLLOUT | POLLRDHUP;
189 rc = poll(&pfd, 1, 0);
191 ATF_CHECK_EQ(POLLOUT, pfd.revents);
193 /* Client writes two bytes, server reads only one of them. */
194 rc = write(cs, "xx", 2);
196 rc = read(ss2, &buffer, 1);
199 /* Server can read, so sees POLLIN. */
201 pfd.events = POLLIN | POLLOUT | POLLRDHUP;
202 rc = poll(&pfd, 1, 0);
204 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents);
206 /* Client closes socket! */
211 * Server sees Linux-style POLLRDHUP. Note that this is the case even
212 * though one byte of data remains unread.
214 * This races against the delivery of FIN caused by the close() above.
215 * Sometimes (more likely when run under truss or if another system
216 * call is added in between) it hits the path where sopoll_generic()
217 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag
218 * SB_SEL so that it's woken up almost immediately and runs again,
219 * which is why we need a non-zero timeout here.
222 pfd.events = POLLRDHUP;
223 rc = poll(&pfd, 1, 60000);
225 ATF_CHECK_EQ(POLLRDHUP, pfd.revents);
231 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect);
232 ATF_TC_BODY(socket_afinet_stream_reconnect, tc)
234 struct sockaddr_in sin;
238 * Make sure that an attempt to connect(2) a connected or disconnected
239 * stream socket fails with EISCONN.
243 ss = socket(PF_INET, SOCK_STREAM, 0);
245 bzero(&sin, sizeof(sin));
246 sin.sin_family = AF_INET;
247 sin.sin_len = sizeof(sin);
248 sin.sin_port = htons(6666);
249 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
250 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
255 /* Client connects, shuts down. */
256 cs = socket(PF_INET, SOCK_STREAM, 0);
258 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
260 rc = shutdown(cs, SHUT_RDWR);
263 /* A subsequent connect(2) fails with EISCONN. */
264 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
265 ATF_CHECK_EQ(-1, rc);
266 ATF_CHECK_EQ(errno, EISCONN);
276 ATF_TP_ADD_TC(tp, socket_afinet);
277 ATF_TP_ADD_TC(tp, socket_afinet_bind_zero);
278 ATF_TP_ADD_TC(tp, socket_afinet_bind_ok);
279 ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup);
280 ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup);
281 ATF_TP_ADD_TC(tp, socket_afinet_stream_reconnect);
283 return atf_no_error();