xref: /iperf/src/net.c (revision a80368bb)
1 /*
2  * iperf, Copyright (c) 2014, 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)
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 		return count - nleft;
257 
258 		case ENOBUFS:
259 		return NET_SOFTERROR;
260 
261 		default:
262 		return NET_HARDERROR;
263 	    }
264 	} else if (r == 0)
265 	    return NET_SOFTERROR;
266 	nleft -= r;
267 	buf += r;
268     }
269     return count;
270 }
271 
272 
273 int
274 has_sendfile(void)
275 {
276 #if defined(HAVE_SENDFILE)
277     return 1;
278 #else /* HAVE_SENDFILE */
279     return 0;
280 #endif /* HAVE_SENDFILE */
281 
282 }
283 
284 
285 /*
286  *                      N S E N D F I L E
287  */
288 
289 int
290 Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
291 {
292     off_t offset;
293 #if defined(HAVE_SENDFILE)
294 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
295     off_t sent;
296 #endif
297     register size_t nleft;
298     register ssize_t r;
299 
300     nleft = count;
301     while (nleft > 0) {
302 	offset = count - nleft;
303 #ifdef linux
304 	r = sendfile(tofd, fromfd, &offset, nleft);
305 #else
306 #ifdef __FreeBSD__
307 	r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
308 	if (r == 0)
309 	    r = sent;
310 #else
311 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)	/* OS X */
312 	sent = nleft;
313 	r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
314 	if (r == 0)
315 	    r = sent;
316 #else
317 	/* Shouldn't happen. */
318 	r = -1;
319 	errno = ENOSYS;
320 #endif
321 #endif
322 #endif
323 	if (r < 0) {
324 	    switch (errno) {
325 		case EINTR:
326 		case EAGAIN:
327 		if (count == nleft)
328 		    return NET_SOFTERROR;
329 		return count - nleft;
330 
331 		case ENOBUFS:
332 		case ENOMEM:
333 		return NET_SOFTERROR;
334 
335 		default:
336 		return NET_HARDERROR;
337 	    }
338 	} else if (r == 0)
339 	    return NET_SOFTERROR;
340 	nleft -= r;
341     }
342     return count;
343 #else /* HAVE_SENDFILE */
344     errno = ENOSYS;	/* error if somehow get called without HAVE_SENDFILE */
345     return -1;
346 #endif /* HAVE_SENDFILE */
347 }
348 
349 /*************************************************************************/
350 
351 /**
352  * getsock_tcp_mss - Returns the MSS size for TCP
353  *
354  */
355 
356 int
357 getsock_tcp_mss(int inSock)
358 {
359     int             mss = 0;
360 
361     int             rc;
362     socklen_t       len;
363 
364     assert(inSock >= 0); /* print error and exit if this is not true */
365 
366     /* query for mss */
367     len = sizeof(mss);
368     rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
369     if (rc == -1) {
370 	perror("getsockopt TCP_MAXSEG");
371 	return -1;
372     }
373 
374     return mss;
375 }
376 
377 
378 
379 /*************************************************************/
380 
381 /* sets TCP_NODELAY and TCP_MAXSEG if requested */
382 // XXX: This function is not being used.
383 
384 int
385 set_tcp_options(int sock, int no_delay, int mss)
386 {
387     socklen_t len;
388     int rc;
389     int new_mss;
390 
391     if (no_delay == 1) {
392         len = sizeof(no_delay);
393         rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len);
394         if (rc == -1) {
395             perror("setsockopt TCP_NODELAY");
396             return -1;
397         }
398     }
399 #ifdef TCP_MAXSEG
400     if (mss > 0) {
401         len = sizeof(new_mss);
402         assert(sock != -1);
403 
404         /* set */
405         new_mss = mss;
406         len = sizeof(new_mss);
407         rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
408         if (rc == -1) {
409             perror("setsockopt TCP_MAXSEG");
410             return -1;
411         }
412         /* verify results */
413         rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
414         if (rc == -1) {
415             perror("getsockopt TCP_MAXSEG");
416             return -1;
417         }
418         if (new_mss != mss) {
419             perror("setsockopt value mismatch");
420             return -1;
421         }
422     }
423 #endif
424     return 0;
425 }
426 
427 /****************************************************************************/
428 
429 int
430 setnonblocking(int fd, int nonblocking)
431 {
432     int flags, newflags;
433 
434     flags = fcntl(fd, F_GETFL, 0);
435     if (flags < 0) {
436         perror("fcntl(F_GETFL)");
437         return -1;
438     }
439     if (nonblocking)
440 	newflags = flags | (int) O_NONBLOCK;
441     else
442 	newflags = flags & ~((int) O_NONBLOCK);
443     if (newflags != flags)
444 	if (fcntl(fd, F_SETFL, newflags) < 0) {
445 	    perror("fcntl(F_SETFL)");
446 	    return -1;
447 	}
448     return 0;
449 }
450 
451 /****************************************************************************/
452 
453 int
454 getsockdomain(int sock)
455 {
456     struct sockaddr sa;
457     socklen_t len = sizeof(sa);
458 
459     if (getsockname(sock, &sa, &len) < 0)
460 	return -1;
461     return sa.sa_family;
462 }
463