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