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