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