xref: /iperf/src/iperf_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 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <errno.h>
13 #include <signal.h>
14 #include <unistd.h>
15 #include <assert.h>
16 #include <fcntl.h>
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <pthread.h>
23 #include <stdint.h>
24 #include <netinet/tcp.h>
25 #include <sys/time.h>
26 #include <sys/resource.h>
27 #include <sched.h>
28 #include <setjmp.h>
29 
30 #include "net.h"
31 #include "iperf.h"
32 #include "iperf_api.h"
33 #include "iperf_udp.h"
34 #include "iperf_tcp.h"
35 #include "iperf_error.h"
36 #include "timer.h"
37 
38 #include "units.h"
39 #include "tcp_window_size.h"
40 #include "iperf_util.h"
41 #include "locale.h"
42 
43 jmp_buf env;			/* to handle longjmp on signal */
44 
45 /*************************** Print usage functions ****************************/
46 
47 void
48 usage()
49 {
50     fprintf(stderr, usage_short);
51 }
52 
53 
54 void
55 usage_long()
56 {
57     fprintf(stderr, usage_long1);
58     fprintf(stderr, usage_long2);
59 }
60 
61 
62 /********************** Get/set test protocol structure ***********************/
63 
64 struct protocol *
65 get_protocol(struct iperf_test *test, int prot_id)
66 {
67     struct protocol *prot;
68 
69     SLIST_FOREACH(prot, &test->protocols, protocols) {
70         if (prot->id == prot_id)
71             break;
72     }
73 
74     if (prot == NULL)
75         i_errno = IEPROTOCOL;
76 
77     return (prot);
78 }
79 
80 int
81 set_protocol(struct iperf_test *test, int prot_id)
82 {
83     struct protocol *prot = NULL;
84 
85     SLIST_FOREACH(prot, &test->protocols, protocols) {
86         if (prot->id == prot_id) {
87             test->protocol = prot;
88             return (0);
89         }
90     }
91 
92     i_errno = IEPROTOCOL;
93 
94     return (-1);
95 }
96 
97 
98 /************************** Iperf callback functions **************************/
99 
100 void
101 iperf_on_new_stream(struct iperf_stream *sp)
102 {
103     connect_msg(sp);
104 }
105 
106 void
107 iperf_on_test_start(struct iperf_test *test)
108 {
109     if (test->verbose) {
110         if (test->settings->bytes) {
111             printf(test_start_bytes, test->protocol->name, test->num_streams,
112                 test->settings->blksize, test->settings->bytes);
113         } else {
114             printf(test_start_time, test->protocol->name, test->num_streams,
115                 test->settings->blksize, test->duration);
116         }
117     }
118 }
119 
120 void
121 iperf_on_connect(struct iperf_test *test)
122 {
123     char ipr[INET6_ADDRSTRLEN];
124     struct sockaddr_storage temp;
125     socklen_t len;
126     int domain, opt;
127 
128     if (test->role == 'c') {
129         printf("Connecting to host %s, port %d\n", test->server_hostname,
130             test->server_port);
131     } else {
132         domain = test->settings->domain;
133         len = sizeof(temp);
134         getpeername(test->ctrl_sck, (struct sockaddr *) &temp, &len);
135         if (domain == AF_INET) {
136             inet_ntop(domain, &((struct sockaddr_in *) &temp)->sin_addr, ipr, sizeof(ipr));
137             printf("Accepted connection from %s, port %d\n", ipr, ntohs(((struct sockaddr_in *) &temp)->sin_port));
138         } else {
139             inet_ntop(domain, &((struct sockaddr_in6 *) &temp)->sin6_addr, ipr, sizeof(ipr));
140             printf("Accepted connection from %s, port %d\n", ipr, ntohs(((struct sockaddr_in6 *) &temp)->sin6_port));
141         }
142     }
143     if (test->verbose) {
144         printf("      Cookie: %s\n", test->cookie);
145         if (test->protocol->id == SOCK_STREAM) {
146             if (test->settings->mss) {
147                 printf("      TCP MSS: %d\n", test->settings->mss);
148             } else {
149                 len = sizeof(opt);
150                 getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
151                 printf("      TCP MSS: %d (default)\n", opt);
152             }
153         }
154 
155     }
156 }
157 
158 void
159 iperf_on_test_finish(struct iperf_test *test)
160 {
161     if (test->verbose) {
162         printf("Test Complete. Summary Results:\n");
163     }
164 }
165 
166 
167 /******************************************************************************/
168 
169 int
170 iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
171 {
172     static struct option longopts[] =
173     {
174         {"client", required_argument, NULL, 'c'},
175         {"server", no_argument, NULL, 's'},
176         {"time", required_argument, NULL, 't'},
177         {"port", required_argument, NULL, 'p'},
178         {"parallel", required_argument, NULL, 'P'},
179         {"udp", no_argument, NULL, 'u'},
180         {"bind", required_argument, NULL, 'B'},
181         {"tcpInfo", no_argument, NULL, 'T'},
182         {"bandwidth", required_argument, NULL, 'b'},
183         {"length", required_argument, NULL, 'l'},
184         {"window", required_argument, NULL, 'w'},
185         {"interval", required_argument, NULL, 'i'},
186         {"bytes", required_argument, NULL, 'n'},
187         {"NoDelay", no_argument, NULL, 'N'},
188         {"Set-mss", required_argument, NULL, 'M'},
189         {"version", no_argument, NULL, 'v'},
190         {"verbose", no_argument, NULL, 'V'},
191         {"debug", no_argument, NULL, 'd'},
192         {"help", no_argument, NULL, 'h'},
193         {"daemon", no_argument, NULL, 'D'},
194         {"format", required_argument, NULL, 'f'},
195         {"reverse", no_argument, NULL, 'R'},
196         {"version6", no_argument, NULL, '6'},
197 
198     /*  XXX: The following ifdef needs to be split up. linux-congestion is not necessarily supported
199      *  by systems that support tos.
200      */
201 #ifdef ADD_WHEN_SUPPORTED
202         {"tos",        required_argument, NULL, 'S'},
203         {"linux-congestion", required_argument, NULL, 'Z'},
204 #endif
205         {NULL, 0, NULL, 0}
206     };
207     char ch;
208 
209     while ((ch = getopt_long(argc, argv, "c:p:st:uP:B:b:l:w:i:n:RS:NTvh6VdM:f:", longopts, NULL)) != -1) {
210         switch (ch) {
211             case 'c':
212                 if (test->role == 's') {
213                     i_errno = IESERVCLIENT;
214                     return (-1);
215                 } else {
216                     test->role = 'c';
217                     test->server_hostname = (char *) malloc(strlen(optarg)+1);
218                     strncpy(test->server_hostname, optarg, strlen(optarg)+1);
219                 }
220                 break;
221             case 'p':
222                 test->server_port = atoi(optarg);
223                 break;
224             case 's':
225                 if (test->role == 'c') {
226                     i_errno = IESERVCLIENT;
227                     return (-1);
228                 } else {
229                     test->role = 's';
230                 }
231                 break;
232             case 't':
233                 if (test->role == 's') {
234                     i_errno = IECLIENTONLY;
235                     return (-1);
236                 }
237                 test->duration = atoi(optarg);
238                 if (test->duration > MAX_TIME) {
239                     i_errno = IEDURATION;
240                     return (-1);
241                 }
242                 break;
243             case 'u':
244                 if (test->role == 's') {
245                     i_errno = IECLIENTONLY;
246                     return (-1);
247                 }
248                 set_protocol(test, Pudp);
249                 test->settings->blksize = DEFAULT_UDP_BLKSIZE;
250                 break;
251             case 'P':
252                 if (test->role == 's') {
253                     i_errno = IECLIENTONLY;
254                     return (-1);
255                 }
256                 test->num_streams = atoi(optarg);
257                 if (test->num_streams > MAX_STREAMS) {
258                     i_errno = IENUMSTREAMS;
259                     return (-1);
260                 }
261                 break;
262             case 'B':
263                 test->bind_address = (char *) malloc(strlen(optarg)+1);
264                 strncpy(test->bind_address, optarg, strlen(optarg)+1);
265                 break;
266             case 'b':
267                 if (test->role == 's') {
268                     i_errno = IECLIENTONLY;
269                     return (-1);
270                 }
271                 test->settings->rate = unit_atof(optarg);
272                 break;
273             case 'l':
274                 if (test->role == 's') {
275                     i_errno = IECLIENTONLY;
276                     return (-1);
277                 }
278                 test->settings->blksize = unit_atoi(optarg);
279                 if (test->settings->blksize > MAX_BLOCKSIZE) {
280                     i_errno = IEBLOCKSIZE;
281                     return (-1);
282                 }
283                 break;
284             case 'w':
285                 // XXX: This is a socket buffer, not specific to TCP
286                 if (test->role == 's') {
287                     i_errno = IECLIENTONLY;
288                     return (-1);
289                 }
290                 test->settings->socket_bufsize = unit_atof(optarg);
291                 if (test->settings->socket_bufsize > MAX_TCP_BUFFER) {
292                     i_errno = IEBUFSIZE;
293                     return (-1);
294                 }
295                 break;
296             case 'i':
297                 /* XXX: could potentially want separate stat collection and reporting intervals,
298                    but just set them to be the same for now */
299                 test->stats_interval = atof(optarg);
300                 test->reporter_interval = atof(optarg);
301                 if (test->stats_interval > MAX_INTERVAL) {
302                     i_errno = IEINTERVAL;
303                     return (-1);
304                 }
305                 break;
306             case 'n':
307                 if (test->role == 's') {
308                     i_errno = IECLIENTONLY;
309                     return (-1);
310                 }
311                 test->settings->bytes = unit_atoi(optarg);
312                 break;
313             case 'N':
314                 if (test->role == 's') {
315                     i_errno = IECLIENTONLY;
316                     return (-1);
317                 }
318                 test->no_delay = 1;
319                 break;
320             case 'M':
321                 if (test->role == 's') {
322                     i_errno = IECLIENTONLY;
323                     return (-1);
324                 }
325                 test->settings->mss = atoi(optarg);
326                 if (test->settings->mss > MAX_MSS) {
327                     i_errno = IEMSS;
328                     return (-1);
329                 }
330                 break;
331             case 'f':
332                 test->settings->unit_format = *optarg;
333                 break;
334             case 'T':
335                 test->tcp_info = 1;
336                 break;
337             case '6':
338                 test->settings->domain = AF_INET6;
339                 break;
340             case 'V':
341                 test->verbose = 1;
342                 break;
343             case 'd':
344                 test->debug = 1;
345                 break;
346             case 'R':
347                 if (test->role == 's') {
348                     i_errno = IECLIENTONLY;
349                     return (-1);
350                 }
351                 test->reverse = 1;
352                 break;
353             case 'S':
354                 if (test->role == 's') {
355                     i_errno = IECLIENTONLY;
356                     return (-1);
357                 }
358                 // XXX: Checking for errors in strtol is not portable. Leave as is?
359                 test->settings->tos = strtol(optarg, NULL, 0);
360                 break;
361             case 'v':
362                 printf(version);
363                 exit(0);
364             case 'h':
365             default:
366                 usage_long();
367                 exit(1);
368         }
369     }
370     /* For subsequent calls to getopt */
371 #ifdef __APPLE__
372     optreset = 1;
373 #endif
374     optind = 0;
375 
376     if ((test->role != 'c') && (test->role != 's')) {
377         i_errno = IENOROLE;
378         return (-1);
379     }
380 
381     return (0);
382 }
383 
384 int
385 all_data_sent(struct iperf_test * test)
386 {
387     if (test->settings->bytes > 0) {
388         if (test->bytes_sent >= (test->num_streams * test->settings->bytes)) {
389             return (1);
390         }
391     }
392 
393     return (0);
394 }
395 
396 int
397 iperf_send(struct iperf_test *test)
398 {
399     int result;
400     iperf_size_t bytes_sent;
401     fd_set temp_write_set;
402     struct timeval tv;
403     struct iperf_stream *sp;
404 
405     memcpy(&temp_write_set, &test->write_set, sizeof(fd_set));
406     tv.tv_sec = 15;
407     tv.tv_usec = 0;
408 
409     result = select(test->max_fd + 1, NULL, &temp_write_set, NULL, &tv);
410     if (result < 0 && errno != EINTR) {
411         i_errno = IESELECT;
412         return (-1);
413     }
414     if (result > 0) {
415         SLIST_FOREACH(sp, &test->streams, streams) {
416             if (FD_ISSET(sp->socket, &temp_write_set)) {
417                 if ((bytes_sent = sp->snd(sp)) < 0) {
418                     i_errno = IESTREAMWRITE;
419                     return (-1);
420                 }
421                 test->bytes_sent += bytes_sent;
422                 FD_CLR(sp->socket, &temp_write_set);
423             }
424         }
425     }
426 
427     return (0);
428 }
429 
430 int
431 iperf_recv(struct iperf_test *test)
432 {
433     int result;
434     iperf_size_t bytes_sent;
435     fd_set temp_read_set;
436     struct timeval tv;
437     struct iperf_stream *sp;
438 
439     memcpy(&temp_read_set, &test->read_set, sizeof(fd_set));
440     tv.tv_sec = 15;
441     tv.tv_usec = 0;
442 
443     result = select(test->max_fd + 1, &temp_read_set, NULL, NULL, &tv);
444     if (result < 0) {
445         i_errno = IESELECT;
446         return (-1);
447     }
448     if (result > 0) {
449         SLIST_FOREACH(sp, &test->streams, streams) {
450             if (FD_ISSET(sp->socket, &temp_read_set)) {
451                 if ((bytes_sent = sp->rcv(sp)) < 0) {
452                     i_errno = IESTREAMREAD;
453                     return (-1);
454                 }
455                 test->bytes_sent += bytes_sent;
456                 FD_CLR(sp->socket, &temp_read_set);
457             }
458         }
459     }
460 
461     return (0);
462 }
463 
464 int
465 iperf_init_test(struct iperf_test *test)
466 {
467     struct iperf_stream *sp;
468     time_t sec;
469     time_t usec;
470 
471     if (test->protocol->init) {
472         if (test->protocol->init(test) < 0)
473             return (-1);
474     }
475 
476     /* Set timers */
477     if (test->settings->bytes == 0) {
478         test->timer = new_timer(test->duration, 0);
479         if (test->timer == NULL)
480             return (-1);
481     }
482 
483     if (test->stats_interval != 0) {
484         sec = (time_t) test->stats_interval;
485         usec = (test->stats_interval - sec) * SEC_TO_US;
486         test->stats_timer = new_timer(sec, usec);
487         if (test->stats_timer == NULL)
488             return (-1);
489     }
490     if (test->reporter_interval != 0) {
491         sec = (time_t) test->reporter_interval;
492         usec = (test->reporter_interval - sec) * SEC_TO_US;
493         test->reporter_timer = new_timer(sec, usec);
494         if (test->reporter_timer == NULL)
495             return (-1);
496     }
497 
498     /* Set start time */
499     SLIST_FOREACH(sp, &test->streams, streams) {
500         if (gettimeofday(&sp->result->start_time, NULL) < 0) {
501             i_errno = IEINITTEST;
502             return (-1);
503         }
504     }
505 
506     if (test->on_test_start)
507         test->on_test_start(test);
508 
509     return (0);
510 }
511 
512 
513 /*********************************************************/
514 
515 int
516 package_parameters(struct iperf_test *test)
517 {
518     char pstring[256];
519     char optbuf[128];
520     memset(pstring, 0, 256*sizeof(char));
521 
522     *pstring = ' ';
523 
524     if (test->protocol->id == Ptcp) {
525         strncat(pstring, "-p ", sizeof(pstring));
526     } else if (test->protocol->id == Pudp) {
527         strncat(pstring, "-u ", sizeof(pstring));
528     }
529 
530     snprintf(optbuf, sizeof(optbuf), "-P %d ", test->num_streams);
531     strncat(pstring, optbuf, sizeof(pstring));
532 
533     if (test->reverse)
534         strncat(pstring, "-R ", sizeof(pstring));
535 
536     if (test->settings->socket_bufsize) {
537         snprintf(optbuf, sizeof(optbuf), "-w %d ", test->settings->socket_bufsize);
538         strncat(pstring, optbuf, sizeof(pstring));
539     }
540 
541     if (test->settings->rate) {
542         snprintf(optbuf, sizeof(optbuf), "-b %llu ", test->settings->rate);
543         strncat(pstring, optbuf, sizeof(pstring));
544     }
545 
546     if (test->settings->mss) {
547         snprintf(optbuf, sizeof(optbuf), "-m %d ", test->settings->mss);
548         strncat(pstring, optbuf, sizeof(pstring));
549     }
550 
551     if (test->no_delay) {
552         snprintf(optbuf, sizeof(optbuf), "-N ");
553         strncat(pstring, optbuf, sizeof(pstring));
554     }
555 
556     if (test->settings->bytes) {
557         snprintf(optbuf, sizeof(optbuf), "-n %llu ", test->settings->bytes);
558         strncat(pstring, optbuf, sizeof(pstring));
559     }
560 
561     if (test->duration) {
562         snprintf(optbuf, sizeof(optbuf), "-t %d ", test->duration);
563         strncat(pstring, optbuf, sizeof(pstring));
564     }
565 
566     if (test->settings->blksize) {
567         snprintf(optbuf, sizeof(optbuf), "-l %d ", test->settings->blksize);
568         strncat(pstring, optbuf, sizeof(pstring));
569     }
570 
571     if (test->settings->tos) {
572         snprintf(optbuf, sizeof(optbuf), "-S %d ", test->settings->tos);
573         strncat(pstring, optbuf, sizeof(pstring));
574     }
575 
576     *pstring = (char) (strlen(pstring) - 1);
577 
578     if (Nwrite(test->ctrl_sck, pstring, strlen(pstring), Ptcp) < 0) {
579         i_errno = IESENDPARAMS;
580         return (-1);
581     }
582 
583     return 0;
584 }
585 
586 
587 int
588 parse_parameters(struct iperf_test *test)
589 {
590     int n;
591     char *param, **params;
592     char len, ch;
593     char pstring[256];
594 
595     memset(pstring, 0, 256 * sizeof(char));
596 
597     if (Nread(test->ctrl_sck, &len, sizeof(char), Ptcp) < 0) {
598         i_errno = IERECVPARAMS;
599         return (-1);
600     }
601 
602     if (Nread(test->ctrl_sck, pstring, len, Ptcp) < 0) {
603         i_errno = IERECVPARAMS;
604         return (-1);
605     }
606 
607     for (param = strtok(pstring, " "), n = 0, params = NULL; param; param = strtok(NULL, " ")) {
608         if ((params = realloc(params, (n+1)*sizeof(char *))) == NULL) {
609             i_errno = IERECVPARAMS;
610             return (-1);
611         }
612         params[n] = param;
613         n++;
614     }
615 
616     // XXX: Should we check for parameters exceeding maximum values here?
617     while ((ch = getopt(n, params, "pt:n:m:uNP:Rw:l:b:S:")) != -1) {
618         switch (ch) {
619             case 'p':
620                 set_protocol(test, Ptcp);
621                 break;
622             case 't':
623                 test->duration = atoi(optarg);
624                 break;
625             case 'n':
626                 test->settings->bytes = atoll(optarg);
627                 break;
628             case 'm':
629                 test->settings->mss = atoi(optarg);
630                 break;
631             case 'u':
632                 set_protocol(test, Pudp);
633                 break;
634             case 'N':
635                 test->no_delay = 1;
636                 break;
637             case 'P':
638                 test->num_streams = atoi(optarg);
639                 break;
640             case 'R':
641                 test->reverse = 1;
642                 break;
643             case 'w':
644                 test->settings->socket_bufsize = atoi(optarg);
645                 break;
646             case 'l':
647                 test->settings->blksize = atoi(optarg);
648                 break;
649             case 'b':
650                 test->settings->rate = atoll(optarg);
651                 break;
652             case 'S':
653                 test->settings->tos = atoi(optarg);
654                 break;
655         }
656     }
657 #ifdef __APPLE__
658     optreset = 1;
659 #endif
660     optind = 0;
661 
662     free(params);
663 
664     return (0);
665 }
666 
667 /**
668  * iperf_exchange_parameters - handles the param_Exchange part for client
669  *
670  */
671 
672 int
673 iperf_exchange_parameters(struct iperf_test * test)
674 {
675     int s, msg;
676     char state;
677 
678     if (test->role == 'c') {
679 
680         if (package_parameters(test) < 0)
681             return (-1);
682 
683     } else {
684 
685         if (parse_parameters(test) < 0)
686             return (-1);
687 
688         if ((s = test->protocol->listen(test)) < 0) {
689             state = SERVER_ERROR;
690             if (Nwrite(test->ctrl_sck, &state, sizeof(state), Ptcp) < 0) {
691                 i_errno = IESENDMESSAGE;
692                 return (-1);
693             }
694             msg = htonl(i_errno);
695             if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) {
696                 i_errno = IECTRLWRITE;
697                 return (-1);
698             }
699             msg = htonl(errno);
700             if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) {
701                 i_errno = IECTRLWRITE;
702                 return (-1);
703             }
704             return (-1);
705         }
706         FD_SET(s, &test->read_set);
707         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
708         test->prot_listener = s;
709 
710         // Send the control message to create streams and start the test
711         test->state = CREATE_STREAMS;
712         if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
713             i_errno = IESENDMESSAGE;
714             return (-1);
715         }
716 
717     }
718 
719     return (0);
720 }
721 
722 /*************************************************************/
723 
724 int
725 iperf_exchange_results(struct iperf_test *test)
726 {
727     unsigned int size;
728     char buf[128];
729     char *results;
730     struct iperf_stream *sp;
731     iperf_size_t bytes_transferred;
732 
733     if (test->role == 'c') {
734         /* Prepare results string and send to server */
735         results = NULL;
736         size = 0;
737         SLIST_FOREACH(sp, &test->streams, streams) {
738             bytes_transferred = (test->reverse ? sp->result->bytes_received : sp->result->bytes_sent);
739             snprintf(buf, 128, "%d:%llu,%lf,%d,%d\n", sp->id, bytes_transferred,sp->jitter,
740                 sp->cnt_error, sp->packet_count);
741             size += strlen(buf);
742             if ((results = realloc(results, size+1)) == NULL) {
743                 i_errno = IEPACKAGERESULTS;
744                 return (-1);
745             }
746             if (sp == SLIST_FIRST(&test->streams))
747                 *results = '\0';
748             strncat(results, buf, size+1);
749         }
750         size++;
751         size = htonl(size);
752         if (Nwrite(test->ctrl_sck, &size, sizeof(size), Ptcp) < 0) {
753             i_errno = IESENDRESULTS;
754             return (-1);
755         }
756         if (Nwrite(test->ctrl_sck, results, ntohl(size), Ptcp) < 0) {
757             i_errno = IESENDRESULTS;
758             return (-1);
759         }
760         free(results);
761 
762         /* Get server results string */
763         if (Nread(test->ctrl_sck, &size, sizeof(size), Ptcp) < 0) {
764             i_errno = IERECVRESULTS;
765             return (-1);
766         }
767         size = ntohl(size);
768         results = (char *) malloc(size * sizeof(char));
769         if (results == NULL) {
770             i_errno = IERECVRESULTS;
771             return (-1);
772         }
773         if (Nread(test->ctrl_sck, results, size, Ptcp) < 0) {
774             i_errno = IERECVRESULTS;
775             return (-1);
776         }
777 
778         // XXX: The only error this sets is IESTREAMID, which may never be reached. Consider making void.
779         if (parse_results(test, results) < 0)
780             return (-1);
781 
782         free(results);
783 
784     } else {
785         /* Get client results string */
786         if (Nread(test->ctrl_sck, &size, sizeof(size), Ptcp) < 0) {
787             i_errno = IERECVRESULTS;
788             return (-1);
789         }
790         size = ntohl(size);
791         results = (char *) malloc(size * sizeof(char));
792         if (results == NULL) {
793             i_errno = IERECVRESULTS;
794             return (-1);
795         }
796         if (Nread(test->ctrl_sck, results, size, Ptcp) < 0) {
797             i_errno = IERECVRESULTS;
798             return (-1);
799         }
800 
801         // XXX: Same issue as with client
802         if (parse_results(test, results) < 0)
803             return (-1);
804 
805         free(results);
806 
807         /* Prepare results string and send to client */
808         results = NULL;
809         size = 0;
810         SLIST_FOREACH(sp, &test->streams, streams) {
811             bytes_transferred = (test->reverse ? sp->result->bytes_sent : sp->result->bytes_received);
812             snprintf(buf, 128, "%d:%llu,%lf,%d,%d\n", sp->id, bytes_transferred, sp->jitter,
813                 sp->cnt_error, sp->packet_count);
814             size += strlen(buf);
815             if ((results = realloc(results, size+1)) == NULL) {
816                 i_errno = IEPACKAGERESULTS;
817                 return (-1);
818             }
819             if (sp == SLIST_FIRST(&test->streams))
820                 *results = '\0';
821             strncat(results, buf, size+1);
822         }
823         size++;
824         size = htonl(size);
825         if (Nwrite(test->ctrl_sck, &size, sizeof(size), Ptcp) < 0) {
826             i_errno = IESENDRESULTS;
827             return (-1);
828         }
829         if (Nwrite(test->ctrl_sck, results, ntohl(size), Ptcp) < 0) {
830             i_errno = IESENDRESULTS;
831             return (-1);
832         }
833         free(results);
834 
835     }
836 
837     return (0);
838 }
839 
840 /*************************************************************/
841 
842 int
843 parse_results(struct iperf_test *test, char *results)
844 {
845     int sid, cerror, pcount;
846     double jitter;
847     char *strp;
848     iperf_size_t bytes_transferred;
849     struct iperf_stream *sp;
850 
851     for (strp = results; *strp; strp = strchr(strp, '\n')+1) {
852         sscanf(strp, "%d:%llu,%lf,%d,%d\n", &sid, &bytes_transferred, &jitter,
853             &cerror, &pcount);
854         SLIST_FOREACH(sp, &test->streams, streams)
855             if (sp->id == sid) break;
856         if (sp == NULL) {
857             i_errno = IESTREAMID;
858             return (-1);
859         }
860         if ((test->role == 'c' && !test->reverse) || (test->role == 's' && test->reverse)) {
861             sp->jitter = jitter;
862             sp->cnt_error = cerror;
863             sp->packet_count = pcount;
864             sp->result->bytes_received = bytes_transferred;
865         } else
866             sp->result->bytes_sent = bytes_transferred;
867     }
868 
869     return (0);
870 }
871 
872 
873 /*************************************************************/
874 /**
875  * add_to_interval_list -- adds new interval to the interval_list
876  *
877  */
878 
879 void
880 add_to_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results * new)
881 {
882     struct iperf_interval_results *ip = NULL;
883 
884     ip = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results));
885     memcpy(ip, new, sizeof(struct iperf_interval_results));
886     ip->next = NULL;
887 
888     if (rp->interval_results == NULL) {	/* if 1st interval */
889         rp->interval_results = ip;
890         rp->last_interval_results = ip; /* pointer to last element in list */
891     } else { /* add to end of list */
892         rp->last_interval_results->next = ip;
893         rp->last_interval_results = ip;
894     }
895 }
896 
897 
898 /************************************************************/
899 
900 /**
901  * connect_msg -- displays connection message
902  * denoting sender/receiver details
903  *
904  */
905 
906 void
907 connect_msg(struct iperf_stream *sp)
908 {
909     char ipl[INET6_ADDRSTRLEN], ipr[INET6_ADDRSTRLEN];
910     int lport, rport, domain = sp->settings->domain;
911 
912     if (domain == AF_INET) {
913         inet_ntop(domain, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
914         inet_ntop(domain, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
915         lport = ntohs(((struct sockaddr_in *) &sp->local_addr)->sin_port);
916         rport = ntohs(((struct sockaddr_in *) &sp->remote_addr)->sin_port);
917     } else {
918         inet_ntop(domain, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
919         inet_ntop(domain, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
920         lport = ntohs(((struct sockaddr_in6 *) &sp->local_addr)->sin6_port);
921         rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
922     }
923 
924     printf("[%3d] local %s port %d connected to %s port %d\n",
925         sp->socket, ipl, lport, ipr, rport);
926 }
927 
928 
929 /**************************************************************************/
930 
931 struct iperf_test *
932 iperf_new_test()
933 {
934     struct iperf_test *test;
935 
936     test = (struct iperf_test *) malloc(sizeof(struct iperf_test));
937     if (!test) {
938         i_errno = IENEWTEST;
939         return (NULL);
940     }
941     /* initialize everything to zero */
942     memset(test, 0, sizeof(struct iperf_test));
943 
944     test->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings));
945     memset(test->settings, 0, sizeof(struct iperf_settings));
946 
947     return (test);
948 }
949 
950 /**************************************************************************/
951 int
952 iperf_defaults(struct iperf_test * testp)
953 {
954     testp->duration = DURATION;
955     testp->server_port = PORT;
956     testp->ctrl_sck = -1;
957     testp->prot_listener = -1;
958 
959     testp->stats_callback = iperf_stats_callback;
960     testp->reporter_callback = iperf_reporter_callback;
961 
962     testp->stats_interval = 0;
963     testp->reporter_interval = 0;
964     testp->num_streams = 1;
965 
966     testp->settings->domain = AF_INET;
967     testp->settings->unit_format = 'a';
968     testp->settings->socket_bufsize = 0;	/* use autotuning */
969     testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
970     testp->settings->rate = RATE;	/* UDP only */
971     testp->settings->mss = 0;
972     testp->settings->bytes = 0;
973     memset(testp->cookie, 0, COOKIE_SIZE);
974 
975     /* Set up protocol list */
976     SLIST_INIT(&testp->streams);
977     SLIST_INIT(&testp->protocols);
978 
979     struct protocol *tcp, *udp;
980     tcp = (struct protocol *) malloc(sizeof(struct protocol));
981     if (!tcp)
982         return (-1);
983     memset(tcp, 0, sizeof(struct protocol));
984     udp = (struct protocol *) malloc(sizeof(struct protocol));
985     if (!udp)
986         return (-1);
987     memset(udp, 0, sizeof(struct protocol));
988 
989     tcp->id = Ptcp;
990     tcp->name = "TCP";
991     tcp->accept = iperf_tcp_accept;
992     tcp->listen = iperf_tcp_listen;
993     tcp->connect = iperf_tcp_connect;
994     tcp->send = iperf_tcp_send;
995     tcp->recv = iperf_tcp_recv;
996     tcp->init = NULL;
997     SLIST_INSERT_HEAD(&testp->protocols, tcp, protocols);
998 
999     udp->id = Pudp;
1000     udp->name = "UDP";
1001     udp->accept = iperf_udp_accept;
1002     udp->listen = iperf_udp_listen;
1003     udp->connect = iperf_udp_connect;
1004     udp->send = iperf_udp_send;
1005     udp->recv = iperf_udp_recv;
1006     udp->init = iperf_udp_init;
1007     SLIST_INSERT_AFTER(tcp, udp, protocols);
1008 
1009     set_protocol(testp, Ptcp);
1010 
1011     testp->on_new_stream = iperf_on_new_stream;
1012     testp->on_test_start = iperf_on_test_start;
1013     testp->on_connect = iperf_on_connect;
1014     testp->on_test_finish = iperf_on_test_finish;
1015 
1016     return (0);
1017 }
1018 
1019 
1020 /**************************************************************************/
1021 void
1022 iperf_free_test(struct iperf_test * test)
1023 {
1024     struct protocol *prot;
1025     struct iperf_stream *sp;
1026 
1027     /* Free streams */
1028     while (!SLIST_EMPTY(&test->streams)) {
1029         sp = SLIST_FIRST(&test->streams);
1030         SLIST_REMOVE_HEAD(&test->streams, streams);
1031         iperf_free_stream(sp);
1032     }
1033 
1034     free(test->server_hostname);
1035     free(test->bind_address);
1036     free(test->settings);
1037     free_timer(test->timer);
1038     free_timer(test->stats_timer);
1039     free_timer(test->reporter_timer);
1040 
1041     /* Free protocol list */
1042     while (!SLIST_EMPTY(&test->protocols)) {
1043         prot = SLIST_FIRST(&test->protocols);
1044         SLIST_REMOVE_HEAD(&test->protocols, protocols);
1045         free(prot);
1046     }
1047 
1048     /* XXX: Why are we setting these values to NULL? */
1049     // test->streams = NULL;
1050     test->stats_callback = NULL;
1051     test->reporter_callback = NULL;
1052     free(test);
1053 }
1054 
1055 
1056 void
1057 iperf_reset_test(struct iperf_test *test)
1058 {
1059     struct iperf_stream *sp;
1060 
1061     /* Free streams */
1062     while (!SLIST_EMPTY(&test->streams)) {
1063         sp = SLIST_FIRST(&test->streams);
1064         SLIST_REMOVE_HEAD(&test->streams, streams);
1065         iperf_free_stream(sp);
1066     }
1067     free_timer(test->timer);
1068     free_timer(test->stats_timer);
1069     free_timer(test->reporter_timer);
1070     test->timer = NULL;
1071     test->stats_timer = NULL;
1072     test->reporter_timer = NULL;
1073 
1074     SLIST_INIT(&test->streams);
1075 
1076     test->role = 's';
1077     set_protocol(test, Ptcp);
1078     test->duration = DURATION;
1079     test->state = 0;
1080     test->server_hostname = NULL;
1081 
1082     test->ctrl_sck = -1;
1083     test->prot_listener = -1;
1084 
1085     test->bytes_sent = 0;
1086 
1087     test->reverse = 0;
1088     test->no_delay = 0;
1089 
1090     FD_ZERO(&test->read_set);
1091     FD_ZERO(&test->write_set);
1092 
1093     test->num_streams = 1;
1094     test->settings->socket_bufsize = 0;
1095     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
1096     test->settings->rate = RATE;   /* UDP only */
1097     test->settings->mss = 0;
1098     memset(test->cookie, 0, COOKIE_SIZE);
1099 }
1100 
1101 
1102 /**************************************************************************/
1103 
1104 /**
1105  * iperf_stats_callback -- handles the statistic gathering for both the client and server
1106  *
1107  * XXX: This function needs to be updated to reflect the new code
1108  */
1109 
1110 
1111 void
1112 iperf_stats_callback(struct iperf_test * test)
1113 {
1114     struct iperf_stream *sp;
1115     struct iperf_stream_result *rp = NULL;
1116     struct iperf_interval_results *ip = NULL, temp;
1117 
1118     SLIST_FOREACH(sp, &test->streams, streams) {
1119         rp = sp->result;
1120 
1121         if ((test->role == 'c' && !test->reverse) || (test->role == 's' && test->reverse))
1122             temp.bytes_transferred = rp->bytes_sent_this_interval;
1123         else
1124             temp.bytes_transferred = rp->bytes_received_this_interval;
1125 
1126         ip = sp->result->interval_results;
1127         /* result->end_time contains timestamp of previous interval */
1128         if ( ip != NULL ) /* not the 1st interval */
1129             memcpy(&temp.interval_start_time, &sp->result->end_time, sizeof(struct timeval));
1130         else /* or use timestamp from beginning */
1131             memcpy(&temp.interval_start_time, &sp->result->start_time, sizeof(struct timeval));
1132         /* now save time of end of this interval */
1133         gettimeofday(&sp->result->end_time, NULL);
1134         memcpy(&temp.interval_end_time, &sp->result->end_time, sizeof(struct timeval));
1135         temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);
1136         //temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);
1137         if (test->tcp_info)
1138             get_tcpinfo(test, &temp);
1139         add_to_interval_list(rp, &temp);
1140         rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
1141 
1142     }
1143 
1144 }
1145 
1146 /**************************************************************************/
1147 
1148 /**
1149  * iperf_reporter_callback -- handles the report printing
1150  *
1151  */
1152 
1153 void
1154 iperf_reporter_callback(struct iperf_test * test)
1155 {
1156     int total_packets = 0, lost_packets = 0;
1157     char ubuf[UNIT_LEN];
1158     char nbuf[UNIT_LEN];
1159     struct iperf_stream *sp = NULL;
1160     iperf_size_t bytes = 0, bytes_sent = 0, bytes_received = 0;
1161     iperf_size_t total_sent = 0, total_received = 0;
1162     double start_time, end_time, avg_jitter;
1163     struct iperf_interval_results *ip = NULL;
1164 
1165     switch (test->state) {
1166         case TEST_RUNNING:
1167         case STREAM_RUNNING:
1168             /* print interval results for each stream */
1169             SLIST_FOREACH(sp, &test->streams, streams) {
1170                 print_interval_results(test, sp);
1171                 bytes += sp->result->interval_results->bytes_transferred; /* sum up all streams */
1172             }
1173             if (bytes <=0 ) { /* this can happen if timer goes off just when client exits */
1174                 fprintf(stderr, "error: bytes <= 0!\n");
1175                 break;
1176             }
1177             /* next build string with sum of all streams */
1178             if (test->num_streams > 1) {
1179                 sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
1180                 ip = sp->result->last_interval_results;	/* use 1st stream for timing info */
1181 
1182                 unit_snprintf(ubuf, UNIT_LEN, (double) (bytes), 'A');
1183                 unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / ip->interval_duration),
1184                         test->settings->unit_format);
1185 
1186                 start_time = timeval_diff(&sp->result->start_time,&ip->interval_start_time);
1187                 end_time = timeval_diff(&sp->result->start_time,&ip->interval_end_time);
1188                 printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
1189 
1190 #if defined(linux) || defined(__FreeBSD__)			/* is it usful to figure out a way so sum * TCP_info acrross multiple streams? */
1191                 if (test->tcp_info)
1192                     print_tcpinfo(ip);
1193 #endif
1194             }
1195             break;
1196         case DISPLAY_RESULTS:
1197             /* print final summary for all intervals */
1198 
1199             printf(report_bw_header);
1200 
1201             start_time = 0.;
1202             sp = SLIST_FIRST(&test->streams);
1203             end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time);
1204             SLIST_FOREACH(sp, &test->streams, streams) {
1205                 bytes_sent = sp->result->bytes_sent;
1206                 bytes_received = sp->result->bytes_received;
1207                 total_sent += bytes_sent;
1208                 total_received += bytes_received;
1209 
1210                 if (test->protocol->id == Pudp) {
1211                     total_packets += sp->packet_count;
1212                     lost_packets += sp->cnt_error;
1213                     avg_jitter += sp->jitter;
1214                 }
1215 
1216                 if (bytes_sent > 0) {
1217                     unit_snprintf(ubuf, UNIT_LEN, (double) (bytes_sent), 'A');
1218                     unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_sent / end_time), test->settings->unit_format);
1219                     if (test->protocol->id == Ptcp) {
1220                         printf("      Sent\n");
1221                         printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
1222 
1223 #if defined(linux) || defined(__FreeBSD__)
1224                         if (test->tcp_info) {
1225                             ip = sp->result->last_interval_results;
1226                             print_tcpinfo(ip);
1227                         }
1228 #endif
1229                     } else {
1230                         printf(report_bw_jitter_loss_format, sp->socket, start_time,
1231                                 end_time, ubuf, nbuf, sp->jitter * 1000, sp->cnt_error,
1232                                 sp->packet_count, (double) (100.0 * sp->cnt_error / sp->packet_count));
1233                         if (test->role == 'c') {
1234                             printf(report_datagrams, sp->socket, sp->packet_count);
1235                         }
1236                         if (sp->outoforder_packets > 0)
1237                             printf(report_sum_outoforder, start_time, end_time, sp->cnt_error);
1238                     }
1239                 }
1240                 if (bytes_received > 0) {
1241                     unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
1242                     unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_received / end_time), test->settings->unit_format);
1243                     if (test->protocol->id == Ptcp) {
1244                         printf("      Received\n");
1245                         printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
1246                     }
1247                 }
1248             }
1249 
1250             if (test->num_streams > 1) {
1251                 unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
1252                 unit_snprintf(nbuf, UNIT_LEN, (double) total_sent / end_time, test->settings->unit_format);
1253                 if (test->protocol->id == Ptcp) {
1254                     printf("      Total sent\n");
1255                     printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
1256                     unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
1257                     unit_snprintf(nbuf, UNIT_LEN, (double) (total_received / end_time), test->settings->unit_format);
1258                     printf("      Total received\n");
1259                     printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
1260                 } else {
1261                     avg_jitter /= test->num_streams;
1262                     printf(report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, avg_jitter,
1263                         lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets));
1264                 }
1265             }
1266             break;
1267     }
1268 
1269 }
1270 
1271 /**************************************************************************/
1272 void
1273 print_interval_results(struct iperf_test * test, struct iperf_stream * sp)
1274 {
1275     char ubuf[UNIT_LEN];
1276     char nbuf[UNIT_LEN];
1277     double st = 0., et = 0.;
1278     struct iperf_interval_results *ir = NULL;
1279 
1280     ir = sp->result->last_interval_results; /* get last entry in linked list */
1281     if (ir == NULL) {
1282         printf("print_interval_results Error: interval_results = NULL \n");
1283         return;
1284     }
1285     if (sp == SLIST_FIRST(&test->streams)) {
1286         printf(report_bw_header);
1287     }
1288 
1289     unit_snprintf(ubuf, UNIT_LEN, (double) (ir->bytes_transferred), 'A');
1290     unit_snprintf(nbuf, UNIT_LEN, (double) (ir->bytes_transferred / ir->interval_duration),
1291             test->settings->unit_format);
1292 
1293     st = timeval_diff(&sp->result->start_time,&ir->interval_start_time);
1294     et = timeval_diff(&sp->result->start_time,&ir->interval_end_time);
1295 
1296     printf(report_bw_format, sp->socket, st, et, ubuf, nbuf);
1297 
1298 #if defined(linux) || defined(__FreeBSD__)
1299     if (test->tcp_info)
1300         print_tcpinfo(ir);
1301 #endif
1302 }
1303 
1304 /**************************************************************************/
1305 void
1306 iperf_free_stream(struct iperf_stream * sp)
1307 {
1308     struct iperf_interval_results *ip, *np;
1309 
1310     /* XXX: need to free interval list too! */
1311     free(sp->buffer);
1312     for (ip = sp->result->interval_results; ip; ip = np) {
1313         np = ip->next;
1314         free(ip);
1315     }
1316     free(sp->result);
1317     free(sp->send_timer);
1318     free(sp);
1319 }
1320 
1321 /**************************************************************************/
1322 struct iperf_stream *
1323 iperf_new_stream(struct iperf_test *test, int s)
1324 {
1325     int i;
1326     struct iperf_stream *sp;
1327 
1328     sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
1329     if (!sp) {
1330         i_errno = IECREATESTREAM;
1331         return (NULL);
1332     }
1333 
1334     memset(sp, 0, sizeof(struct iperf_stream));
1335 
1336     sp->buffer = (char *) malloc(test->settings->blksize);
1337     sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
1338     sp->settings = test->settings;
1339 
1340     if (!sp->buffer) {
1341         i_errno = IECREATESTREAM;
1342         return (NULL);
1343     }
1344     if (!sp->result) {
1345         i_errno = IECREATESTREAM;
1346         return (NULL);
1347     }
1348 
1349     memset(sp->result, 0, sizeof(struct iperf_stream_result));
1350 
1351     /* Randomize the buffer */
1352     srandom(time(NULL));
1353     for (i = 0; i < test->settings->blksize; ++i)
1354         sp->buffer[i] = random();
1355 
1356     /* Set socket */
1357     sp->socket = s;
1358 
1359     sp->snd = test->protocol->send;
1360     sp->rcv = test->protocol->recv;
1361 
1362     /* Initialize stream */
1363     if (iperf_init_stream(sp, test) < 0)
1364         return (NULL);
1365     iperf_add_stream(test, sp);
1366 
1367     return (sp);
1368 }
1369 
1370 /**************************************************************************/
1371 int
1372 iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
1373 {
1374     socklen_t len;
1375     int opt;
1376 
1377     len = sizeof(struct sockaddr_storage);
1378     if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
1379         i_errno = IEINITSTREAM;
1380         return (-1);
1381     }
1382     len = sizeof(struct sockaddr_storage);
1383     if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
1384         i_errno = IEINITSTREAM;
1385         return (-1);
1386     }
1387     /* Set IP TOS */
1388     if ((opt = test->settings->tos)) {
1389         if (test->settings->domain == AF_INET6) {
1390 #ifdef IPV6_TCLASS
1391             if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
1392                 i_errno = IESETCOS;
1393                 return (-1);
1394             }
1395 #else
1396             i_errno = IESETCOS;
1397             return (-1);
1398 #endif
1399         } else {
1400             if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
1401                 i_errno = IESETTOS;
1402                 return (-1);
1403             }
1404         }
1405     }
1406 
1407     return (0);
1408 }
1409 
1410 /**************************************************************************/
1411 void
1412 iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp)
1413 {
1414     int i;
1415     struct iperf_stream *n, *prev;
1416 
1417     if (SLIST_EMPTY(&test->streams)) {
1418         SLIST_INSERT_HEAD(&test->streams, sp, streams);
1419         sp->id = 1;
1420     } else {
1421         // for (n = test->streams, i = 2; n->next; n = n->next, ++i);
1422         i = 2;
1423         SLIST_FOREACH(n, &test->streams, streams) {
1424             prev = n;
1425             ++i;
1426         }
1427         SLIST_INSERT_AFTER(prev, sp, streams);
1428         sp->id = i;
1429     }
1430 }
1431 
1432 void
1433 sig_handler(int sig)
1434 {
1435    longjmp(env, 1);
1436 }
1437 
1438