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