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