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