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