xref: /iperf/src/net.c (revision 56a97f93)
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 #include "net.h"
24 #include "timer.h"
25 
26 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
27  * Copyright: http://swtch.com/libtask/COPYRIGHT
28 */
29 
30 /* make connection to server */
31 int
32 netdial(int domain, int proto, char *local, char *server, int port)
33 {
34     int s;
35     struct addrinfo hints, *res;
36 
37     s = socket(domain, proto, 0);
38     if (s < 0) {
39         return (-1);
40     }
41 
42     if (local) {
43         memset(&hints, 0, sizeof(hints));
44         hints.ai_family = domain;
45         hints.ai_socktype = proto;
46 
47         // XXX: Check getaddrinfo for errors!
48         if (getaddrinfo(local, NULL, &hints, &res) != 0)
49             return (-1);
50 
51         if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0)
52             return (-1);
53 
54         freeaddrinfo(res);
55     }
56 
57     memset(&hints, 0, sizeof(hints));
58     hints.ai_family = domain;
59     hints.ai_socktype = proto;
60 
61     // XXX: Check getaddrinfo for errors!
62     if (getaddrinfo(server, NULL, &hints, &res) != 0)
63         return (-1);
64 
65     ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(port);
66 
67     if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) {
68         return (-1);
69     }
70 
71     freeaddrinfo(res);
72 
73     return (s);
74 }
75 
76 /***************************************************************/
77 
78 int
79 netannounce(int domain, int proto, char *local, int port)
80 {
81     int s, opt;
82     struct addrinfo hints, *res;
83     char portstr[6];
84 
85     s = socket(domain, proto, 0);
86     if (s < 0) {
87         return (-1);
88     }
89     opt = 1;
90     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
91 
92     snprintf(portstr, 6, "%d", port);
93     memset(&hints, 0, sizeof(hints));
94     hints.ai_family = domain;
95     hints.ai_socktype = proto;
96     hints.ai_flags = AI_PASSIVE;
97     // XXX: Check getaddrinfo for errors!
98     if (getaddrinfo(local, portstr, &hints, &res) != 0)
99         return (-1);
100 
101     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
102         close(s);
103         return (-1);
104     }
105 
106     freeaddrinfo(res);
107 
108     if (proto == SOCK_STREAM) {
109         if (listen(s, 5) < 0) {
110             return (-1);
111         }
112     }
113 
114     return (s);
115 }
116 
117 
118 /*******************************************************************/
119 /* reads 'count' byptes from a socket  */
120 /********************************************************************/
121 
122 int
123 Nread(int fd, void *buf, int count, int prot)
124 {
125     register int n;
126     register int nleft = count;
127 
128     while (nleft > 0) {
129         if ((n = read(fd, buf, nleft)) < 0) {
130             if (errno == EINTR)
131                 n = 0;
132             else
133                 return (-1);
134         } else if (n == 0)
135             break;
136 
137         nleft -= n;
138         buf += n;
139     }
140     return (count - nleft);
141 }
142 
143 
144 /*
145  *                      N W R I T E
146  *
147  * XXX: After updating this function to use read/write, the only difference between
148  *      TCP and UDP is that udp handles ENOBUFS. Should we merge the two?
149  */
150 
151 int
152 Nwrite(int fd, void *buf, int count, int prot)
153 {
154     register int n;
155     register int nleft = count;
156 
157     if (prot == SOCK_DGRAM) { /* UDP mode */
158         while (nleft > 0) {
159             if ((n = write(fd, buf, nleft)) < 0) {
160                 if (errno == EINTR) {
161                     n = 0;
162                 } else if (errno == ENOBUFS) {
163                     /* wait if run out of buffers */
164                     /* XXX: but how long to wait? Start shorter and increase delay each time?? */
165                     delay(18000);   // XXX: Fixme!
166                     n = 0;
167                 } else {
168                     return (-1);
169                 }
170             }
171             nleft -= n;
172             buf += n;
173         }
174     } else {
175         while (nleft > 0) {
176             if ((n = write(fd, buf, nleft)) < 0) {
177                 if (errno == EINTR)
178                     n = 0;
179                 else
180                     return (-1);
181             }
182             nleft -= n;
183             buf += n;
184         }
185     }
186     return (count);
187 }
188 
189 /*************************************************************************/
190 
191 /**
192  * getsock_tcp_mss - Returns the MSS size for TCP
193  *
194  */
195 
196 int
197 getsock_tcp_mss(int inSock)
198 {
199     int             mss = 0;
200 
201     int             rc;
202     socklen_t       len;
203 
204     assert(inSock >= 0); /* print error and exit if this is not true */
205 
206     /* query for mss */
207     len = sizeof(mss);
208     rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
209 
210     return mss;
211 }
212 
213 
214 
215 /*************************************************************/
216 
217 /* sets TCP_NODELAY and TCP_MAXSEG if requested */
218 // XXX: This function is not being used.
219 
220 int
221 set_tcp_options(int sock, int no_delay, int mss)
222 {
223 
224     socklen_t       len;
225 
226     if (no_delay == 1) {
227         int             no_delay = 1;
228 
229         len = sizeof(no_delay);
230         int             rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
231                              (char *)&no_delay, len);
232 
233         if (rc == -1) {
234             perror("TCP_NODELAY");
235             return -1;
236         }
237     }
238 #ifdef TCP_MAXSEG
239     if (mss > 0) {
240         int             rc;
241         int             new_mss;
242 
243         len = sizeof(new_mss);
244 
245         assert(sock != -1);
246 
247         /* set */
248         new_mss = mss;
249         len = sizeof(new_mss);
250         rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
251         if (rc == -1) {
252             perror("setsockopt");
253             return -1;
254         }
255         /* verify results */
256         rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
257         if (new_mss != mss) {
258             perror("setsockopt value mismatch");
259             return -1;
260         }
261     }
262 #endif
263     return 0;
264 }
265 
266 /****************************************************************************/
267 
268 // XXX: This function is not being used.
269 int
270 setnonblocking(int sock)
271 {
272     int       opts = 0;
273 
274     opts = (opts | O_NONBLOCK);
275     if (fcntl(sock, F_SETFL, opts) < 0)
276     {
277         perror("fcntl(F_SETFL)");
278         return -1;
279     }
280     return 0;
281 }
282 
283