xref: /iperf/src/net.c (revision 6edfd8d6)
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     hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain);
111     hints.ai_socktype = proto;
112     hints.ai_flags = AI_PASSIVE;
113     if (getaddrinfo(local, portstr, &hints, &res) != 0)
114         return -1;
115 
116     s = socket(res->ai_family, proto, 0);
117     if (s < 0) {
118 	freeaddrinfo(res);
119         return -1;
120     }
121 
122     opt = 1;
123     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
124 		   (char *) &opt, sizeof(opt)) < 0) {
125 	close(s);
126 	freeaddrinfo(res);
127 	return -1;
128     }
129     if (domain == AF_UNSPEC || domain == AF_INET6) {
130 	if (domain == AF_UNSPEC)
131 	    opt = 0;
132 	else if (domain == AF_INET6)
133 	    opt = 1;
134 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
135 		       (char *) &opt, sizeof(opt)) < 0) {
136 	    close(s);
137 	    freeaddrinfo(res);
138 	    return -1;
139 	}
140     }
141 
142     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
143         close(s);
144 	freeaddrinfo(res);
145         return -1;
146     }
147 
148     freeaddrinfo(res);
149 
150     if (proto == SOCK_STREAM) {
151         if (listen(s, 5) < 0) {
152 	    close(s);
153             return -1;
154         }
155     }
156 
157     return s;
158 }
159 
160 
161 /*******************************************************************/
162 /* reads 'count' bytes from a socket  */
163 /********************************************************************/
164 
165 int
166 Nread(int fd, char *buf, size_t count, int prot)
167 {
168     register ssize_t r;
169     register size_t nleft = count;
170 
171     while (nleft > 0) {
172         r = read(fd, buf, nleft);
173         if (r < 0) {
174             if (errno == EINTR || errno == EAGAIN)
175                 break;
176             else
177                 return NET_HARDERROR;
178         } else if (r == 0)
179             break;
180 
181         nleft -= r;
182         buf += r;
183     }
184     return count - nleft;
185 }
186 
187 
188 /*
189  *                      N W R I T E
190  */
191 
192 int
193 Nwrite(int fd, const 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 = write(fd, buf, nleft);
200 	if (r < 0) {
201 	    switch (errno) {
202 		case EINTR:
203 		case EAGAIN:
204 		return count - nleft;
205 
206 		case ENOBUFS:
207 		return NET_SOFTERROR;
208 
209 		default:
210 		return NET_HARDERROR;
211 	    }
212 	} else if (r == 0)
213 	    return NET_SOFTERROR;
214 	nleft -= r;
215 	buf += r;
216     }
217     return count;
218 }
219 
220 
221 int
222 has_sendfile(void)
223 {
224 #if defined(HAS_SENDFILE)
225     return 1;
226 #else /* HAS_SENDFILE */
227     return 0;
228 #endif /* HAS_SENDFILE */
229 
230 }
231 
232 
233 /*
234  *                      N S E N D F I L E
235  */
236 
237 int
238 Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
239 {
240     off_t offset;
241 #if defined(HAVE_SENDFILE)
242 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
243     off_t sent;
244 #endif
245     register size_t nleft;
246     register ssize_t r;
247 
248     nleft = count;
249     while (nleft > 0) {
250 	offset = count - nleft;
251 #ifdef linux
252 	r = sendfile(tofd, fromfd, &offset, nleft);
253 #else
254 #ifdef __FreeBSD__
255 	r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
256 	if (r == 0)
257 	    r = sent;
258 #else
259 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)	/* OS X */
260 	sent = nleft;
261 	r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
262 	if (r == 0)
263 	    r = sent;
264 #else
265 	/* Shouldn't happen. */
266 	r = -1;
267 	errno = ENOSYS;
268 #endif
269 #endif
270 #endif
271 	if (r < 0) {
272 	    switch (errno) {
273 		case EINTR:
274 		case EAGAIN:
275 		return count - nleft;
276 
277 		case ENOBUFS:
278 		case ENOMEM:
279 		return NET_SOFTERROR;
280 
281 		default:
282 		return NET_HARDERROR;
283 	    }
284 	} else if (r == 0)
285 	    return NET_SOFTERROR;
286 	nleft -= r;
287     }
288     return count;
289 #else /* HAVE_SENDFILE */
290     errno = ENOSYS;	/* error if somehow get called without HAVE_SENDFILE */
291     return -1;
292 #endif /* HAVE_SENDFILE */
293 }
294 
295 /*************************************************************************/
296 
297 /**
298  * getsock_tcp_mss - Returns the MSS size for TCP
299  *
300  */
301 
302 int
303 getsock_tcp_mss(int inSock)
304 {
305     int             mss = 0;
306 
307     int             rc;
308     socklen_t       len;
309 
310     assert(inSock >= 0); /* print error and exit if this is not true */
311 
312     /* query for mss */
313     len = sizeof(mss);
314     rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
315     if (rc == -1) {
316 	perror("getsockopt TCP_MAXSEG");
317 	return -1;
318     }
319 
320     return mss;
321 }
322 
323 
324 
325 /*************************************************************/
326 
327 /* sets TCP_NODELAY and TCP_MAXSEG if requested */
328 // XXX: This function is not being used.
329 
330 int
331 set_tcp_options(int sock, int no_delay, int mss)
332 {
333     socklen_t len;
334     int rc;
335     int new_mss;
336 
337     if (no_delay == 1) {
338         len = sizeof(no_delay);
339         rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len);
340         if (rc == -1) {
341             perror("setsockopt TCP_NODELAY");
342             return -1;
343         }
344     }
345 #ifdef TCP_MAXSEG
346     if (mss > 0) {
347         len = sizeof(new_mss);
348         assert(sock != -1);
349 
350         /* set */
351         new_mss = mss;
352         len = sizeof(new_mss);
353         rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
354         if (rc == -1) {
355             perror("setsockopt TCP_MAXSEG");
356             return -1;
357         }
358         /* verify results */
359         rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
360         if (rc == -1) {
361             perror("getsockopt TCP_MAXSEG");
362             return -1;
363         }
364         if (new_mss != mss) {
365             perror("setsockopt value mismatch");
366             return -1;
367         }
368     }
369 #endif
370     return 0;
371 }
372 
373 /****************************************************************************/
374 
375 int
376 setnonblocking(int fd, int nonblocking)
377 {
378     int flags, newflags;
379 
380     flags = fcntl(fd, F_GETFL, 0);
381     if (flags < 0) {
382         perror("fcntl(F_GETFL)");
383         return -1;
384     }
385     if (nonblocking)
386 	newflags = flags | (int) O_NONBLOCK;
387     else
388 	newflags = flags & ~((int) O_NONBLOCK);
389     if (newflags != flags)
390 	if (fcntl(fd, F_SETFL, newflags) < 0) {
391 	    perror("fcntl(F_SETFL)");
392 	    return -1;
393 	}
394     return 0;
395 }
396 
397 /****************************************************************************/
398 
399 int
400 getsockdomain(int sock)
401 {
402     struct sockaddr sa;
403     socklen_t len = sizeof(sa);
404 
405     if (getsockname(sock, &sa, &len) < 0)
406 	return -1;
407     return sa.sa_family;
408 }
409