Annotation of embedaddon/iperf/src/net.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * iperf, Copyright (c) 2014-2019, The Regents of the University of
1.1 misho 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>
1.1.1.2 misho 32: #include <arpa/inet.h>
1.1 misho 33: #include <sys/socket.h>
34: #include <sys/types.h>
35: #include <netinet/in.h>
36: #include <assert.h>
37: #include <netdb.h>
38: #include <string.h>
1.1.1.2 misho 39: #include <fcntl.h>
40: #include <limits.h>
1.1 misho 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:
1.1.1.2 misho 59: #ifdef HAVE_POLL_H
60: #include <poll.h>
61: #endif /* HAVE_POLL_H */
62:
1.1.1.3 ! misho 63: #include "iperf.h"
1.1 misho 64: #include "iperf_util.h"
65: #include "net.h"
66: #include "timer.h"
67:
1.1.1.3 ! misho 68: static int nread_read_timeout = 10;
! 69: static int nread_overall_timeout = 30;
! 70:
1.1.1.2 misho 71: /*
72: * Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this
73: * by including "iperf.h", but net.c lives "below" this layer. Clearly the
74: * presence of this declaration is a sign we need to revisit this layering.
75: */
76: extern int gerror;
77:
78: /*
79: * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
80: * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
81: */
82: int
83: timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
84: int timeout)
85: {
86: struct pollfd pfd;
87: socklen_t optlen;
88: int flags, optval;
89: int ret;
90:
91: flags = 0;
92: if (timeout != -1) {
93: flags = fcntl(s, F_GETFL, 0);
94: if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
95: return -1;
96: }
97:
98: if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
99: pfd.fd = s;
100: pfd.events = POLLOUT;
101: if ((ret = poll(&pfd, 1, timeout)) == 1) {
102: optlen = sizeof(optval);
103: if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
104: &optval, &optlen)) == 0) {
105: errno = optval;
106: ret = optval == 0 ? 0 : -1;
107: }
108: } else if (ret == 0) {
109: errno = ETIMEDOUT;
110: ret = -1;
111: } else
112: ret = -1;
113: }
114:
115: if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
116: ret = -1;
117:
118: return (ret);
119: }
120:
1.1 misho 121: /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
122: * Copyright: http://swtch.com/libtask/COPYRIGHT
123: */
124:
1.1.1.3 ! misho 125: /* create a socket */
1.1 misho 126: int
1.1.1.3 ! misho 127: create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out)
1.1 misho 128: {
1.1.1.3 ! misho 129: struct addrinfo hints, *local_res = NULL, *server_res = NULL;
1.1.1.2 misho 130: int s, saved_errno;
1.1.1.3 ! misho 131: char portstr[6];
1.1 misho 132:
133: if (local) {
134: memset(&hints, 0, sizeof(hints));
135: hints.ai_family = domain;
136: hints.ai_socktype = proto;
1.1.1.2 misho 137: if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
1.1 misho 138: return -1;
139: }
140:
141: memset(&hints, 0, sizeof(hints));
142: hints.ai_family = domain;
143: hints.ai_socktype = proto;
1.1.1.3 ! misho 144: snprintf(portstr, sizeof(portstr), "%d", port);
! 145: if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) {
! 146: if (local)
! 147: freeaddrinfo(local_res);
1.1 misho 148: return -1;
1.1.1.3 ! misho 149: }
1.1 misho 150:
151: s = socket(server_res->ai_family, proto, 0);
152: if (s < 0) {
153: if (local)
154: freeaddrinfo(local_res);
155: freeaddrinfo(server_res);
156: return -1;
157: }
158:
1.1.1.3 ! misho 159: if (bind_dev) {
! 160: #if defined(HAVE_SO_BINDTODEVICE)
! 161: if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
! 162: bind_dev, IFNAMSIZ) < 0)
! 163: #endif // HAVE_SO_BINDTODEVICE
! 164: {
! 165: saved_errno = errno;
! 166: close(s);
! 167: freeaddrinfo(local_res);
! 168: freeaddrinfo(server_res);
! 169: errno = saved_errno;
! 170: return -1;
! 171: }
! 172: }
! 173:
1.1.1.2 misho 174: /* Bind the local address if given a name (with or without --cport) */
1.1 misho 175: if (local) {
176: if (local_port) {
177: struct sockaddr_in *lcladdr;
178: lcladdr = (struct sockaddr_in *)local_res->ai_addr;
179: lcladdr->sin_port = htons(local_port);
180: }
181:
182: if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
1.1.1.2 misho 183: saved_errno = errno;
1.1 misho 184: close(s);
185: freeaddrinfo(local_res);
186: freeaddrinfo(server_res);
1.1.1.2 misho 187: errno = saved_errno;
1.1 misho 188: return -1;
189: }
190: freeaddrinfo(local_res);
191: }
1.1.1.2 misho 192: /* No local name, but --cport given */
193: else if (local_port) {
194: size_t addrlen;
195: struct sockaddr_storage lcl;
196:
197: /* IPv4 */
198: if (server_res->ai_family == AF_INET) {
199: struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
200: lcladdr->sin_family = AF_INET;
201: lcladdr->sin_port = htons(local_port);
202: lcladdr->sin_addr.s_addr = INADDR_ANY;
203: addrlen = sizeof(struct sockaddr_in);
204: }
205: /* IPv6 */
206: else if (server_res->ai_family == AF_INET6) {
207: struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
208: lcladdr->sin6_family = AF_INET6;
209: lcladdr->sin6_port = htons(local_port);
210: lcladdr->sin6_addr = in6addr_any;
211: addrlen = sizeof(struct sockaddr_in6);
212: }
213: /* Unknown protocol */
214: else {
1.1.1.3 ! misho 215: close(s);
! 216: freeaddrinfo(server_res);
1.1.1.2 misho 217: errno = EAFNOSUPPORT;
218: return -1;
219: }
220:
221: if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
222: saved_errno = errno;
223: close(s);
224: freeaddrinfo(server_res);
225: errno = saved_errno;
226: return -1;
227: }
228: }
1.1 misho 229:
1.1.1.3 ! misho 230: *server_res_out = server_res;
! 231: return s;
! 232: }
! 233:
! 234: /* make connection to server */
! 235: int
! 236: netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout)
! 237: {
! 238: struct addrinfo *server_res = NULL;
! 239: int s, saved_errno;
! 240:
! 241: s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res);
! 242: if (s < 0) {
! 243: return -1;
! 244: }
! 245:
1.1.1.2 misho 246: if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
247: saved_errno = errno;
1.1 misho 248: close(s);
249: freeaddrinfo(server_res);
1.1.1.2 misho 250: errno = saved_errno;
1.1 misho 251: return -1;
252: }
253:
254: freeaddrinfo(server_res);
255: return s;
256: }
257:
258: /***************************************************************/
259:
260: int
1.1.1.3 ! misho 261: netannounce(int domain, int proto, const char *local, const char *bind_dev, int port)
1.1 misho 262: {
263: struct addrinfo hints, *res;
264: char portstr[6];
1.1.1.2 misho 265: int s, opt, saved_errno;
1.1 misho 266:
267: snprintf(portstr, 6, "%d", port);
268: memset(&hints, 0, sizeof(hints));
1.1.1.3 ! misho 269: /*
1.1 misho 270: * If binding to the wildcard address with no explicit address
271: * family specified, then force us to get an AF_INET6 socket. On
272: * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
273: * and ai_flags containing AI_PASSIVE returns a result structure
274: * with ai_family set to AF_INET, with the result that we create
275: * and bind an IPv4 address wildcard address and by default, we
276: * can't accept IPv6 connections.
277: *
278: * On FreeBSD, under the above circumstances, ai_family in the
279: * result structure is set to AF_INET6.
280: */
281: if (domain == AF_UNSPEC && !local) {
282: hints.ai_family = AF_INET6;
283: }
284: else {
285: hints.ai_family = domain;
286: }
287: hints.ai_socktype = proto;
288: hints.ai_flags = AI_PASSIVE;
1.1.1.2 misho 289: if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
1.1.1.3 ! misho 290: return -1;
1.1 misho 291:
292: s = socket(res->ai_family, proto, 0);
293: if (s < 0) {
294: freeaddrinfo(res);
295: return -1;
296: }
297:
1.1.1.3 ! misho 298: if (bind_dev) {
! 299: #if defined(HAVE_SO_BINDTODEVICE)
! 300: if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
! 301: bind_dev, IFNAMSIZ) < 0)
! 302: #endif // HAVE_SO_BINDTODEVICE
! 303: {
! 304: saved_errno = errno;
! 305: close(s);
! 306: freeaddrinfo(res);
! 307: errno = saved_errno;
! 308: return -1;
! 309: }
! 310: }
! 311:
1.1 misho 312: opt = 1;
1.1.1.3 ! misho 313: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1.1 misho 314: (char *) &opt, sizeof(opt)) < 0) {
1.1.1.2 misho 315: saved_errno = errno;
1.1 misho 316: close(s);
317: freeaddrinfo(res);
1.1.1.2 misho 318: errno = saved_errno;
1.1 misho 319: return -1;
320: }
321: /*
322: * If we got an IPv6 socket, figure out if it should accept IPv4
323: * connections as well. We do that if and only if no address
324: * family was specified explicitly. Note that we can only
325: * do this if the IPV6_V6ONLY socket option is supported. Also,
326: * OpenBSD explicitly omits support for IPv4-mapped addresses,
327: * even though it implements IPV6_V6ONLY.
328: */
329: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
330: if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) {
331: if (domain == AF_UNSPEC)
332: opt = 0;
333: else
334: opt = 1;
1.1.1.3 ! misho 335: if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1.1 misho 336: (char *) &opt, sizeof(opt)) < 0) {
1.1.1.2 misho 337: saved_errno = errno;
1.1 misho 338: close(s);
339: freeaddrinfo(res);
1.1.1.2 misho 340: errno = saved_errno;
1.1 misho 341: return -1;
342: }
343: }
344: #endif /* IPV6_V6ONLY */
345:
346: if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
1.1.1.2 misho 347: saved_errno = errno;
1.1 misho 348: close(s);
349: freeaddrinfo(res);
1.1.1.2 misho 350: errno = saved_errno;
1.1 misho 351: return -1;
352: }
353:
354: freeaddrinfo(res);
1.1.1.3 ! misho 355:
1.1 misho 356: if (proto == SOCK_STREAM) {
1.1.1.2 misho 357: if (listen(s, INT_MAX) < 0) {
358: saved_errno = errno;
1.1 misho 359: close(s);
1.1.1.2 misho 360: errno = saved_errno;
1.1 misho 361: return -1;
362: }
363: }
364:
365: return s;
366: }
367:
368:
369: /*******************************************************************/
370: /* reads 'count' bytes from a socket */
371: /********************************************************************/
372:
373: int
374: Nread(int fd, char *buf, size_t count, int prot)
375: {
376: register ssize_t r;
377: register size_t nleft = count;
1.1.1.3 ! misho 378: struct iperf_time ftimeout = { 0, 0 };
! 379:
! 380: fd_set rfdset;
! 381: struct timeval timeout = { nread_read_timeout, 0 };
! 382:
! 383: /*
! 384: * fd might not be ready for reading on entry. Check for this
! 385: * (with timeout) first.
! 386: *
! 387: * This check could go inside the while() loop below, except we're
! 388: * currently considering whether it might make sense to support a
! 389: * codepath that bypassese this check, for situations where we
! 390: * already know that fd has data on it (for example if we'd gotten
! 391: * to here as the result of a select() call.
! 392: */
! 393: {
! 394: FD_ZERO(&rfdset);
! 395: FD_SET(fd, &rfdset);
! 396: r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
! 397: if (r < 0) {
! 398: return NET_HARDERROR;
! 399: }
! 400: if (r == 0) {
! 401: return 0;
! 402: }
! 403: }
1.1 misho 404:
405: while (nleft > 0) {
406: r = read(fd, buf, nleft);
407: if (r < 0) {
408: if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
409: break;
410: else
411: return NET_HARDERROR;
412: } else if (r == 0)
413: break;
414:
415: nleft -= r;
416: buf += r;
1.1.1.3 ! misho 417:
! 418: /*
! 419: * We need some more bytes but don't want to wait around
! 420: * forever for them. In the case of partial results, we need
! 421: * to be able to read some bytes every nread_timeout seconds.
! 422: */
! 423: if (nleft > 0) {
! 424: struct iperf_time now;
! 425:
! 426: /*
! 427: * Also, we have an approximate upper limit for the total time
! 428: * that a Nread call is supposed to take. We trade off accuracy
! 429: * of this timeout for a hopefully lower performance impact.
! 430: */
! 431: iperf_time_now(&now);
! 432: if (ftimeout.secs == 0) {
! 433: ftimeout = now;
! 434: iperf_time_add_usecs(&ftimeout, nread_overall_timeout * 1000000L);
! 435: }
! 436: if (iperf_time_compare(&ftimeout, &now) < 0) {
! 437: break;
! 438: }
! 439:
! 440: FD_ZERO(&rfdset);
! 441: FD_SET(fd, &rfdset);
! 442: r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
! 443: if (r < 0) {
! 444: return NET_HARDERROR;
! 445: }
! 446: if (r == 0) {
! 447: break;
! 448: }
! 449: }
1.1 misho 450: }
451: return count - nleft;
452: }
453:
454:
455: /*
456: * N W R I T E
457: */
458:
459: int
460: Nwrite(int fd, const char *buf, size_t count, int prot)
461: {
462: register ssize_t r;
463: register size_t nleft = count;
464:
465: while (nleft > 0) {
466: r = write(fd, buf, nleft);
467: if (r < 0) {
468: switch (errno) {
469: case EINTR:
470: case EAGAIN:
471: #if (EAGAIN != EWOULDBLOCK)
472: case EWOULDBLOCK:
473: #endif
474: return count - nleft;
475:
476: case ENOBUFS:
477: return NET_SOFTERROR;
478:
479: default:
480: return NET_HARDERROR;
481: }
482: } else if (r == 0)
483: return NET_SOFTERROR;
484: nleft -= r;
485: buf += r;
486: }
487: return count;
488: }
489:
490:
491: int
492: has_sendfile(void)
493: {
494: #if defined(HAVE_SENDFILE)
495: return 1;
496: #else /* HAVE_SENDFILE */
497: return 0;
498: #endif /* HAVE_SENDFILE */
499:
500: }
501:
502:
503: /*
504: * N S E N D F I L E
505: */
506:
507: int
508: Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
509: {
510: #if defined(HAVE_SENDFILE)
1.1.1.3 ! misho 511: off_t offset;
1.1 misho 512: #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
513: off_t sent;
514: #endif
515: register size_t nleft;
516: register ssize_t r;
517:
518: nleft = count;
519: while (nleft > 0) {
520: offset = count - nleft;
521: #ifdef linux
522: r = sendfile(tofd, fromfd, &offset, nleft);
523: if (r > 0)
524: nleft -= r;
525: #elif defined(__FreeBSD__)
526: r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
527: nleft -= sent;
528: #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */
529: sent = nleft;
530: r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
531: nleft -= sent;
532: #else
533: /* Shouldn't happen. */
534: r = -1;
535: errno = ENOSYS;
536: #endif
537: if (r < 0) {
538: switch (errno) {
539: case EINTR:
540: case EAGAIN:
541: #if (EAGAIN != EWOULDBLOCK)
542: case EWOULDBLOCK:
543: #endif
544: if (count == nleft)
545: return NET_SOFTERROR;
546: return count - nleft;
547:
548: case ENOBUFS:
549: case ENOMEM:
550: return NET_SOFTERROR;
551:
552: default:
553: return NET_HARDERROR;
554: }
555: }
556: #ifdef linux
557: else if (r == 0)
558: return NET_SOFTERROR;
559: #endif
560: }
561: return count;
562: #else /* HAVE_SENDFILE */
563: errno = ENOSYS; /* error if somehow get called without HAVE_SENDFILE */
564: return NET_HARDERROR;
565: #endif /* HAVE_SENDFILE */
566: }
567:
568: /*************************************************************************/
569:
570: int
571: setnonblocking(int fd, int nonblocking)
572: {
573: int flags, newflags;
574:
575: flags = fcntl(fd, F_GETFL, 0);
576: if (flags < 0) {
577: perror("fcntl(F_GETFL)");
578: return -1;
579: }
580: if (nonblocking)
581: newflags = flags | (int) O_NONBLOCK;
582: else
583: newflags = flags & ~((int) O_NONBLOCK);
584: if (newflags != flags)
585: if (fcntl(fd, F_SETFL, newflags) < 0) {
586: perror("fcntl(F_SETFL)");
587: return -1;
588: }
589: return 0;
590: }
591:
592: /****************************************************************************/
593:
594: int
595: getsockdomain(int sock)
596: {
597: struct sockaddr_storage sa;
598: socklen_t len = sizeof(sa);
599:
600: if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) {
601: return -1;
602: }
603: return ((struct sockaddr *) &sa)->sa_family;
604: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>