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