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