Annotation of embedaddon/iperf/src/net.c, revision 1.1.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>