]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/netinet/socket_afinet.c
zfs: merge openzfs/zfs@a9d6b0690
[FreeBSD/FreeBSD.git] / tests / sys / netinet / socket_afinet.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Bjoern A. Zeeb
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <errno.h>
34 #include <poll.h>
35
36 #include <atf-c.h>
37
38 ATF_TC_WITHOUT_HEAD(socket_afinet);
39 ATF_TC_BODY(socket_afinet, tc)
40 {
41         int sd;
42
43         sd = socket(PF_INET, SOCK_DGRAM, 0);
44         ATF_CHECK(sd >= 0);
45
46         close(sd);
47 }
48
49 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero);
50 ATF_TC_BODY(socket_afinet_bind_zero, tc)
51 {
52         int sd, rc;
53         struct sockaddr_in sin;
54
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)");
57
58         sd = socket(PF_INET, SOCK_DGRAM, 0);
59         ATF_CHECK(sd >= 0);
60
61         bzero(&sin, sizeof(sin));
62         /*
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),
65          * so we bind to 0:0.
66          */
67         rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
68         ATF_CHECK_EQ(0, rc);
69
70         close(sd);
71 }
72
73 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok);
74 ATF_TC_BODY(socket_afinet_bind_ok, tc)
75 {
76         int sd, rc;
77         struct sockaddr_in sin;
78
79         sd = socket(PF_INET, SOCK_DGRAM, 0);
80         ATF_CHECK(sd >= 0);
81
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));
88         ATF_CHECK_EQ(0, rc);
89
90         close(sd);
91 }
92
93 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup);
94 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc)
95 {
96         int ss, ss2, cs, rc;
97         struct sockaddr_in sin;
98         struct pollfd pfd;
99         int one = 1;
100
101         /* Verify that we don't expose POLLRDHUP if not requested. */
102
103         /* Server setup. */
104         ss = socket(PF_INET, SOCK_STREAM, 0);
105         ATF_CHECK(ss >= 0);
106         rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
107         ATF_CHECK_EQ(0, rc);
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));
114         ATF_CHECK_EQ(0, rc);
115         rc = listen(ss, 1);
116         ATF_CHECK_EQ(0, rc);
117
118         /* Client connects, server accepts. */
119         cs = socket(PF_INET, SOCK_STREAM, 0);
120         ATF_CHECK(cs >= 0);
121         rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
122         ATF_CHECK_EQ(0, rc);
123         ss2 = accept(ss, NULL, NULL);
124         ATF_CHECK(ss2 >= 0);
125
126         /* Server can write, sees only POLLOUT. */
127         pfd.fd = ss2;
128         pfd.events = POLLIN | POLLOUT;
129         rc = poll(&pfd, 1, 0);
130         ATF_CHECK_EQ(1, rc);
131         ATF_CHECK_EQ(POLLOUT, pfd.revents);
132
133         /* Client closes socket! */
134         rc = close(cs);
135         ATF_CHECK_EQ(0, rc);
136
137         /*
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.
141          */
142         pfd.fd = ss2;
143         pfd.events = POLLIN;
144         rc = poll(&pfd, 1, 60000);
145         ATF_CHECK_EQ(1, rc);
146         ATF_CHECK_EQ(POLLIN, pfd.revents);
147
148         close(ss2);
149         close(ss);
150 }
151
152 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup);
153 ATF_TC_BODY(socket_afinet_poll_rdhup, tc)
154 {
155         int ss, ss2, cs, rc;
156         struct sockaddr_in sin;
157         struct pollfd pfd;
158         char buffer;
159         int one = 1;
160
161         /* Verify that server sees POLLRDHUP if it asks for it. */
162
163         /* Server setup. */
164         ss = socket(PF_INET, SOCK_STREAM, 0);
165         ATF_CHECK(ss >= 0);
166         rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
167         ATF_CHECK_EQ(0, rc);
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));
174         ATF_CHECK_EQ(0, rc);
175         rc = listen(ss, 1);
176         ATF_CHECK_EQ(0, rc);
177
178         /* Client connects, server accepts. */
179         cs = socket(PF_INET, SOCK_STREAM, 0);
180         ATF_CHECK(cs >= 0);
181         rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
182         ATF_CHECK_EQ(0, rc);
183         ss2 = accept(ss, NULL, NULL);
184         ATF_CHECK(ss2 >= 0);
185
186         /* Server can write, so sees POLLOUT. */
187         pfd.fd = ss2;
188         pfd.events = POLLIN | POLLOUT | POLLRDHUP;
189         rc = poll(&pfd, 1, 0);
190         ATF_CHECK_EQ(1, rc);
191         ATF_CHECK_EQ(POLLOUT, pfd.revents);
192
193         /* Client writes two bytes, server reads only one of them. */
194         rc = write(cs, "xx", 2);
195         ATF_CHECK_EQ(2, rc);
196         rc = read(ss2, &buffer, 1);
197         ATF_CHECK_EQ(1, rc);
198
199         /* Server can read, so sees POLLIN. */
200         pfd.fd = ss2;
201         pfd.events = POLLIN | POLLOUT | POLLRDHUP;
202         rc = poll(&pfd, 1, 0);
203         ATF_CHECK_EQ(1, rc);
204         ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents);
205
206         /* Client closes socket! */
207         rc = close(cs);
208         ATF_CHECK_EQ(0, rc);
209
210         /*
211          * Server sees Linux-style POLLRDHUP.  Note that this is the case even
212          * though one byte of data remains unread.
213          *
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.
220          */
221         pfd.fd = ss2;
222         pfd.events = POLLRDHUP;
223         rc = poll(&pfd, 1, 60000);
224         ATF_CHECK_EQ(1, rc);
225         ATF_CHECK_EQ(POLLRDHUP, pfd.revents);
226
227         close(ss2);
228         close(ss);
229 }
230
231 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect);
232 ATF_TC_BODY(socket_afinet_stream_reconnect, tc)
233 {
234         struct sockaddr_in sin;
235         int ss, cs, rc;
236
237         /*
238          * Make sure that an attempt to connect(2) a connected or disconnected
239          * stream socket fails with EISCONN.
240          */
241
242         /* Server setup. */
243         ss = socket(PF_INET, SOCK_STREAM, 0);
244         ATF_CHECK(ss >= 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));
251         ATF_CHECK_EQ(0, rc);
252         rc = listen(ss, 1);
253         ATF_CHECK_EQ(0, rc);
254
255         /* Client connects, shuts down. */
256         cs = socket(PF_INET, SOCK_STREAM, 0);
257         ATF_CHECK(cs >= 0);
258         rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
259         ATF_CHECK_EQ(0, rc);
260         rc = shutdown(cs, SHUT_RDWR);
261         ATF_CHECK_EQ(0, rc);
262
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);
267
268         rc = close(cs);
269         ATF_CHECK_EQ(0, rc);
270         rc = close(ss);
271         ATF_CHECK_EQ(0, rc);
272 }
273
274 ATF_TP_ADD_TCS(tp)
275 {
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);
282
283         return atf_no_error();
284 }