Annotation of embedaddon/iperf/src/net.c, revision 1.1
1.1 ! misho 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 TTD@lbl.gov.
! 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>