• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 <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_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 <ericj@monkey.org>
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 /* make connection to server */
123 int
netdial(int domain,int proto,const char * local,int local_port,const char * server,int port,int timeout)124 netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout)
125 {
126     struct addrinfo hints, *local_res, *server_res;
127     int s, saved_errno;
128 
129     if (local) {
130         memset(&hints, 0, sizeof(hints));
131         hints.ai_family = domain;
132         hints.ai_socktype = proto;
133         if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
134             return -1;
135     }
136 
137     memset(&hints, 0, sizeof(hints));
138     hints.ai_family = domain;
139     hints.ai_socktype = proto;
140     if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0)
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 
151     /* Bind the local address if given a name (with or without --cport) */
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) {
160 	    saved_errno = errno;
161 	    close(s);
162 	    freeaddrinfo(local_res);
163 	    freeaddrinfo(server_res);
164 	    errno = saved_errno;
165             return -1;
166 	}
167         freeaddrinfo(local_res);
168     }
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     }
204 
205     ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);
206     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
207 	saved_errno = errno;
208 	close(s);
209 	freeaddrinfo(server_res);
210 	errno = saved_errno;
211         return -1;
212     }
213 
214     freeaddrinfo(server_res);
215     return s;
216 }
217 
218 /***************************************************************/
219 
220 int
netannounce(int domain,int proto,const char * local,int port)221 netannounce(int domain, int proto, const char *local, int port)
222 {
223     struct addrinfo hints, *res;
224     char portstr[6];
225     int s, opt, saved_errno;
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;
249     if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
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) {
261 	saved_errno = errno;
262 	close(s);
263 	freeaddrinfo(res);
264 	errno = saved_errno;
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) {
283 	    saved_errno = errno;
284 	    close(s);
285 	    freeaddrinfo(res);
286 	    errno = saved_errno;
287 	    return -1;
288 	}
289     }
290 #endif /* IPV6_V6ONLY */
291 
292     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
293         saved_errno = errno;
294         close(s);
295 	freeaddrinfo(res);
296         errno = saved_errno;
297         return -1;
298     }
299 
300     freeaddrinfo(res);
301 
302     if (proto == SOCK_STREAM) {
303         if (listen(s, INT_MAX) < 0) {
304 	    saved_errno = errno;
305 	    close(s);
306 	    errno = saved_errno;
307             return -1;
308         }
309     }
310 
311     return s;
312 }
313 
314 
315 /*******************************************************************/
316 /* reads 'count' bytes from a socket  */
317 /********************************************************************/
318 
319 int
Nread(int fd,char * buf,size_t count,int prot)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
Nwrite(int fd,const char * buf,size_t count,int prot)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
has_sendfile(void)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
Nsendfile(int fromfd,int tofd,const char * buf,size_t count)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
setnonblocking(int fd,int nonblocking)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
getsockdomain(int sock)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 }
492