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