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