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 [email protected]. 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 <arpa/inet.h> 33 #include <sys/socket.h> 34 #include <sys/types.h> 35 #include <netinet/in.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.h" 64 #include "iperf_util.h" 65 #include "net.h" 66 #include "timer.h" 67 68 /* 69 * Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this 70 * by including "iperf.h", but net.c lives "below" this layer. Clearly the 71 * presence of this declaration is a sign we need to revisit this layering. 72 */ 73 extern int gerror; 74 75 /* 76 * timeout_connect adapted from netcat, via OpenBSD and FreeBSD 77 * Copyright (c) 2001 Eric Jackson <[email protected]> 78 */ 79 int 80 timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, 81 int timeout) 82 { 83 struct pollfd pfd; 84 socklen_t optlen; 85 int flags, optval; 86 int ret; 87 88 flags = 0; 89 if (timeout != -1) { 90 flags = fcntl(s, F_GETFL, 0); 91 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 92 return -1; 93 } 94 95 if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 96 pfd.fd = s; 97 pfd.events = POLLOUT; 98 if ((ret = poll(&pfd, 1, timeout)) == 1) { 99 optlen = sizeof(optval); 100 if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 101 &optval, &optlen)) == 0) { 102 errno = optval; 103 ret = optval == 0 ? 0 : -1; 104 } 105 } else if (ret == 0) { 106 errno = ETIMEDOUT; 107 ret = -1; 108 } else 109 ret = -1; 110 } 111 112 if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 113 ret = -1; 114 115 return (ret); 116 } 117 118 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ 119 * Copyright: http://swtch.com/libtask/COPYRIGHT 120 */ 121 122 /* create a socket */ 123 int 124 create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out) 125 { 126 struct addrinfo hints, *local_res = NULL, *server_res = NULL; 127 int s, saved_errno; 128 char portstr[6]; 129 130 if (local) { 131 memset(&hints, 0, sizeof(hints)); 132 hints.ai_family = domain; 133 hints.ai_socktype = proto; 134 if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0) 135 return -1; 136 } 137 138 memset(&hints, 0, sizeof(hints)); 139 hints.ai_family = domain; 140 hints.ai_socktype = proto; 141 snprintf(portstr, sizeof(portstr), "%d", port); 142 if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) { 143 if (local) 144 freeaddrinfo(local_res); 145 return -1; 146 } 147 148 s = socket(server_res->ai_family, proto, 0); 149 if (s < 0) { 150 if (local) 151 freeaddrinfo(local_res); 152 freeaddrinfo(server_res); 153 return -1; 154 } 155 156 if (bind_dev) { 157 #if defined(HAVE_SO_BINDTODEVICE) 158 if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, 159 bind_dev, IFNAMSIZ) < 0) 160 #endif // HAVE_SO_BINDTODEVICE 161 { 162 saved_errno = errno; 163 close(s); 164 freeaddrinfo(local_res); 165 freeaddrinfo(server_res); 166 errno = saved_errno; 167 return -1; 168 } 169 } 170 171 /* Bind the local address if given a name (with or without --cport) */ 172 if (local) { 173 if (local_port) { 174 struct sockaddr_in *lcladdr; 175 lcladdr = (struct sockaddr_in *)local_res->ai_addr; 176 lcladdr->sin_port = htons(local_port); 177 } 178 179 if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { 180 saved_errno = errno; 181 close(s); 182 freeaddrinfo(local_res); 183 freeaddrinfo(server_res); 184 errno = saved_errno; 185 return -1; 186 } 187 freeaddrinfo(local_res); 188 } 189 /* No local name, but --cport given */ 190 else if (local_port) { 191 size_t addrlen; 192 struct sockaddr_storage lcl; 193 194 /* IPv4 */ 195 if (server_res->ai_family == AF_INET) { 196 struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl; 197 lcladdr->sin_family = AF_INET; 198 lcladdr->sin_port = htons(local_port); 199 lcladdr->sin_addr.s_addr = INADDR_ANY; 200 addrlen = sizeof(struct sockaddr_in); 201 } 202 /* IPv6 */ 203 else if (server_res->ai_family == AF_INET6) { 204 struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl; 205 lcladdr->sin6_family = AF_INET6; 206 lcladdr->sin6_port = htons(local_port); 207 lcladdr->sin6_addr = in6addr_any; 208 addrlen = sizeof(struct sockaddr_in6); 209 } 210 /* Unknown protocol */ 211 else { 212 close(s); 213 freeaddrinfo(server_res); 214 errno = EAFNOSUPPORT; 215 return -1; 216 } 217 218 if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { 219 saved_errno = errno; 220 close(s); 221 freeaddrinfo(server_res); 222 errno = saved_errno; 223 return -1; 224 } 225 } 226 227 *server_res_out = server_res; 228 return s; 229 } 230 231 /* make connection to server */ 232 int 233 netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout) 234 { 235 struct addrinfo *server_res = NULL; 236 int s, saved_errno; 237 238 s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res); 239 if (s < 0) { 240 return -1; 241 } 242 243 if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { 244 saved_errno = errno; 245 close(s); 246 freeaddrinfo(server_res); 247 errno = saved_errno; 248 return -1; 249 } 250 251 freeaddrinfo(server_res); 252 return s; 253 } 254 255 /***************************************************************/ 256 257 int 258 netannounce(int domain, int proto, const char *local, const char *bind_dev, int port) 259 { 260 struct addrinfo hints, *res; 261 char portstr[6]; 262 int s, opt, saved_errno; 263 264 snprintf(portstr, 6, "%d", port); 265 memset(&hints, 0, sizeof(hints)); 266 /* 267 * If binding to the wildcard address with no explicit address 268 * family specified, then force us to get an AF_INET6 socket. On 269 * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family, 270 * and ai_flags containing AI_PASSIVE returns a result structure 271 * with ai_family set to AF_INET, with the result that we create 272 * and bind an IPv4 address wildcard address and by default, we 273 * can't accept IPv6 connections. 274 * 275 * On FreeBSD, under the above circumstances, ai_family in the 276 * result structure is set to AF_INET6. 277 */ 278 if (domain == AF_UNSPEC && !local) { 279 hints.ai_family = AF_INET6; 280 } 281 else { 282 hints.ai_family = domain; 283 } 284 hints.ai_socktype = proto; 285 hints.ai_flags = AI_PASSIVE; 286 if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0) 287 return -1; 288 289 s = socket(res->ai_family, proto, 0); 290 if (s < 0) { 291 freeaddrinfo(res); 292 return -1; 293 } 294 295 if (bind_dev) { 296 #if defined(HAVE_SO_BINDTODEVICE) 297 if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, 298 bind_dev, IFNAMSIZ) < 0) 299 #endif // HAVE_SO_BINDTODEVICE 300 { 301 saved_errno = errno; 302 close(s); 303 freeaddrinfo(res); 304 errno = saved_errno; 305 return -1; 306 } 307 } 308 309 opt = 1; 310 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 311 (char *) &opt, sizeof(opt)) < 0) { 312 saved_errno = errno; 313 close(s); 314 freeaddrinfo(res); 315 errno = saved_errno; 316 return -1; 317 } 318 /* 319 * If we got an IPv6 socket, figure out if it should accept IPv4 320 * connections as well. We do that if and only if no address 321 * family was specified explicitly. Note that we can only 322 * do this if the IPV6_V6ONLY socket option is supported. Also, 323 * OpenBSD explicitly omits support for IPv4-mapped addresses, 324 * even though it implements IPV6_V6ONLY. 325 */ 326 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) 327 if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) { 328 if (domain == AF_UNSPEC) 329 opt = 0; 330 else 331 opt = 1; 332 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 333 (char *) &opt, sizeof(opt)) < 0) { 334 saved_errno = errno; 335 close(s); 336 freeaddrinfo(res); 337 errno = saved_errno; 338 return -1; 339 } 340 } 341 #endif /* IPV6_V6ONLY */ 342 343 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 344 saved_errno = errno; 345 close(s); 346 freeaddrinfo(res); 347 errno = saved_errno; 348 return -1; 349 } 350 351 freeaddrinfo(res); 352 353 if (proto == SOCK_STREAM) { 354 if (listen(s, INT_MAX) < 0) { 355 saved_errno = errno; 356 close(s); 357 errno = saved_errno; 358 return -1; 359 } 360 } 361 362 return s; 363 } 364 365 366 /*******************************************************************/ 367 /* reads 'count' bytes from a socket */ 368 /********************************************************************/ 369 370 int 371 Nread(int fd, char *buf, size_t count, int prot) 372 { 373 register ssize_t r; 374 register size_t nleft = count; 375 376 while (nleft > 0) { 377 r = read(fd, buf, nleft); 378 if (r < 0) { 379 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) 380 break; 381 else 382 return NET_HARDERROR; 383 } else if (r == 0) 384 break; 385 386 nleft -= r; 387 buf += r; 388 } 389 return count - nleft; 390 } 391 392 393 /* 394 * N W R I T E 395 */ 396 397 int 398 Nwrite(int fd, const char *buf, size_t count, int prot) 399 { 400 register ssize_t r; 401 register size_t nleft = count; 402 403 while (nleft > 0) { 404 r = write(fd, buf, nleft); 405 if (r < 0) { 406 switch (errno) { 407 case EINTR: 408 case EAGAIN: 409 #if (EAGAIN != EWOULDBLOCK) 410 case EWOULDBLOCK: 411 #endif 412 return count - nleft; 413 414 case ENOBUFS: 415 return NET_SOFTERROR; 416 417 default: 418 return NET_HARDERROR; 419 } 420 } else if (r == 0) 421 return NET_SOFTERROR; 422 nleft -= r; 423 buf += r; 424 } 425 return count; 426 } 427 428 429 int 430 has_sendfile(void) 431 { 432 #if defined(HAVE_SENDFILE) 433 return 1; 434 #else /* HAVE_SENDFILE */ 435 return 0; 436 #endif /* HAVE_SENDFILE */ 437 438 } 439 440 441 /* 442 * N S E N D F I L E 443 */ 444 445 int 446 Nsendfile(int fromfd, int tofd, const char *buf, size_t count) 447 { 448 off_t offset; 449 #if defined(HAVE_SENDFILE) 450 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) 451 off_t sent; 452 #endif 453 register size_t nleft; 454 register ssize_t r; 455 456 nleft = count; 457 while (nleft > 0) { 458 offset = count - nleft; 459 #ifdef linux 460 r = sendfile(tofd, fromfd, &offset, nleft); 461 if (r > 0) 462 nleft -= r; 463 #elif defined(__FreeBSD__) 464 r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0); 465 nleft -= sent; 466 #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 467 sent = nleft; 468 r = sendfile(fromfd, tofd, offset, &sent, NULL, 0); 469 nleft -= sent; 470 #else 471 /* Shouldn't happen. */ 472 r = -1; 473 errno = ENOSYS; 474 #endif 475 if (r < 0) { 476 switch (errno) { 477 case EINTR: 478 case EAGAIN: 479 #if (EAGAIN != EWOULDBLOCK) 480 case EWOULDBLOCK: 481 #endif 482 if (count == nleft) 483 return NET_SOFTERROR; 484 return count - nleft; 485 486 case ENOBUFS: 487 case ENOMEM: 488 return NET_SOFTERROR; 489 490 default: 491 return NET_HARDERROR; 492 } 493 } 494 #ifdef linux 495 else if (r == 0) 496 return NET_SOFTERROR; 497 #endif 498 } 499 return count; 500 #else /* HAVE_SENDFILE */ 501 errno = ENOSYS; /* error if somehow get called without HAVE_SENDFILE */ 502 return NET_HARDERROR; 503 #endif /* HAVE_SENDFILE */ 504 } 505 506 /*************************************************************************/ 507 508 int 509 setnonblocking(int fd, int nonblocking) 510 { 511 int flags, newflags; 512 513 flags = fcntl(fd, F_GETFL, 0); 514 if (flags < 0) { 515 perror("fcntl(F_GETFL)"); 516 return -1; 517 } 518 if (nonblocking) 519 newflags = flags | (int) O_NONBLOCK; 520 else 521 newflags = flags & ~((int) O_NONBLOCK); 522 if (newflags != flags) 523 if (fcntl(fd, F_SETFL, newflags) < 0) { 524 perror("fcntl(F_SETFL)"); 525 return -1; 526 } 527 return 0; 528 } 529 530 /****************************************************************************/ 531 532 int 533 getsockdomain(int sock) 534 { 535 struct sockaddr_storage sa; 536 socklen_t len = sizeof(sa); 537 538 if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) { 539 return -1; 540 } 541 return ((struct sockaddr *) &sa)->sa_family; 542 } 543