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