1 /* 2 * iperf, Copyright (c) 2014-2019, The Regents of the University of 3 * California, through Lawrence Berkeley National Laboratory (subject 4 * to receipt of any required approvals from the U.S. Dept. of 5 * Energy). All rights reserved. 6 * 7 * If you have questions about your rights to use or distribute this 8 * software, please contact Berkeley Lab's Technology Transfer 9 * Department at TTD@lbl.gov. 10 * 11 * NOTICE. This software is owned by the U.S. Department of Energy. 12 * As such, the U.S. Government has been granted for itself and others 13 * acting on its behalf a paid-up, nonexclusive, irrevocable, 14 * worldwide license in the Software to reproduce, prepare derivative 15 * works, and perform publicly and display publicly. Beginning five 16 * (5) years after the date permission to assert copyright is obtained 17 * from the U.S. Department of Energy, and subject to any subsequent 18 * five (5) year renewals, the U.S. Government is granted for itself 19 * and others acting on its behalf a paid-up, nonexclusive, 20 * irrevocable, worldwide license in the Software to reproduce, 21 * prepare derivative works, distribute copies to the public, perform 22 * publicly and display publicly, and to permit others to do so. 23 * 24 * This code is distributed under a BSD style license, see the LICENSE 25 * file for complete information. 26 */ 27 #include "iperf_config.h" 28 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <errno.h> 32 #include <sys/socket.h> 33 #include <sys/types.h> 34 #include <netinet/in.h> 35 #include <netinet/tcp.h> 36 #include <assert.h> 37 #include <netdb.h> 38 #include <string.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 42 #ifdef HAVE_SENDFILE 43 #ifdef linux 44 #include <sys/sendfile.h> 45 #else 46 #ifdef __FreeBSD__ 47 #include <sys/uio.h> 48 #else 49 #if defined(__APPLE__) && defined(__MACH__) /* OS X */ 50 #include <AvailabilityMacros.h> 51 #if defined(MAC_OS_X_VERSION_10_6) 52 #include <sys/uio.h> 53 #endif 54 #endif 55 #endif 56 #endif 57 #endif /* HAVE_SENDFILE */ 58 59 #ifdef HAVE_POLL_H 60 #include <poll.h> 61 #endif /* HAVE_POLL_H */ 62 63 #include "iperf_util.h" 64 #include "net.h" 65 #include "timer.h" 66 67 /* 68 * Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this 69 * by including "iperf.h", but net.c lives "below" this layer. Clearly the 70 * presence of this declaration is a sign we need to revisit this layering. 71 */ 72 extern int gerror; 73 74 /* 75 * timeout_connect adapted from netcat, via OpenBSD and FreeBSD 76 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 77 */ 78 int 79 timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, 80 int timeout) 81 { 82 struct pollfd pfd; 83 socklen_t optlen; 84 int flags, optval; 85 int ret; 86 87 flags = 0; 88 if (timeout != -1) { 89 flags = fcntl(s, F_GETFL, 0); 90 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 91 return -1; 92 } 93 94 if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 95 pfd.fd = s; 96 pfd.events = POLLOUT; 97 if ((ret = poll(&pfd, 1, timeout)) == 1) { 98 optlen = sizeof(optval); 99 if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 100 &optval, &optlen)) == 0) { 101 errno = optval; 102 ret = optval == 0 ? 0 : -1; 103 } 104 } else if (ret == 0) { 105 errno = ETIMEDOUT; 106 ret = -1; 107 } else 108 ret = -1; 109 } 110 111 if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 112 ret = -1; 113 114 return (ret); 115 } 116 117 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ 118 * Copyright: http://swtch.com/libtask/COPYRIGHT 119 */ 120 121 /* make connection to server */ 122 int 123 netdial(int domain, int proto, char *local, int local_port, char *server, int port, int timeout) 124 { 125 struct addrinfo hints, *local_res, *server_res; 126 int s, saved_errno; 127 128 if (local) { 129 memset(&hints, 0, sizeof(hints)); 130 hints.ai_family = domain; 131 hints.ai_socktype = proto; 132 if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0) 133 return -1; 134 } 135 136 memset(&hints, 0, sizeof(hints)); 137 hints.ai_family = domain; 138 hints.ai_socktype = proto; 139 if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0) 140 return -1; 141 142 s = socket(server_res->ai_family, proto, 0); 143 if (s < 0) { 144 if (local) 145 freeaddrinfo(local_res); 146 freeaddrinfo(server_res); 147 return -1; 148 } 149 150 /* Bind the local address if given a name (with or without --cport) */ 151 if (local) { 152 if (local_port) { 153 struct sockaddr_in *lcladdr; 154 lcladdr = (struct sockaddr_in *)local_res->ai_addr; 155 lcladdr->sin_port = htons(local_port); 156 } 157 158 if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { 159 saved_errno = errno; 160 close(s); 161 freeaddrinfo(local_res); 162 freeaddrinfo(server_res); 163 errno = saved_errno; 164 return -1; 165 } 166 freeaddrinfo(local_res); 167 } 168 /* No local name, but --cport given */ 169 else if (local_port) { 170 size_t addrlen; 171 struct sockaddr_storage lcl; 172 173 /* IPv4 */ 174 if (server_res->ai_family == AF_INET) { 175 struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl; 176 lcladdr->sin_family = AF_INET; 177 lcladdr->sin_port = htons(local_port); 178 lcladdr->sin_addr.s_addr = INADDR_ANY; 179 addrlen = sizeof(struct sockaddr_in); 180 } 181 /* IPv6 */ 182 else if (server_res->ai_family == AF_INET6) { 183 struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl; 184 lcladdr->sin6_family = AF_INET6; 185 lcladdr->sin6_port = htons(local_port); 186 lcladdr->sin6_addr = in6addr_any; 187 addrlen = sizeof(struct sockaddr_in6); 188 } 189 /* Unknown protocol */ 190 else { 191 errno = EAFNOSUPPORT; 192 return -1; 193 } 194 195 if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { 196 saved_errno = errno; 197 close(s); 198 freeaddrinfo(server_res); 199 errno = saved_errno; 200 return -1; 201 } 202 } 203 204 ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); 205 if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { 206 saved_errno = errno; 207 close(s); 208 freeaddrinfo(server_res); 209 errno = saved_errno; 210 return -1; 211 } 212 213 freeaddrinfo(server_res); 214 return s; 215 } 216 217 /***************************************************************/ 218 219 int 220 netannounce(int domain, int proto, char *local, int port) 221 { 222 struct addrinfo hints, *res; 223 char portstr[6]; 224 int s, opt, saved_errno; 225 226 snprintf(portstr, 6, "%d", port); 227 memset(&hints, 0, sizeof(hints)); 228 /* 229 * If binding to the wildcard address with no explicit address 230 * family specified, then force us to get an AF_INET6 socket. On 231 * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family, 232 * and ai_flags containing AI_PASSIVE returns a result structure 233 * with ai_family set to AF_INET, with the result that we create 234 * and bind an IPv4 address wildcard address and by default, we 235 * can't accept IPv6 connections. 236 * 237 * On FreeBSD, under the above circumstances, ai_family in the 238 * result structure is set to AF_INET6. 239 */ 240 if (domain == AF_UNSPEC && !local) { 241 hints.ai_family = AF_INET6; 242 } 243 else { 244 hints.ai_family = domain; 245 } 246 hints.ai_socktype = proto; 247 hints.ai_flags = AI_PASSIVE; 248 if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0) 249 return -1; 250 251 s = socket(res->ai_family, proto, 0); 252 if (s < 0) { 253 freeaddrinfo(res); 254 return -1; 255 } 256 257 opt = 1; 258 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 259 (char *) &opt, sizeof(opt)) < 0) { 260 saved_errno = errno; 261 close(s); 262 freeaddrinfo(res); 263 errno = saved_errno; 264 return -1; 265 } 266 /* 267 * If we got an IPv6 socket, figure out if it should accept IPv4 268 * connections as well. We do that if and only if no address 269 * family was specified explicitly. Note that we can only 270 * do this if the IPV6_V6ONLY socket option is supported. Also, 271 * OpenBSD explicitly omits support for IPv4-mapped addresses, 272 * even though it implements IPV6_V6ONLY. 273 */ 274 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) 275 if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) { 276 if (domain == AF_UNSPEC) 277 opt = 0; 278 else 279 opt = 1; 280 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 281 (char *) &opt, sizeof(opt)) < 0) { 282 saved_errno = errno; 283 close(s); 284 freeaddrinfo(res); 285 errno = saved_errno; 286 return -1; 287 } 288 } 289 #endif /* IPV6_V6ONLY */ 290 291 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 292 saved_errno = errno; 293 close(s); 294 freeaddrinfo(res); 295 errno = saved_errno; 296 return -1; 297 } 298 299 freeaddrinfo(res); 300 301 if (proto == SOCK_STREAM) { 302 if (listen(s, INT_MAX) < 0) { 303 saved_errno = errno; 304 close(s); 305 errno = saved_errno; 306 return -1; 307 } 308 } 309 310 return s; 311 } 312 313 314 /*******************************************************************/ 315 /* reads 'count' bytes from a socket */ 316 /********************************************************************/ 317 318 int 319 Nread(int fd, char *buf, size_t count, int prot) 320 { 321 register ssize_t r; 322 register size_t nleft = count; 323 324 while (nleft > 0) { 325 r = read(fd, buf, nleft); 326 if (r < 0) { 327 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) 328 break; 329 else 330 return NET_HARDERROR; 331 } else if (r == 0) 332 break; 333 334 nleft -= r; 335 buf += r; 336 } 337 return count - nleft; 338 } 339 340 341 /* 342 * N W R I T E 343 */ 344 345 int 346 Nwrite(int fd, const char *buf, size_t count, int prot) 347 { 348 register ssize_t r; 349 register size_t nleft = count; 350 351 while (nleft > 0) { 352 r = write(fd, buf, nleft); 353 if (r < 0) { 354 switch (errno) { 355 case EINTR: 356 case EAGAIN: 357 #if (EAGAIN != EWOULDBLOCK) 358 case EWOULDBLOCK: 359 #endif 360 return count - nleft; 361 362 case ENOBUFS: 363 return NET_SOFTERROR; 364 365 default: 366 return NET_HARDERROR; 367 } 368 } else if (r == 0) 369 return NET_SOFTERROR; 370 nleft -= r; 371 buf += r; 372 } 373 return count; 374 } 375 376 377 int 378 has_sendfile(void) 379 { 380 #if defined(HAVE_SENDFILE) 381 return 1; 382 #else /* HAVE_SENDFILE */ 383 return 0; 384 #endif /* HAVE_SENDFILE */ 385 386 } 387 388 389 /* 390 * N S E N D F I L E 391 */ 392 393 int 394 Nsendfile(int fromfd, int tofd, const char *buf, size_t count) 395 { 396 off_t offset; 397 #if defined(HAVE_SENDFILE) 398 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) 399 off_t sent; 400 #endif 401 register size_t nleft; 402 register ssize_t r; 403 404 nleft = count; 405 while (nleft > 0) { 406 offset = count - nleft; 407 #ifdef linux 408 r = sendfile(tofd, fromfd, &offset, nleft); 409 if (r > 0) 410 nleft -= r; 411 #elif defined(__FreeBSD__) 412 r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0); 413 nleft -= sent; 414 #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 415 sent = nleft; 416 r = sendfile(fromfd, tofd, offset, &sent, NULL, 0); 417 nleft -= sent; 418 #else 419 /* Shouldn't happen. */ 420 r = -1; 421 errno = ENOSYS; 422 #endif 423 if (r < 0) { 424 switch (errno) { 425 case EINTR: 426 case EAGAIN: 427 #if (EAGAIN != EWOULDBLOCK) 428 case EWOULDBLOCK: 429 #endif 430 if (count == nleft) 431 return NET_SOFTERROR; 432 return count - nleft; 433 434 case ENOBUFS: 435 case ENOMEM: 436 return NET_SOFTERROR; 437 438 default: 439 return NET_HARDERROR; 440 } 441 } 442 #ifdef linux 443 else if (r == 0) 444 return NET_SOFTERROR; 445 #endif 446 } 447 return count; 448 #else /* HAVE_SENDFILE */ 449 errno = ENOSYS; /* error if somehow get called without HAVE_SENDFILE */ 450 return NET_HARDERROR; 451 #endif /* HAVE_SENDFILE */ 452 } 453 454 /*************************************************************************/ 455 456 int 457 setnonblocking(int fd, int nonblocking) 458 { 459 int flags, newflags; 460 461 flags = fcntl(fd, F_GETFL, 0); 462 if (flags < 0) { 463 perror("fcntl(F_GETFL)"); 464 return -1; 465 } 466 if (nonblocking) 467 newflags = flags | (int) O_NONBLOCK; 468 else 469 newflags = flags & ~((int) O_NONBLOCK); 470 if (newflags != flags) 471 if (fcntl(fd, F_SETFL, newflags) < 0) { 472 perror("fcntl(F_SETFL)"); 473 return -1; 474 } 475 return 0; 476 } 477 478 /****************************************************************************/ 479 480 int 481 getsockdomain(int sock) 482 { 483 struct sockaddr_storage sa; 484 socklen_t len = sizeof(sa); 485 486 if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) { 487 return -1; 488 } 489 return ((struct sockaddr *) &sa)->sa_family; 490 } 491