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