xref: /iperf/src/net.c (revision d88f4cec)
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;
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 	    close(s);
152 	    freeaddrinfo(local_res);
153 	    freeaddrinfo(server_res);
154             return -1;
155 	}
156         freeaddrinfo(local_res);
157     }
158 
159     ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);
160     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
161 	close(s);
162 	freeaddrinfo(server_res);
163         return -1;
164     }
165 
166     freeaddrinfo(server_res);
167     return s;
168 }
169 
170 /***************************************************************/
171 
172 int
173 netannounce(int domain, int proto, char *local, int port)
174 {
175     struct addrinfo hints, *res;
176     char portstr[6];
177     int s, opt;
178 
179     snprintf(portstr, 6, "%d", port);
180     memset(&hints, 0, sizeof(hints));
181     /*
182      * If binding to the wildcard address with no explicit address
183      * family specified, then force us to get an AF_INET6 socket.  On
184      * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
185      * and ai_flags containing AI_PASSIVE returns a result structure
186      * with ai_family set to AF_INET, with the result that we create
187      * and bind an IPv4 address wildcard address and by default, we
188      * can't accept IPv6 connections.
189      *
190      * On FreeBSD, under the above circumstances, ai_family in the
191      * result structure is set to AF_INET6.
192      */
193     if (domain == AF_UNSPEC && !local) {
194 	hints.ai_family = AF_INET6;
195     }
196     else {
197 	hints.ai_family = domain;
198     }
199     hints.ai_socktype = proto;
200     hints.ai_flags = AI_PASSIVE;
201     if (getaddrinfo(local, portstr, &hints, &res) != 0)
202         return -1;
203 
204     s = socket(res->ai_family, proto, 0);
205     if (s < 0) {
206 	freeaddrinfo(res);
207         return -1;
208     }
209 
210     opt = 1;
211     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
212 		   (char *) &opt, sizeof(opt)) < 0) {
213 	close(s);
214 	freeaddrinfo(res);
215 	return -1;
216     }
217     /*
218      * If we got an IPv6 socket, figure out if it should accept IPv4
219      * connections as well.  We do that if and only if no address
220      * family was specified explicitly.  Note that we can only
221      * do this if the IPV6_V6ONLY socket option is supported.  Also,
222      * OpenBSD explicitly omits support for IPv4-mapped addresses,
223      * even though it implements IPV6_V6ONLY.
224      */
225 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
226     if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) {
227 	if (domain == AF_UNSPEC)
228 	    opt = 0;
229 	else
230 	    opt = 1;
231 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
232 		       (char *) &opt, sizeof(opt)) < 0) {
233 	    close(s);
234 	    freeaddrinfo(res);
235 	    return -1;
236 	}
237     }
238 #endif /* IPV6_V6ONLY */
239 
240     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
241         close(s);
242 	freeaddrinfo(res);
243         return -1;
244     }
245 
246     freeaddrinfo(res);
247 
248     if (proto == SOCK_STREAM) {
249         if (listen(s, 5) < 0) {
250 	    close(s);
251             return -1;
252         }
253     }
254 
255     return s;
256 }
257 
258 
259 /*******************************************************************/
260 /* reads 'count' bytes from a socket  */
261 /********************************************************************/
262 
263 int
264 Nread(int fd, char *buf, size_t count, int prot)
265 {
266     register ssize_t r;
267     register size_t nleft = count;
268 
269     while (nleft > 0) {
270         r = read(fd, buf, nleft);
271         if (r < 0) {
272             if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
273                 break;
274             else
275                 return NET_HARDERROR;
276         } else if (r == 0)
277             break;
278 
279         nleft -= r;
280         buf += r;
281     }
282     return count - nleft;
283 }
284 
285 
286 /*
287  *                      N W R I T E
288  */
289 
290 int
291 Nwrite(int fd, const char *buf, size_t count, int prot)
292 {
293     register ssize_t r;
294     register size_t nleft = count;
295 
296     while (nleft > 0) {
297 	r = write(fd, buf, nleft);
298 	if (r < 0) {
299 	    switch (errno) {
300 		case EINTR:
301 		case EAGAIN:
302 #if (EAGAIN != EWOULDBLOCK)
303 		case EWOULDBLOCK:
304 #endif
305 		return count - nleft;
306 
307 		case ENOBUFS:
308 		return NET_SOFTERROR;
309 
310 		default:
311 		return NET_HARDERROR;
312 	    }
313 	} else if (r == 0)
314 	    return NET_SOFTERROR;
315 	nleft -= r;
316 	buf += r;
317     }
318     return count;
319 }
320 
321 
322 int
323 has_sendfile(void)
324 {
325 #if defined(HAVE_SENDFILE)
326     return 1;
327 #else /* HAVE_SENDFILE */
328     return 0;
329 #endif /* HAVE_SENDFILE */
330 
331 }
332 
333 
334 /*
335  *                      N S E N D F I L E
336  */
337 
338 int
339 Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
340 {
341     off_t offset;
342 #if defined(HAVE_SENDFILE)
343 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
344     off_t sent;
345 #endif
346     register size_t nleft;
347     register ssize_t r;
348 
349     nleft = count;
350     while (nleft > 0) {
351 	offset = count - nleft;
352 #ifdef linux
353 	r = sendfile(tofd, fromfd, &offset, nleft);
354 	if (r > 0)
355 	    nleft -= r;
356 #elif defined(__FreeBSD__)
357 	r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
358 	nleft -= sent;
359 #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)	/* OS X */
360 	sent = nleft;
361 	r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
362 	nleft -= sent;
363 #else
364 	/* Shouldn't happen. */
365 	r = -1;
366 	errno = ENOSYS;
367 #endif
368 	if (r < 0) {
369 	    switch (errno) {
370 		case EINTR:
371 		case EAGAIN:
372 #if (EAGAIN != EWOULDBLOCK)
373 		case EWOULDBLOCK:
374 #endif
375 		if (count == nleft)
376 		    return NET_SOFTERROR;
377 		return count - nleft;
378 
379 		case ENOBUFS:
380 		case ENOMEM:
381 		return NET_SOFTERROR;
382 
383 		default:
384 		return NET_HARDERROR;
385 	    }
386 	}
387 #ifdef linux
388 	else if (r == 0)
389 	    return NET_SOFTERROR;
390 #endif
391     }
392     return count;
393 #else /* HAVE_SENDFILE */
394     errno = ENOSYS;	/* error if somehow get called without HAVE_SENDFILE */
395     return NET_HARDERROR;
396 #endif /* HAVE_SENDFILE */
397 }
398 
399 /*************************************************************************/
400 
401 /**
402  * getsock_tcp_mss - Returns the MSS size for TCP
403  *
404  */
405 
406 int
407 getsock_tcp_mss(int inSock)
408 {
409     int             mss = 0;
410 
411     int             rc;
412     socklen_t       len;
413 
414     assert(inSock >= 0); /* print error and exit if this is not true */
415 
416     /* query for mss */
417     len = sizeof(mss);
418     rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
419     if (rc == -1) {
420 	perror("getsockopt TCP_MAXSEG");
421 	return -1;
422     }
423 
424     return mss;
425 }
426 
427 
428 
429 /*************************************************************/
430 
431 /* sets TCP_NODELAY and TCP_MAXSEG if requested */
432 // XXX: This function is not being used.
433 
434 int
435 set_tcp_options(int sock, int no_delay, int mss)
436 {
437     socklen_t len;
438     int rc;
439     int new_mss;
440 
441     if (no_delay == 1) {
442         len = sizeof(no_delay);
443         rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len);
444         if (rc == -1) {
445             perror("setsockopt TCP_NODELAY");
446             return -1;
447         }
448     }
449 #ifdef TCP_MAXSEG
450     if (mss > 0) {
451         len = sizeof(new_mss);
452         assert(sock != -1);
453 
454         /* set */
455         new_mss = mss;
456         len = sizeof(new_mss);
457         rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
458         if (rc == -1) {
459             perror("setsockopt TCP_MAXSEG");
460             return -1;
461         }
462         /* verify results */
463         rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
464         if (rc == -1) {
465             perror("getsockopt TCP_MAXSEG");
466             return -1;
467         }
468         if (new_mss != mss) {
469             perror("setsockopt value mismatch");
470             return -1;
471         }
472     }
473 #endif
474     return 0;
475 }
476 
477 /****************************************************************************/
478 
479 int
480 setnonblocking(int fd, int nonblocking)
481 {
482     int flags, newflags;
483 
484     flags = fcntl(fd, F_GETFL, 0);
485     if (flags < 0) {
486         perror("fcntl(F_GETFL)");
487         return -1;
488     }
489     if (nonblocking)
490 	newflags = flags | (int) O_NONBLOCK;
491     else
492 	newflags = flags & ~((int) O_NONBLOCK);
493     if (newflags != flags)
494 	if (fcntl(fd, F_SETFL, newflags) < 0) {
495 	    perror("fcntl(F_SETFL)");
496 	    return -1;
497 	}
498     return 0;
499 }
500 
501 /****************************************************************************/
502 
503 int
504 getsockdomain(int sock)
505 {
506     struct sockaddr_storage sa;
507     socklen_t len = sizeof(sa);
508 
509     if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) {
510         return -1;
511     }
512     return ((struct sockaddr *) &sa)->sa_family;
513 }
514