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