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(0); 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 socklen_t slen; 99 struct pollfd pfd; 100 int one = 1; 101 102 /* Verify that we don't expose POLLRDHUP if not requested. */ 103 104 /* Server setup. */ 105 ss = socket(PF_INET, SOCK_STREAM, 0); 106 ATF_CHECK(ss >= 0); 107 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 108 ATF_CHECK_EQ(0, rc); 109 bzero(&sin, sizeof(sin)); 110 sin.sin_family = AF_INET; 111 sin.sin_len = sizeof(sin); 112 sin.sin_port = htons(0); 113 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 114 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 115 ATF_CHECK_EQ(0, rc); 116 rc = listen(ss, 1); 117 ATF_CHECK_EQ(0, rc); 118 slen = sizeof(sin); 119 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 120 ATF_CHECK_EQ(0, rc); 121 122 /* Client connects, server accepts. */ 123 cs = socket(PF_INET, SOCK_STREAM, 0); 124 ATF_CHECK(cs >= 0); 125 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 126 ATF_CHECK_EQ(0, rc); 127 ss2 = accept(ss, NULL, NULL); 128 ATF_CHECK(ss2 >= 0); 129 130 /* Server can write, sees only POLLOUT. */ 131 pfd.fd = ss2; 132 pfd.events = POLLIN | POLLOUT; 133 rc = poll(&pfd, 1, 0); 134 ATF_CHECK_EQ(1, rc); 135 ATF_CHECK_EQ(POLLOUT, pfd.revents); 136 137 /* Client closes socket! */ 138 rc = close(cs); 139 ATF_CHECK_EQ(0, rc); 140 141 /* 142 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask. 143 * Need non-zero timeout to wait for the FIN to arrive and trigger the 144 * socket to become readable. 145 */ 146 pfd.fd = ss2; 147 pfd.events = POLLIN; 148 rc = poll(&pfd, 1, 60000); 149 ATF_CHECK_EQ(1, rc); 150 ATF_CHECK_EQ(POLLIN, pfd.revents); 151 152 close(ss2); 153 close(ss); 154 } 155 156 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup); 157 ATF_TC_BODY(socket_afinet_poll_rdhup, tc) 158 { 159 int ss, ss2, cs, rc; 160 struct sockaddr_in sin; 161 socklen_t slen; 162 struct pollfd pfd; 163 char buffer; 164 int one = 1; 165 166 /* Verify that server sees POLLRDHUP if it asks for it. */ 167 168 /* Server setup. */ 169 ss = socket(PF_INET, SOCK_STREAM, 0); 170 ATF_CHECK(ss >= 0); 171 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 172 ATF_CHECK_EQ(0, rc); 173 bzero(&sin, sizeof(sin)); 174 sin.sin_family = AF_INET; 175 sin.sin_len = sizeof(sin); 176 sin.sin_port = htons(0); 177 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 178 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 179 ATF_CHECK_EQ(0, rc); 180 rc = listen(ss, 1); 181 ATF_CHECK_EQ(0, rc); 182 slen = sizeof(sin); 183 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 184 ATF_CHECK_EQ(0, rc); 185 186 /* Client connects, server accepts. */ 187 cs = socket(PF_INET, SOCK_STREAM, 0); 188 ATF_CHECK(cs >= 0); 189 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 190 ATF_CHECK_EQ(0, rc); 191 ss2 = accept(ss, NULL, NULL); 192 ATF_CHECK(ss2 >= 0); 193 194 /* Server can write, so sees POLLOUT. */ 195 pfd.fd = ss2; 196 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 197 rc = poll(&pfd, 1, 0); 198 ATF_CHECK_EQ(1, rc); 199 ATF_CHECK_EQ(POLLOUT, pfd.revents); 200 201 /* Client writes two bytes, server reads only one of them. */ 202 rc = write(cs, "xx", 2); 203 ATF_CHECK_EQ(2, rc); 204 rc = read(ss2, &buffer, 1); 205 ATF_CHECK_EQ(1, rc); 206 207 /* Server can read, so sees POLLIN. */ 208 pfd.fd = ss2; 209 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 210 rc = poll(&pfd, 1, 0); 211 ATF_CHECK_EQ(1, rc); 212 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents); 213 214 /* Client closes socket! */ 215 rc = close(cs); 216 ATF_CHECK_EQ(0, rc); 217 218 /* 219 * Server sees Linux-style POLLRDHUP. Note that this is the case even 220 * though one byte of data remains unread. 221 * 222 * This races against the delivery of FIN caused by the close() above. 223 * Sometimes (more likely when run under truss or if another system 224 * call is added in between) it hits the path where sopoll_generic() 225 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag 226 * SB_SEL so that it's woken up almost immediately and runs again, 227 * which is why we need a non-zero timeout here. 228 */ 229 pfd.fd = ss2; 230 pfd.events = POLLRDHUP; 231 rc = poll(&pfd, 1, 60000); 232 ATF_CHECK_EQ(1, rc); 233 ATF_CHECK_EQ(POLLRDHUP, pfd.revents); 234 235 close(ss2); 236 close(ss); 237 } 238 239 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect); 240 ATF_TC_BODY(socket_afinet_stream_reconnect, tc) 241 { 242 struct sockaddr_in sin; 243 socklen_t slen; 244 int ss, cs, rc; 245 246 /* 247 * Make sure that an attempt to connect(2) a connected or disconnected 248 * stream socket fails with EISCONN. 249 */ 250 251 /* Server setup. */ 252 ss = socket(PF_INET, SOCK_STREAM, 0); 253 ATF_CHECK(ss >= 0); 254 bzero(&sin, sizeof(sin)); 255 sin.sin_family = AF_INET; 256 sin.sin_len = sizeof(sin); 257 sin.sin_port = htons(0); 258 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 259 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 260 ATF_CHECK_EQ(0, rc); 261 rc = listen(ss, 1); 262 ATF_CHECK_EQ(0, rc); 263 slen = sizeof(sin); 264 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 265 ATF_CHECK_EQ(0, rc); 266 267 /* Client connects, shuts down. */ 268 cs = socket(PF_INET, SOCK_STREAM, 0); 269 ATF_CHECK(cs >= 0); 270 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 271 ATF_CHECK_EQ(0, rc); 272 rc = shutdown(cs, SHUT_RDWR); 273 ATF_CHECK_EQ(0, rc); 274 275 /* A subsequent connect(2) fails with EISCONN. */ 276 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 277 ATF_CHECK_EQ(-1, rc); 278 ATF_CHECK_EQ(errno, EISCONN); 279 280 rc = close(cs); 281 ATF_CHECK_EQ(0, rc); 282 rc = close(ss); 283 ATF_CHECK_EQ(0, rc); 284 } 285 286 ATF_TP_ADD_TCS(tp) 287 { 288 ATF_TP_ADD_TC(tp, socket_afinet); 289 ATF_TP_ADD_TC(tp, socket_afinet_bind_zero); 290 ATF_TP_ADD_TC(tp, socket_afinet_bind_ok); 291 ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup); 292 ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup); 293 ATF_TP_ADD_TC(tp, socket_afinet_stream_reconnect); 294 295 return atf_no_error(); 296 } 297