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