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