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 #include <sys/socket.h> 30 #include <netinet/in.h> 31 #include <errno.h> 32 #include <poll.h> 33 34 #include <atf-c.h> 35 36 ATF_TC_WITHOUT_HEAD(socket_afinet); 37 ATF_TC_BODY(socket_afinet, tc) 38 { 39 int sd; 40 41 sd = socket(PF_INET, SOCK_DGRAM, 0); 42 ATF_CHECK(sd >= 0); 43 44 close(sd); 45 } 46 47 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero); 48 ATF_TC_BODY(socket_afinet_bind_zero, tc) 49 { 50 int sd, rc; 51 struct sockaddr_in sin; 52 53 if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) 54 atf_tc_skip("doesn't work when mac_portacl(4) loaded (https://bugs.freebsd.org/238781)"); 55 56 sd = socket(PF_INET, SOCK_DGRAM, 0); 57 ATF_CHECK(sd >= 0); 58 59 bzero(&sin, sizeof(sin)); 60 /* 61 * For AF_INET we do not check the family in in_pcbbind_setup(9), 62 * sa_len gets set from the syscall argument in getsockaddr(9), 63 * so we bind to 0:0. 64 */ 65 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 66 ATF_CHECK_EQ(0, rc); 67 68 close(sd); 69 } 70 71 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok); 72 ATF_TC_BODY(socket_afinet_bind_ok, tc) 73 { 74 int sd, rc; 75 struct sockaddr_in sin; 76 77 sd = socket(PF_INET, SOCK_DGRAM, 0); 78 ATF_CHECK(sd >= 0); 79 80 bzero(&sin, sizeof(sin)); 81 sin.sin_family = AF_INET; 82 sin.sin_len = sizeof(sin); 83 sin.sin_port = htons(0); 84 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 85 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 86 ATF_CHECK_EQ(0, rc); 87 88 close(sd); 89 } 90 91 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup); 92 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc) 93 { 94 int ss, ss2, cs, rc; 95 struct sockaddr_in sin; 96 socklen_t slen; 97 struct pollfd pfd; 98 int one = 1; 99 100 /* Verify that we don't expose POLLRDHUP if not requested. */ 101 102 /* Server setup. */ 103 ss = socket(PF_INET, SOCK_STREAM, 0); 104 ATF_CHECK(ss >= 0); 105 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 106 ATF_CHECK_EQ(0, rc); 107 bzero(&sin, sizeof(sin)); 108 sin.sin_family = AF_INET; 109 sin.sin_len = sizeof(sin); 110 sin.sin_port = htons(0); 111 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 112 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 113 ATF_CHECK_EQ(0, rc); 114 rc = listen(ss, 1); 115 ATF_CHECK_EQ(0, rc); 116 slen = sizeof(sin); 117 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 118 ATF_CHECK_EQ(0, rc); 119 120 /* Client connects, server accepts. */ 121 cs = socket(PF_INET, SOCK_STREAM, 0); 122 ATF_CHECK(cs >= 0); 123 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 124 ATF_CHECK_EQ(0, rc); 125 ss2 = accept(ss, NULL, NULL); 126 ATF_CHECK(ss2 >= 0); 127 128 /* Server can write, sees only POLLOUT. */ 129 pfd.fd = ss2; 130 pfd.events = POLLIN | POLLOUT; 131 rc = poll(&pfd, 1, 0); 132 ATF_CHECK_EQ(1, rc); 133 ATF_CHECK_EQ(POLLOUT, pfd.revents); 134 135 /* Client closes socket! */ 136 rc = close(cs); 137 ATF_CHECK_EQ(0, rc); 138 139 /* 140 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask. 141 * Need non-zero timeout to wait for the FIN to arrive and trigger the 142 * socket to become readable. 143 */ 144 pfd.fd = ss2; 145 pfd.events = POLLIN; 146 rc = poll(&pfd, 1, 60000); 147 ATF_CHECK_EQ(1, rc); 148 ATF_CHECK_EQ(POLLIN, pfd.revents); 149 150 close(ss2); 151 close(ss); 152 } 153 154 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup); 155 ATF_TC_BODY(socket_afinet_poll_rdhup, tc) 156 { 157 int ss, ss2, cs, rc; 158 struct sockaddr_in sin; 159 socklen_t slen; 160 struct pollfd pfd; 161 char buffer; 162 int one = 1; 163 164 /* Verify that server sees POLLRDHUP if it asks for it. */ 165 166 /* Server setup. */ 167 ss = socket(PF_INET, SOCK_STREAM, 0); 168 ATF_CHECK(ss >= 0); 169 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 170 ATF_CHECK_EQ(0, rc); 171 bzero(&sin, sizeof(sin)); 172 sin.sin_family = AF_INET; 173 sin.sin_len = sizeof(sin); 174 sin.sin_port = htons(0); 175 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 176 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 177 ATF_CHECK_EQ(0, rc); 178 rc = listen(ss, 1); 179 ATF_CHECK_EQ(0, rc); 180 slen = sizeof(sin); 181 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 182 ATF_CHECK_EQ(0, rc); 183 184 /* Client connects, server accepts. */ 185 cs = socket(PF_INET, SOCK_STREAM, 0); 186 ATF_CHECK(cs >= 0); 187 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 188 ATF_CHECK_EQ(0, rc); 189 ss2 = accept(ss, NULL, NULL); 190 ATF_CHECK(ss2 >= 0); 191 192 /* Server can write, so sees POLLOUT. */ 193 pfd.fd = ss2; 194 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 195 rc = poll(&pfd, 1, 0); 196 ATF_CHECK_EQ(1, rc); 197 ATF_CHECK_EQ(POLLOUT, pfd.revents); 198 199 /* Client writes two bytes, server reads only one of them. */ 200 rc = write(cs, "xx", 2); 201 ATF_CHECK_EQ(2, rc); 202 rc = read(ss2, &buffer, 1); 203 ATF_CHECK_EQ(1, rc); 204 205 /* Server can read, so sees POLLIN. */ 206 pfd.fd = ss2; 207 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 208 rc = poll(&pfd, 1, 0); 209 ATF_CHECK_EQ(1, rc); 210 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents); 211 212 /* Client closes socket! */ 213 rc = close(cs); 214 ATF_CHECK_EQ(0, rc); 215 216 /* 217 * Server sees Linux-style POLLRDHUP. Note that this is the case even 218 * though one byte of data remains unread. 219 * 220 * This races against the delivery of FIN caused by the close() above. 221 * Sometimes (more likely when run under truss or if another system 222 * call is added in between) it hits the path where sopoll_generic() 223 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag 224 * SB_SEL so that it's woken up almost immediately and runs again, 225 * which is why we need a non-zero timeout here. 226 */ 227 pfd.fd = ss2; 228 pfd.events = POLLRDHUP; 229 rc = poll(&pfd, 1, 60000); 230 ATF_CHECK_EQ(1, rc); 231 ATF_CHECK_EQ(POLLRDHUP, pfd.revents); 232 233 close(ss2); 234 close(ss); 235 } 236 237 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect); 238 ATF_TC_BODY(socket_afinet_stream_reconnect, tc) 239 { 240 struct sockaddr_in sin; 241 socklen_t slen; 242 int ss, cs, rc; 243 244 /* 245 * Make sure that an attempt to connect(2) a connected or disconnected 246 * stream socket fails with EISCONN. 247 */ 248 249 /* Server setup. */ 250 ss = socket(PF_INET, SOCK_STREAM, 0); 251 ATF_CHECK(ss >= 0); 252 bzero(&sin, sizeof(sin)); 253 sin.sin_family = AF_INET; 254 sin.sin_len = sizeof(sin); 255 sin.sin_port = htons(0); 256 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 257 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 258 ATF_CHECK_EQ(0, rc); 259 rc = listen(ss, 1); 260 ATF_CHECK_EQ(0, rc); 261 slen = sizeof(sin); 262 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 263 ATF_CHECK_EQ(0, rc); 264 265 /* Client connects, shuts down. */ 266 cs = socket(PF_INET, SOCK_STREAM, 0); 267 ATF_CHECK(cs >= 0); 268 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 269 ATF_CHECK_EQ(0, rc); 270 rc = shutdown(cs, SHUT_RDWR); 271 ATF_CHECK_EQ(0, rc); 272 273 /* A subsequent connect(2) fails with EISCONN. */ 274 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 275 ATF_CHECK_EQ(-1, rc); 276 ATF_CHECK_EQ(errno, EISCONN); 277 278 rc = close(cs); 279 ATF_CHECK_EQ(0, rc); 280 rc = close(ss); 281 ATF_CHECK_EQ(0, rc); 282 } 283 284 ATF_TP_ADD_TCS(tp) 285 { 286 ATF_TP_ADD_TC(tp, socket_afinet); 287 ATF_TP_ADD_TC(tp, socket_afinet_bind_zero); 288 ATF_TP_ADD_TC(tp, socket_afinet_bind_ok); 289 ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup); 290 ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup); 291 ATF_TP_ADD_TC(tp, socket_afinet_stream_reconnect); 292 293 return atf_no_error(); 294 } 295