xref: /iperf/src/iperf_client_api.c (revision 60bd98a5)
1 /*
2  * Copyright (c) 2009-2014, 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 <errno.h>
11 #include <setjmp.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <sys/types.h>
18 #include <sys/select.h>
19 #include <sys/uio.h>
20 #include <arpa/inet.h>
21 
22 #include "iperf.h"
23 #include "iperf_api.h"
24 #include "iperf_util.h"
25 #include "locale.h"
26 #include "net.h"
27 #include "timer.h"
28 
29 
30 int
31 iperf_create_streams(struct iperf_test *test)
32 {
33     int i, s;
34     struct iperf_stream *sp;
35 
36     for (i = 0; i < test->num_streams; ++i) {
37 
38         if ((s = test->protocol->connect(test)) < 0)
39             return -1;
40 
41 	if (test->sender)
42 	    FD_SET(s, &test->write_set);
43 	else
44 	    FD_SET(s, &test->read_set);
45 	if (s > test->max_fd) test->max_fd = s;
46 
47         sp = iperf_new_stream(test, s);
48         if (!sp)
49             return -1;
50 
51         /* Perform the new stream callback */
52         if (test->on_new_stream)
53             test->on_new_stream(sp);
54     }
55 
56     return 0;
57 }
58 
59 static void
60 test_timer_proc(TimerClientData client_data, struct timeval *nowP)
61 {
62     struct iperf_test *test = client_data.p;
63 
64     test->timer = NULL;
65     test->done = 1;
66 }
67 
68 static void
69 client_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
70 {
71     struct iperf_test *test = client_data.p;
72 
73     if (test->done)
74         return;
75     if (test->stats_callback)
76 	test->stats_callback(test);
77 }
78 
79 static void
80 client_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
81 {
82     struct iperf_test *test = client_data.p;
83 
84     if (test->done)
85         return;
86     if (test->reporter_callback)
87 	test->reporter_callback(test);
88 }
89 
90 static int
91 create_client_timers(struct iperf_test * test)
92 {
93     struct timeval now;
94     TimerClientData cd;
95 
96     if (gettimeofday(&now, NULL) < 0) {
97 	i_errno = IEINITTEST;
98 	return -1;
99     }
100     cd.p = test;
101     test->timer = test->stats_timer = test->reporter_timer = NULL;
102     if (test->duration != 0) {
103 	test->done = 0;
104         test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0);
105         if (test->timer == NULL) {
106             i_errno = IEINITTEST;
107             return -1;
108 	}
109     }
110     if (test->stats_interval != 0) {
111         test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
112         if (test->stats_timer == NULL) {
113             i_errno = IEINITTEST;
114             return -1;
115 	}
116     }
117     if (test->reporter_interval != 0) {
118         test->reporter_timer = tmr_create(&now, client_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
119         if (test->reporter_timer == NULL) {
120             i_errno = IEINITTEST;
121             return -1;
122 	}
123     }
124     return 0;
125 }
126 
127 static void
128 client_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
129 {
130     struct iperf_test *test = client_data.p;
131 
132     test->omit_timer = NULL;
133     test->omitting = 0;
134     iperf_reset_stats(test);
135     if (test->verbose && !test->json_output && test->reporter_interval == 0)
136         iprintf(test, "%s", report_omit_done);
137 
138     /* Reset the timers. */
139     if (test->stats_timer != NULL)
140         tmr_reset(nowP, test->stats_timer);
141     if (test->reporter_timer != NULL)
142         tmr_reset(nowP, test->reporter_timer);
143 }
144 
145 static int
146 create_client_omit_timer(struct iperf_test * test)
147 {
148     struct timeval now;
149     TimerClientData cd;
150 
151     if (test->omit == 0) {
152 	test->omit_timer = NULL;
153         test->omitting = 0;
154     } else {
155 	if (gettimeofday(&now, NULL) < 0) {
156 	    i_errno = IEINITTEST;
157 	    return -1;
158 	}
159 	test->omitting = 1;
160 	cd.p = test;
161 	test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
162 	if (test->omit_timer == NULL) {
163 	    i_errno = IEINITTEST;
164 	    return -1;
165 	}
166     }
167     return 0;
168 }
169 
170 int
171 iperf_handle_message_client(struct iperf_test *test)
172 {
173     int rval;
174     int32_t err;
175 
176     /*!!! Why is this read() and not Nread()? */
177     if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
178         if (rval == 0) {
179             i_errno = IECTRLCLOSE;
180             return -1;
181         } else {
182             i_errno = IERECVMESSAGE;
183             return -1;
184         }
185     }
186 
187     switch (test->state) {
188         case PARAM_EXCHANGE:
189             if (iperf_exchange_parameters(test) < 0)
190                 return -1;
191             if (test->on_connect)
192                 test->on_connect(test);
193             break;
194         case CREATE_STREAMS:
195             if (iperf_create_streams(test) < 0)
196                 return -1;
197             break;
198         case TEST_START:
199             if (iperf_init_test(test) < 0)
200                 return -1;
201             if (create_client_timers(test) < 0)
202                 return -1;
203             if (create_client_omit_timer(test) < 0)
204                 return -1;
205 	    if (!test->reverse)
206 		if (iperf_create_send_timers(test) < 0)
207 		    return -1;
208             break;
209         case TEST_RUNNING:
210             break;
211         case EXCHANGE_RESULTS:
212             if (iperf_exchange_results(test) < 0)
213                 return -1;
214             break;
215         case DISPLAY_RESULTS:
216             if (test->on_test_finish)
217                 test->on_test_finish(test);
218             iperf_client_end(test);
219             break;
220         case IPERF_DONE:
221             break;
222         case SERVER_TERMINATE:
223             i_errno = IESERVERTERM;
224 
225 	    /*
226 	     * Temporarily be in DISPLAY_RESULTS phase so we can get
227 	     * ending summary statistics.
228 	     */
229 	    signed char oldstate = test->state;
230 	    cpu_util(test->cpu_util);
231 	    test->state = DISPLAY_RESULTS;
232 	    test->reporter_callback(test);
233 	    test->state = oldstate;
234             return -1;
235         case ACCESS_DENIED:
236             i_errno = IEACCESSDENIED;
237             return -1;
238         case SERVER_ERROR:
239             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
240                 i_errno = IECTRLREAD;
241                 return -1;
242             }
243 	    i_errno = ntohl(err);
244             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
245                 i_errno = IECTRLREAD;
246                 return -1;
247             }
248             errno = ntohl(err);
249             return -1;
250         default:
251             i_errno = IEMESSAGE;
252             return -1;
253     }
254 
255     return 0;
256 }
257 
258 
259 
260 /* iperf_connect -- client to server connection function */
261 int
262 iperf_connect(struct iperf_test *test)
263 {
264     FD_ZERO(&test->read_set);
265     FD_ZERO(&test->write_set);
266 
267     make_cookie(test->cookie);
268 
269     /* Create and connect the control channel */
270     if (test->ctrl_sck < 0)
271 	test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->server_hostname, test->server_port);
272     if (test->ctrl_sck < 0) {
273         i_errno = IECONNECT;
274         return -1;
275     }
276 
277     if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
278         i_errno = IESENDCOOKIE;
279         return -1;
280     }
281 
282     FD_SET(test->ctrl_sck, &test->read_set);
283     if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
284 
285     return 0;
286 }
287 
288 
289 int
290 iperf_client_end(struct iperf_test *test)
291 {
292     struct iperf_stream *sp;
293 
294     /* Close all stream sockets */
295     SLIST_FOREACH(sp, &test->streams, streams) {
296         close(sp->socket);
297     }
298 
299     /* show final summary */
300     test->reporter_callback(test);
301 
302     if (iperf_set_send_state(test, IPERF_DONE) != 0)
303         return -1;
304 
305     return 0;
306 }
307 
308 
309 static jmp_buf sigend_jmp_buf;
310 
311 static void
312 sigend_handler(int sig)
313 {
314     longjmp(sigend_jmp_buf, 1);
315 }
316 
317 
318 typedef enum { cm_select, cm_itimer } cm_t;
319 
320 static int sigalrm_triggered;
321 
322 static void
323 sigalrm_handler(int sig)
324 {
325     sigalrm_triggered = 1;
326 }
327 
328 int
329 iperf_run_client(struct iperf_test * test)
330 {
331     cm_t concurrency_model;
332     int startup;
333     int result = 0;
334     fd_set read_set, write_set;
335     struct timeval now;
336     struct timeval* timeout = NULL;
337     struct itimerval itv;
338 
339     /* Termination signals. */
340     iperf_catch_sigend(sigend_handler);
341     if (setjmp(sigend_jmp_buf))
342 	iperf_got_sigend(test);
343 
344     if (test->affinity != -1)
345 	if (iperf_setaffinity(test, test->affinity) != 0)
346 	    return -1;
347 
348     if (test->json_output)
349 	if (iperf_json_start(test) < 0)
350 	    return -1;
351 
352     if (test->json_output) {
353 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
354 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
355     } else if (test->verbose) {
356 	iprintf(test, "%s\n", version);
357 	iprintf(test, "%s", "");
358 	fflush(stdout);
359 	printf("%s\n", get_system_info());
360     }
361 
362     /* Start the client and connect to the server */
363     if (iperf_connect(test) < 0)
364         return -1;
365 
366     /* Begin calculating CPU utilization */
367     cpu_util(NULL);
368 
369     startup = 1;
370     concurrency_model = cm_select;	/* always start in select mode */
371     while (test->state != IPERF_DONE) {
372 
373 	if (concurrency_model == cm_select) {
374 	    memcpy(&read_set, &test->read_set, sizeof(fd_set));
375 	    memcpy(&write_set, &test->write_set, sizeof(fd_set));
376 	    (void) gettimeofday(&now, NULL);
377 	    timeout = tmr_timeout(&now);
378 	    result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
379 	    if (result < 0 && errno != EINTR) {
380 		i_errno = IESELECT;
381 		return -1;
382 	    }
383 	    if (result > 0) {
384 		if (FD_ISSET(test->ctrl_sck, &read_set)) {
385 		    if (iperf_handle_message_client(test) < 0) {
386 			return -1;
387 		    }
388 		    FD_CLR(test->ctrl_sck, &read_set);
389 		}
390 	    }
391 	}
392 
393 	if (test->state == TEST_RUNNING) {
394 
395 	    /* Is this our first time really running? */
396 	    if (startup) {
397 	        startup = 0;
398 		/* Decide which concurrency model to use for the real test.
399 		** SIGALRM is less overhead but there are a bunch of cases
400 		** where it either won't work or is ill-advised.
401 		*/
402 		if (test->may_use_sigalrm && test->settings->rate == 0 &&
403 		    (test->stats_interval == 0 || test->stats_interval > 0.2) &&
404 		    (test->reporter_interval == 0 || test->reporter_interval > 0.2) &&
405 		    (test->omit == 0 || test->omit > 0.2) &&
406 		    ! test->reverse) {
407 		    concurrency_model = cm_itimer;
408 		    test->multisend = 1;
409 		    signal(SIGALRM, sigalrm_handler);
410 		    sigalrm_triggered = 0;
411 		    itv.it_interval.tv_sec = 0;
412 		    itv.it_interval.tv_usec = 100000;
413 		    itv.it_value.tv_sec = 0;
414 		    itv.it_value.tv_usec = 100000;
415 		    (void) setitimer(ITIMER_REAL, &itv, NULL);
416 		}
417 
418 	    }
419 
420 	    if (test->reverse) {
421 		// Reverse mode. Client receives.
422 		if (iperf_recv(test, &read_set) < 0)
423 		    return -1;
424 	    } else {
425 		// Regular mode. Client sends.
426 		if (iperf_send(test, concurrency_model == cm_itimer ? NULL : &write_set) < 0)
427 		    return -1;
428 	    }
429 
430 	    if ((concurrency_model == cm_select &&
431 	         (result == 0 ||
432 		  (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0))) ||
433 	        (concurrency_model == cm_itimer && sigalrm_triggered)) {
434 		/* Run the timers. */
435 		(void) gettimeofday(&now, NULL);
436 		tmr_run(&now);
437 	        if (concurrency_model == cm_itimer)
438 		    sigalrm_triggered = 0;
439 	    }
440 
441 	    /* Is the test done yet? */
442 	    if ((!test->omitting) &&
443 	        ((test->duration != 0 && test->done) ||
444 	         (test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) ||
445 	         (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks))) {
446 		/* Yes, done!  Send TEST_END. */
447 		test->done = 1;
448 		cpu_util(test->cpu_util);
449 		test->stats_callback(test);
450 		if (iperf_set_send_state(test, TEST_END) != 0)
451 		    return -1;
452 		/* If we were doing setitimer(), go back to select() for the end. */
453 		if (concurrency_model == cm_itimer) {
454 		    itv.it_interval.tv_sec = 0;
455 		    itv.it_interval.tv_usec = 0;
456 		    itv.it_value.tv_sec = 0;
457 		    itv.it_value.tv_usec = 0;
458 		    (void) setitimer(ITIMER_REAL, &itv, NULL);
459 		    concurrency_model = cm_select;
460 		}
461 	    }
462 	}
463 	// If we're in reverse mode, continue draining the data
464 	// connection(s) even if test is over.  This prevents a
465 	// deadlock where the server side fills up its pipe(s)
466 	// and gets blocked, so it can't receive state changes
467 	// from the client side.
468 	else if (test->reverse && test->state == TEST_END) {
469 	    if (iperf_recv(test, &read_set) < 0)
470 		return -1;
471 	}
472     }
473 
474     if (test->json_output) {
475 	if (iperf_json_finish(test) < 0)
476 	    return -1;
477     } else {
478 	iprintf(test, "\n");
479 	iprintf(test, "%s", report_done);
480     }
481 
482     return 0;
483 }
484