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