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