xref: /iperf/src/iperf_server_api.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 /* iperf_server_api.c: Functions to be used by an iperf server
11 */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <getopt.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <assert.h>
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <pthread.h>
27 #include <stdint.h>
28 #include <netinet/tcp.h>
29 #include <sys/time.h>
30 #include <sys/resource.h>
31 #include <sched.h>
32 #include <setjmp.h>
33 
34 #include "iperf.h"
35 #include "iperf_server_api.h"
36 #include "iperf_api.h"
37 #include "iperf_udp.h"
38 #include "iperf_tcp.h"
39 #include "iperf_error.h"
40 #include "iperf_util.h"
41 #include "timer.h"
42 #include "net.h"
43 #include "units.h"
44 #include "tcp_window_size.h"
45 #include "iperf_util.h"
46 #include "locale.h"
47 
48 
49 int
50 iperf_server_listen(struct iperf_test *test)
51 {
52     char ubuf[UNIT_LEN];
53     int x;
54 
55     if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
56         i_errno = IELISTEN;
57         return (-1);
58     }
59 
60     printf("-----------------------------------------------------------\n");
61     printf("Server listening on %d\n", test->server_port);
62 
63     // This needs to be changed to reflect if client has different window size
64     // make sure we got what we asked for
65     /* XXX: This needs to be moved to the stream listener
66     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
67         // Needs to set some sort of error number/message
68         perror("SO_RCVBUF");
69         return -1;
70     }
71     */
72 
73     // XXX: This code needs to be moved to after parameter exhange
74     /*
75     if (test->protocol->id == Ptcp) {
76         if (test->settings->socket_bufsize > 0) {
77             unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
78             printf("TCP window size: %s\n", ubuf);
79         } else {
80             printf("Using TCP Autotuning\n");
81         }
82     }
83     */
84     printf("-----------------------------------------------------------\n");
85 
86     FD_ZERO(&test->read_set);
87     FD_ZERO(&test->write_set);
88     FD_SET(test->listener, &test->read_set);
89     test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd;
90 
91     return 0;
92 }
93 
94 int
95 iperf_accept(struct iperf_test *test)
96 {
97     int s;
98     int rbuf = ACCESS_DENIED;
99     char cookie[COOKIE_SIZE];
100     socklen_t len;
101     struct sockaddr_in addr;
102 
103     len = sizeof(addr);
104     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
105         i_errno = IEACCEPT;
106         return (-1);
107     }
108 
109     if (test->ctrl_sck == -1) {
110         /* Server free, accept new client */
111         if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
112             i_errno = IERECVCOOKIE;
113             return (-1);
114         }
115 
116         FD_SET(s, &test->read_set);
117         FD_SET(s, &test->write_set);
118         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
119         test->ctrl_sck = s;
120 
121         test->state = PARAM_EXCHANGE;
122         if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
123             i_errno = IESENDMESSAGE;
124             return (-1);
125         }
126         if (iperf_exchange_parameters(test) < 0) {
127             return (-1);
128         }
129         if (test->on_connect) {
130             test->on_connect(test);
131         }
132     } else {
133         // XXX: Do we even need to receive cookie if we're just going to deny anyways?
134         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
135             i_errno = IERECVCOOKIE;
136             return (-1);
137         }
138         if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) {
139             i_errno = IESENDMESSAGE;
140             return (-1);
141         }
142         close(s);
143     }
144 
145     return (0);
146 }
147 
148 
149 /**************************************************************************/
150 int
151 iperf_handle_message_server(struct iperf_test *test)
152 {
153     int rval;
154     struct iperf_stream *sp;
155 
156     // XXX: Need to rethink how this behaves to fit API
157     if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) {
158         if (rval == 0) {
159             fprintf(stderr, "The client has unexpectedly closed the connection.\n");
160             i_errno = IECTRLCLOSE;
161             test->state = IPERF_DONE;
162             return (0);
163         } else {
164             i_errno = IERECVMESSAGE;
165             return (-1);
166         }
167     }
168 
169     switch(test->state) {
170         case TEST_START:
171             break;
172         case TEST_END:
173             cpu_util(&test->cpu_util);
174             test->stats_callback(test);
175             SLIST_FOREACH(sp, &test->streams, streams) {
176                 FD_CLR(sp->socket, &test->read_set);
177                 FD_CLR(sp->socket, &test->write_set);
178                 close(sp->socket);
179             }
180             test->state = EXCHANGE_RESULTS;
181             if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
182                 i_errno = IESENDMESSAGE;
183                 return (-1);
184             }
185             if (iperf_exchange_results(test) < 0)
186                 return (-1);
187             test->state = DISPLAY_RESULTS;
188             if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
189                 i_errno = IESENDMESSAGE;
190                 return (-1);
191             }
192             if (test->on_test_finish)
193                 test->on_test_finish(test);
194             test->reporter_callback(test);
195             break;
196         case IPERF_DONE:
197             break;
198         case CLIENT_TERMINATE:
199             i_errno = IECLIENTTERM;
200 
201             // XXX: Remove this line below!
202             fprintf(stderr, "The client has terminated.\n");
203             SLIST_FOREACH(sp, &test->streams, streams) {
204                 FD_CLR(sp->socket, &test->read_set);
205                 FD_CLR(sp->socket, &test->write_set);
206                 close(sp->socket);
207             }
208             test->state = IPERF_DONE;
209             break;
210         default:
211             i_errno = IEMESSAGE;
212             return (-1);
213     }
214 
215     return (0);
216 }
217 
218 /* XXX: This function is not used anymore */
219 void
220 iperf_test_reset(struct iperf_test *test)
221 {
222     struct iperf_stream *sp;
223 
224     close(test->ctrl_sck);
225 
226     /* Free streams */
227     while (!SLIST_EMPTY(&test->streams)) {
228         sp = SLIST_FIRST(&test->streams);
229         SLIST_REMOVE_HEAD(&test->streams, streams);
230         iperf_free_stream(sp);
231     }
232     free_timer(test->timer);
233     free_timer(test->stats_timer);
234     free_timer(test->reporter_timer);
235     test->timer = NULL;
236     test->stats_timer = NULL;
237     test->reporter_timer = NULL;
238 
239     SLIST_INIT(&test->streams);
240 
241     test->role = 's';
242     set_protocol(test, Ptcp);
243     test->duration = DURATION;
244     test->state = 0;
245     test->server_hostname = NULL;
246 
247     test->ctrl_sck = -1;
248     test->prot_listener = -1;
249 
250     test->bytes_sent = 0;
251 
252     test->reverse = 0;
253     test->no_delay = 0;
254 
255     FD_ZERO(&test->read_set);
256     FD_ZERO(&test->write_set);
257     FD_SET(test->listener, &test->read_set);
258     test->max_fd = test->listener;
259 
260     test->num_streams = 1;
261     test->settings->socket_bufsize = 0;
262     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
263     test->settings->rate = RATE;   /* UDP only */
264     test->settings->mss = 0;
265     memset(test->cookie, 0, COOKIE_SIZE);
266 }
267 
268 int
269 iperf_run_server(struct iperf_test *test)
270 {
271     int result, s, streams_accepted;
272     fd_set temp_read_set, temp_write_set;
273     struct iperf_stream *sp;
274     struct timeval tv;
275     time_t sec, usec;
276 
277     // Open socket and listen
278     if (iperf_server_listen(test) < 0) {
279         return (-1);
280     }
281 
282     // Begin calculating CPU utilization
283     cpu_util(NULL);
284 
285     test->state = IPERF_START;
286     streams_accepted = 0;
287 
288     while (test->state != IPERF_DONE) {
289 
290         memcpy(&temp_read_set, &test->read_set, sizeof(fd_set));
291         memcpy(&temp_write_set, &test->write_set, sizeof(fd_set));
292         tv.tv_sec = 15;
293         tv.tv_usec = 0;
294 
295         result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv);
296         if (result < 0 && errno != EINTR) {
297             i_errno = IESELECT;
298             return (-1);
299         } else if (result > 0) {
300             if (FD_ISSET(test->listener, &temp_read_set)) {
301                 if (test->state != CREATE_STREAMS) {
302                     if (iperf_accept(test) < 0) {
303                         return (-1);
304                     }
305                     FD_CLR(test->listener, &temp_read_set);
306                 }
307             }
308             if (FD_ISSET(test->ctrl_sck, &temp_read_set)) {
309                 if (iperf_handle_message_server(test) < 0)
310                     return (-1);
311                 FD_CLR(test->ctrl_sck, &temp_read_set);
312             }
313 
314             if (test->state == CREATE_STREAMS) {
315                 if (FD_ISSET(test->prot_listener, &temp_read_set)) {
316 
317                     if ((s = test->protocol->accept(test)) < 0)
318                         return (-1);
319 
320                     if (!is_closed(s)) {
321                         sp = iperf_new_stream(test, s);
322                         if (!sp)
323                             return (-1);
324 
325                         FD_SET(s, &test->read_set);
326                         FD_SET(s, &test->write_set);
327                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
328 
329                         streams_accepted++;
330                         if (test->on_new_stream)
331                             test->on_new_stream(sp);
332                     }
333                     FD_CLR(test->prot_listener, &temp_read_set);
334                 }
335 
336                 if (streams_accepted == test->num_streams) {
337                     if (test->protocol->id != Ptcp) {
338                         FD_CLR(test->prot_listener, &test->read_set);
339                         close(test->prot_listener);
340                     } else {
341                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
342                             FD_CLR(test->listener, &test->read_set);
343                             close(test->listener);
344                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
345                                 i_errno = IELISTEN;
346                                 return (-1);
347                             }
348                             test->listener = s;
349                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
350                             FD_SET(test->listener, &test->read_set);
351                         }
352                     }
353                     test->prot_listener = -1;
354                     test->state = TEST_START;
355                     if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
356                         i_errno = IESENDMESSAGE;
357                         return (-1);
358                     }
359                     if (iperf_init_test(test) < 0)
360                         return (-1);
361                     test->state = TEST_RUNNING;
362                     if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
363                         i_errno = IESENDMESSAGE;
364                         return (-1);
365                     }
366                 }
367             }
368 
369             if (test->state == TEST_RUNNING) {
370                 if (test->reverse) {
371                     // Reverse mode. Server sends.
372                     if (iperf_send(test) < 0)
373                         return (-1);
374                 } else {
375                     // Regular mode. Server receives.
376                     if (iperf_recv(test) < 0)
377                         return (-1);
378                 }
379 
380                 /* Perform callbacks */
381                 if (timer_expired(test->stats_timer)) {
382                     test->stats_callback(test);
383                     sec = (time_t) test->stats_interval;
384                     usec = (test->stats_interval - sec) * SEC_TO_US;
385                     if (update_timer(test->stats_timer, sec, usec) < 0)
386                         return (-1);
387                 }
388                 if (timer_expired(test->reporter_timer)) {
389                     test->reporter_callback(test);
390                     sec = (time_t) test->reporter_interval;
391                     usec = (test->reporter_interval - sec) * SEC_TO_US;
392                     if (update_timer(test->reporter_timer, sec, usec) < 0)
393                         return (-1);
394                 }
395             }
396         }
397     }
398 
399     /* Close open test sockets */
400     close(test->ctrl_sck);
401     close(test->listener);
402 
403     return (0);
404 }
405 
406