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