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