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