Annotation of embedaddon/iperf/src/iperf_api.c, revision 1.1.1.2

1.1       misho       1: /*
1.1.1.2 ! misho       2:  * iperf, Copyright (c) 2014-2020, The Regents of the University of
1.1       misho       3:  * California, through Lawrence Berkeley National Laboratory (subject
                      4:  * to receipt of any required approvals from the U.S. Dept. of
                      5:  * Energy).  All rights reserved.
                      6:  *
                      7:  * If you have questions about your rights to use or distribute this
                      8:  * software, please contact Berkeley Lab's Technology Transfer
                      9:  * Department at TTD@lbl.gov.
                     10:  *
                     11:  * NOTICE.  This software is owned by the U.S. Department of Energy.
                     12:  * As such, the U.S. Government has been granted for itself and others
                     13:  * acting on its behalf a paid-up, nonexclusive, irrevocable,
                     14:  * worldwide license in the Software to reproduce, prepare derivative
                     15:  * works, and perform publicly and display publicly.  Beginning five
                     16:  * (5) years after the date permission to assert copyright is obtained
                     17:  * from the U.S. Department of Energy, and subject to any subsequent
                     18:  * five (5) year renewals, the U.S. Government is granted for itself
                     19:  * and others acting on its behalf a paid-up, nonexclusive,
                     20:  * irrevocable, worldwide license in the Software to reproduce,
                     21:  * prepare derivative works, distribute copies to the public, perform
                     22:  * publicly and display publicly, and to permit others to do so.
                     23:  *
                     24:  * This code is distributed under a BSD style license, see the LICENSE file
                     25:  * for complete information.
                     26:  */
1.1.1.2 ! misho      27: #ifndef _GNU_SOURCE
        !            28: # define _GNU_SOURCE
        !            29: #endif
1.1       misho      30: #define __USE_GNU
                     31: 
                     32: #include "iperf_config.h"
                     33: 
                     34: #include <stdio.h>
                     35: #include <stdlib.h>
                     36: #include <string.h>
1.1.1.2 ! misho      37: #include <time.h>
1.1       misho      38: #include <getopt.h>
                     39: #include <errno.h>
                     40: #include <signal.h>
                     41: #include <unistd.h>
                     42: #include <assert.h>
                     43: #include <fcntl.h>
                     44: #include <sys/socket.h>
                     45: #include <sys/types.h>
                     46: #include <netinet/in.h>
                     47: #include <arpa/inet.h>
                     48: #include <netdb.h>
                     49: #ifdef HAVE_STDINT_H
                     50: #include <stdint.h>
                     51: #endif
                     52: #include <netinet/tcp.h>
                     53: #include <sys/time.h>
                     54: #include <sys/resource.h>
                     55: #include <sys/mman.h>
                     56: #include <sys/stat.h>
                     57: #include <sched.h>
                     58: #include <setjmp.h>
                     59: #include <stdarg.h>
1.1.1.2 ! misho      60: #include <math.h>
1.1       misho      61: 
                     62: #if defined(HAVE_CPUSET_SETAFFINITY)
                     63: #include <sys/param.h>
                     64: #include <sys/cpuset.h>
                     65: #endif /* HAVE_CPUSET_SETAFFINITY */
                     66: 
1.1.1.2 ! misho      67: #if defined(__CYGWIN__) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
        !            68: #define CPU_SETSIZE __CPU_SETSIZE
        !            69: #endif /* __CYGWIN__, _WIN32, _WIN64, __WINDOWS__ */
        !            70: 
        !            71: #if defined(HAVE_SETPROCESSAFFINITYMASK)
        !            72: #include <Windows.h>
        !            73: #endif /* HAVE_SETPROCESSAFFINITYMASK */
        !            74: 
1.1       misho      75: #include "net.h"
                     76: #include "iperf.h"
                     77: #include "iperf_api.h"
                     78: #include "iperf_udp.h"
                     79: #include "iperf_tcp.h"
1.1.1.2 ! misho      80: #if defined(HAVE_SCTP_H)
1.1       misho      81: #include "iperf_sctp.h"
1.1.1.2 ! misho      82: #endif /* HAVE_SCTP_H */
1.1       misho      83: #include "timer.h"
                     84: 
                     85: #include "cjson.h"
                     86: #include "units.h"
                     87: #include "iperf_util.h"
                     88: #include "iperf_locale.h"
                     89: #include "version.h"
1.1.1.2 ! misho      90: #if defined(HAVE_SSL)
        !            91: #include <openssl/bio.h>
        !            92: #include "iperf_auth.h"
        !            93: #endif /* HAVE_SSL */
1.1       misho      94: 
                     95: /* Forwards. */
                     96: static int send_parameters(struct iperf_test *test);
                     97: static int get_parameters(struct iperf_test *test);
                     98: static int send_results(struct iperf_test *test);
                     99: static int get_results(struct iperf_test *test);
                    100: static int diskfile_send(struct iperf_stream *sp);
                    101: static int diskfile_recv(struct iperf_stream *sp);
                    102: static int JSON_write(int fd, cJSON *json);
                    103: static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams);
                    104: static cJSON *JSON_read(int fd);
                    105: 
                    106: 
                    107: /*************************** Print usage functions ****************************/
                    108: 
                    109: void
                    110: usage()
                    111: {
                    112:     fputs(usage_shortstr, stderr);
                    113: }
                    114: 
                    115: 
                    116: void
1.1.1.2 ! misho     117: usage_long(FILE *f)
1.1       misho     118: {
1.1.1.2 ! misho     119:     fprintf(f, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE);
1.1       misho     120: }
                    121: 
                    122: 
1.1.1.2 ! misho     123: void warning(const char *str)
1.1       misho     124: {
                    125:     fprintf(stderr, "warning: %s\n", str);
                    126: }
                    127: 
                    128: 
                    129: /************** Getter routines for some fields inside iperf_test *************/
                    130: 
                    131: int
                    132: iperf_get_verbose(struct iperf_test *ipt)
                    133: {
                    134:     return ipt->verbose;
                    135: }
                    136: 
                    137: int
                    138: iperf_get_control_socket(struct iperf_test *ipt)
                    139: {
                    140:     return ipt->ctrl_sck;
                    141: }
                    142: 
                    143: int
1.1.1.2 ! misho     144: iperf_get_control_socket_mss(struct iperf_test *ipt)
        !           145: {
        !           146:     return ipt->ctrl_sck_mss;
        !           147: }
        !           148: 
        !           149: int
1.1       misho     150: iperf_get_test_omit(struct iperf_test *ipt)
                    151: {
                    152:     return ipt->omit;
                    153: }
                    154: 
                    155: int
                    156: iperf_get_test_duration(struct iperf_test *ipt)
                    157: {
                    158:     return ipt->duration;
                    159: }
                    160: 
                    161: uint64_t
                    162: iperf_get_test_rate(struct iperf_test *ipt)
                    163: {
                    164:     return ipt->settings->rate;
                    165: }
                    166: 
1.1.1.2 ! misho     167: uint64_t
        !           168: iperf_get_test_bitrate_limit(struct iperf_test *ipt)
        !           169: {
        !           170:     return ipt->settings->bitrate_limit;
        !           171: }
        !           172: 
        !           173: double
        !           174: iperf_get_test_bitrate_limit_interval(struct iperf_test *ipt)
        !           175: {
        !           176:     return ipt->settings->bitrate_limit_interval;
        !           177: }
        !           178: 
        !           179: int
        !           180: iperf_get_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt)
        !           181: {
        !           182:     return ipt->settings->bitrate_limit_stats_per_interval;
        !           183: }
        !           184: 
        !           185: uint64_t
        !           186: iperf_get_test_fqrate(struct iperf_test *ipt)
        !           187: {
        !           188:     return ipt->settings->fqrate;
        !           189: }
        !           190: 
        !           191: int
        !           192: iperf_get_test_pacing_timer(struct iperf_test *ipt)
        !           193: {
        !           194:     return ipt->settings->pacing_timer;
        !           195: }
        !           196: 
        !           197: uint64_t
        !           198: iperf_get_test_bytes(struct iperf_test *ipt)
        !           199: {
        !           200:     return (uint64_t) ipt->settings->bytes;
        !           201: }
        !           202: 
        !           203: uint64_t
        !           204: iperf_get_test_blocks(struct iperf_test *ipt)
        !           205: {
        !           206:     return (uint64_t) ipt->settings->blocks;
        !           207: }
        !           208: 
1.1       misho     209: int
                    210: iperf_get_test_burst(struct iperf_test *ipt)
                    211: {
                    212:     return ipt->settings->burst;
                    213: }
                    214: 
                    215: char
                    216: iperf_get_test_role(struct iperf_test *ipt)
                    217: {
                    218:     return ipt->role;
                    219: }
                    220: 
                    221: int
                    222: iperf_get_test_reverse(struct iperf_test *ipt)
                    223: {
                    224:     return ipt->reverse;
                    225: }
                    226: 
                    227: int
                    228: iperf_get_test_blksize(struct iperf_test *ipt)
                    229: {
                    230:     return ipt->settings->blksize;
                    231: }
                    232: 
                    233: FILE *
                    234: iperf_get_test_outfile (struct iperf_test *ipt)
                    235: {
                    236:     return ipt->outfile;
                    237: }
                    238: 
                    239: int
                    240: iperf_get_test_socket_bufsize(struct iperf_test *ipt)
                    241: {
                    242:     return ipt->settings->socket_bufsize;
                    243: }
                    244: 
                    245: double
                    246: iperf_get_test_reporter_interval(struct iperf_test *ipt)
                    247: {
                    248:     return ipt->reporter_interval;
                    249: }
                    250: 
                    251: double
                    252: iperf_get_test_stats_interval(struct iperf_test *ipt)
                    253: {
                    254:     return ipt->stats_interval;
                    255: }
                    256: 
                    257: int
                    258: iperf_get_test_num_streams(struct iperf_test *ipt)
                    259: {
                    260:     return ipt->num_streams;
                    261: }
                    262: 
                    263: int
1.1.1.2 ! misho     264: iperf_get_test_timestamps(struct iperf_test *ipt)
        !           265: {
        !           266:     return ipt->timestamps;
        !           267: }
        !           268: 
        !           269: const char *
        !           270: iperf_get_test_timestamp_format(struct iperf_test *ipt)
        !           271: {
        !           272:     return ipt->timestamp_format;
        !           273: }
        !           274: 
        !           275: int
        !           276: iperf_get_test_repeating_payload(struct iperf_test *ipt)
        !           277: {
        !           278:     return ipt->repeating_payload;
        !           279: }
        !           280: 
        !           281: int
1.1       misho     282: iperf_get_test_server_port(struct iperf_test *ipt)
                    283: {
                    284:     return ipt->server_port;
                    285: }
                    286: 
                    287: char*
                    288: iperf_get_test_server_hostname(struct iperf_test *ipt)
                    289: {
                    290:     return ipt->server_hostname;
                    291: }
                    292: 
                    293: char*
                    294: iperf_get_test_template(struct iperf_test *ipt)
                    295: {
                    296:     return ipt->tmp_template;
                    297: }
                    298: 
                    299: int
                    300: iperf_get_test_protocol_id(struct iperf_test *ipt)
                    301: {
                    302:     return ipt->protocol->id;
                    303: }
                    304: 
                    305: int
                    306: iperf_get_test_json_output(struct iperf_test *ipt)
                    307: {
                    308:     return ipt->json_output;
                    309: }
                    310: 
                    311: char *
                    312: iperf_get_test_json_output_string(struct iperf_test *ipt)
                    313: {
                    314:     return ipt->json_output_string;
                    315: }
                    316: 
                    317: int
                    318: iperf_get_test_zerocopy(struct iperf_test *ipt)
                    319: {
                    320:     return ipt->zerocopy;
                    321: }
                    322: 
                    323: int
                    324: iperf_get_test_get_server_output(struct iperf_test *ipt)
                    325: {
                    326:     return ipt->get_server_output;
                    327: }
                    328: 
                    329: char
                    330: iperf_get_test_unit_format(struct iperf_test *ipt)
                    331: {
                    332:     return ipt->settings->unit_format;
                    333: }
                    334: 
                    335: char *
                    336: iperf_get_test_bind_address(struct iperf_test *ipt)
                    337: {
                    338:     return ipt->bind_address;
                    339: }
                    340: 
                    341: int
                    342: iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
                    343: {
                    344:     return ipt->udp_counters_64bit;
                    345: }
                    346: 
                    347: int
                    348: iperf_get_test_one_off(struct iperf_test *ipt)
                    349: {
                    350:     return ipt->one_off;
                    351: }
                    352: 
                    353: int
1.1.1.2 ! misho     354: iperf_get_test_tos(struct iperf_test *ipt)
        !           355: {
        !           356:     return ipt->settings->tos;
        !           357: }
        !           358: 
        !           359: char *
        !           360: iperf_get_test_extra_data(struct iperf_test *ipt)
        !           361: {
        !           362:     return ipt->extra_data;
        !           363: }
        !           364: 
        !           365: static const char iperf_version[] = IPERF_VERSION;
        !           366: char *
        !           367: iperf_get_iperf_version(void)
        !           368: {
        !           369:     return (char*)iperf_version;
        !           370: }
        !           371: 
        !           372: int
        !           373: iperf_get_test_no_delay(struct iperf_test *ipt)
1.1       misho     374: {
1.1.1.2 ! misho     375:     return ipt->no_delay;
        !           376: }
        !           377: 
        !           378: int
        !           379: iperf_get_test_connect_timeout(struct iperf_test *ipt)
        !           380: {
        !           381:     return ipt->settings->connect_timeout;
1.1       misho     382: }
                    383: 
                    384: /************** Setter routines for some fields inside iperf_test *************/
                    385: 
                    386: void
                    387: iperf_set_verbose(struct iperf_test *ipt, int verbose)
                    388: {
                    389:     ipt->verbose = verbose;
                    390: }
                    391: 
                    392: void
                    393: iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
                    394: {
                    395:     ipt->ctrl_sck = ctrl_sck;
                    396: }
                    397: 
                    398: void
                    399: iperf_set_test_omit(struct iperf_test *ipt, int omit)
                    400: {
                    401:     ipt->omit = omit;
                    402: }
                    403: 
                    404: void
                    405: iperf_set_test_duration(struct iperf_test *ipt, int duration)
                    406: {
                    407:     ipt->duration = duration;
                    408: }
                    409: 
                    410: void
                    411: iperf_set_test_reporter_interval(struct iperf_test *ipt, double reporter_interval)
                    412: {
                    413:     ipt->reporter_interval = reporter_interval;
                    414: }
                    415: 
                    416: void
                    417: iperf_set_test_stats_interval(struct iperf_test *ipt, double stats_interval)
                    418: {
                    419:     ipt->stats_interval = stats_interval;
                    420: }
                    421: 
                    422: void
                    423: iperf_set_test_state(struct iperf_test *ipt, signed char state)
                    424: {
                    425:     ipt->state = state;
                    426: }
                    427: 
                    428: void
                    429: iperf_set_test_blksize(struct iperf_test *ipt, int blksize)
                    430: {
                    431:     ipt->settings->blksize = blksize;
                    432: }
                    433: 
                    434: void
1.1.1.2 ! misho     435: iperf_set_test_logfile(struct iperf_test *ipt, const char *logfile)
        !           436: {
        !           437:     ipt->logfile = strdup(logfile);
        !           438: }
        !           439: 
        !           440: void
1.1       misho     441: iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
                    442: {
                    443:     ipt->settings->rate = rate;
                    444: }
                    445: 
                    446: void
1.1.1.2 ! misho     447: iperf_set_test_bitrate_limit_maximum(struct iperf_test *ipt, uint64_t total_rate)
        !           448: {
        !           449:     ipt->settings->bitrate_limit = total_rate;
        !           450: }
        !           451: 
        !           452: void
        !           453: iperf_set_test_bitrate_limit_interval(struct iperf_test *ipt, uint64_t bitrate_limit_interval)
        !           454: {
        !           455:     ipt->settings->bitrate_limit_interval = bitrate_limit_interval;
        !           456: }
        !           457: 
        !           458: void
        !           459: iperf_set_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt, uint64_t bitrate_limit_stats_per_interval)
        !           460: {
        !           461:     ipt->settings->bitrate_limit_stats_per_interval = bitrate_limit_stats_per_interval;
        !           462: }
        !           463: 
        !           464: void
        !           465: iperf_set_test_fqrate(struct iperf_test *ipt, uint64_t fqrate)
        !           466: {
        !           467:     ipt->settings->fqrate = fqrate;
        !           468: }
        !           469: 
        !           470: void
        !           471: iperf_set_test_pacing_timer(struct iperf_test *ipt, int pacing_timer)
        !           472: {
        !           473:     ipt->settings->pacing_timer = pacing_timer;
        !           474: }
        !           475: 
        !           476: void
        !           477: iperf_set_test_bytes(struct iperf_test *ipt, uint64_t bytes)
        !           478: {
        !           479:     ipt->settings->bytes = (iperf_size_t) bytes;
        !           480: }
        !           481: 
        !           482: void
        !           483: iperf_set_test_blocks(struct iperf_test *ipt, uint64_t blocks)
        !           484: {
        !           485:     ipt->settings->blocks = (iperf_size_t) blocks;
        !           486: }
        !           487: 
        !           488: void
1.1       misho     489: iperf_set_test_burst(struct iperf_test *ipt, int burst)
                    490: {
                    491:     ipt->settings->burst = burst;
                    492: }
                    493: 
                    494: void
1.1.1.2 ! misho     495: iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)
1.1       misho     496: {
1.1.1.2 ! misho     497:     ipt->server_port = srv_port;
1.1       misho     498: }
                    499: 
                    500: void
                    501: iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)
                    502: {
                    503:     ipt->settings->socket_bufsize = socket_bufsize;
                    504: }
                    505: 
                    506: void
                    507: iperf_set_test_num_streams(struct iperf_test *ipt, int num_streams)
                    508: {
                    509:     ipt->num_streams = num_streams;
                    510: }
                    511: 
1.1.1.2 ! misho     512: void
        !           513: iperf_set_test_repeating_payload(struct iperf_test *ipt, int repeating_payload)
        !           514: {
        !           515:     ipt->repeating_payload = repeating_payload;
        !           516: }
        !           517: 
        !           518: void
        !           519: iperf_set_test_timestamps(struct iperf_test *ipt, int timestamps)
        !           520: {
        !           521:     ipt->timestamps = timestamps;
        !           522: }
        !           523: 
        !           524: void
        !           525: iperf_set_test_timestamp_format(struct iperf_test *ipt, const char *tf)
        !           526: {
        !           527:     ipt->timestamp_format = strdup(tf);
        !           528: }
        !           529: 
1.1       misho     530: static void
                    531: check_sender_has_retransmits(struct iperf_test *ipt)
                    532: {
1.1.1.2 ! misho     533:     if (ipt->mode != RECEIVER && ipt->protocol->id == Ptcp && has_tcpinfo_retransmits())
1.1       misho     534:        ipt->sender_has_retransmits = 1;
                    535:     else
                    536:        ipt->sender_has_retransmits = 0;
                    537: }
                    538: 
                    539: void
                    540: iperf_set_test_role(struct iperf_test *ipt, char role)
                    541: {
                    542:     ipt->role = role;
1.1.1.2 ! misho     543:     if (!ipt->reverse) {
        !           544:         if (ipt->bidirectional)
        !           545:             ipt->mode = BIDIRECTIONAL;
        !           546:         else if (role == 'c')
        !           547:             ipt->mode = SENDER;
        !           548:         else if (role == 's')
        !           549:             ipt->mode = RECEIVER;
        !           550:     } else {
        !           551:         if (role == 'c')
        !           552:             ipt->mode = RECEIVER;
        !           553:         else if (role == 's')
        !           554:             ipt->mode = SENDER;
        !           555:     }
1.1       misho     556:     check_sender_has_retransmits(ipt);
                    557: }
                    558: 
                    559: void
1.1.1.2 ! misho     560: iperf_set_test_server_hostname(struct iperf_test *ipt, const char *server_hostname)
1.1       misho     561: {
                    562:     ipt->server_hostname = strdup(server_hostname);
                    563: }
                    564: 
                    565: void
1.1.1.2 ! misho     566: iperf_set_test_template(struct iperf_test *ipt, const char *tmp_template)
1.1       misho     567: {
                    568:     ipt->tmp_template = strdup(tmp_template);
                    569: }
                    570: 
                    571: void
                    572: iperf_set_test_reverse(struct iperf_test *ipt, int reverse)
                    573: {
                    574:     ipt->reverse = reverse;
1.1.1.2 ! misho     575:     if (!ipt->reverse) {
        !           576:         if (ipt->role == 'c')
        !           577:             ipt->mode = SENDER;
        !           578:         else if (ipt->role == 's')
        !           579:             ipt->mode = RECEIVER;
        !           580:     } else {
        !           581:         if (ipt->role == 'c')
        !           582:             ipt->mode = RECEIVER;
        !           583:         else if (ipt->role == 's')
        !           584:             ipt->mode = SENDER;
        !           585:     }
1.1       misho     586:     check_sender_has_retransmits(ipt);
                    587: }
                    588: 
                    589: void
                    590: iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
                    591: {
                    592:     ipt->json_output = json_output;
                    593: }
                    594: 
                    595: int
                    596: iperf_has_zerocopy( void )
                    597: {
                    598:     return has_sendfile();
                    599: }
                    600: 
                    601: void
                    602: iperf_set_test_zerocopy(struct iperf_test *ipt, int zerocopy)
                    603: {
                    604:     ipt->zerocopy = (zerocopy && has_sendfile());
                    605: }
                    606: 
                    607: void
                    608: iperf_set_test_get_server_output(struct iperf_test *ipt, int get_server_output)
                    609: {
                    610:     ipt->get_server_output = get_server_output;
                    611: }
                    612: 
                    613: void
                    614: iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
                    615: {
                    616:     ipt->settings->unit_format = unit_format;
                    617: }
                    618: 
1.1.1.2 ! misho     619: #if defined(HAVE_SSL)
        !           620: void
        !           621: iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username)
        !           622: {
        !           623:     ipt->settings->client_username = strdup(client_username);
        !           624: }
        !           625: 
1.1       misho     626: void
1.1.1.2 ! misho     627: iperf_set_test_client_password(struct iperf_test *ipt, const char *client_password)
1.1       misho     628: {
1.1.1.2 ! misho     629:     ipt->settings->client_password = strdup(client_password);
        !           630: }
        !           631: 
        !           632: void
        !           633: iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, const char *client_rsa_pubkey_base64)
        !           634: {
        !           635:     ipt->settings->client_rsa_pubkey = load_pubkey_from_base64(client_rsa_pubkey_base64);
        !           636: }
        !           637: 
        !           638: void
        !           639: iperf_set_test_server_authorized_users(struct iperf_test *ipt, const char *server_authorized_users)
        !           640: {
        !           641:     ipt->server_authorized_users = strdup(server_authorized_users);
        !           642: }
        !           643: 
        !           644: void
        !           645: iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64)
        !           646: {
        !           647:     ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
        !           648: }
        !           649: #endif // HAVE_SSL
        !           650: 
        !           651: void
        !           652: iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address)
        !           653: {
        !           654:     ipt->bind_address = strdup(bnd_address);
1.1       misho     655: }
                    656: 
                    657: void
                    658: iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
                    659: {
                    660:     ipt->udp_counters_64bit = udp_counters_64bit;
                    661: }
                    662: 
                    663: void
                    664: iperf_set_test_one_off(struct iperf_test *ipt, int one_off)
                    665: {
                    666:     ipt->one_off = one_off;
                    667: }
                    668: 
                    669: void
1.1.1.2 ! misho     670: iperf_set_test_tos(struct iperf_test *ipt, int tos)
1.1       misho     671: {
1.1.1.2 ! misho     672:     ipt->settings->tos = tos;
1.1       misho     673: }
                    674: 
1.1.1.2 ! misho     675: void
        !           676: iperf_set_test_extra_data(struct iperf_test *ipt, const char *dat)
        !           677: {
        !           678:     ipt->extra_data = strdup(dat);
        !           679: }
        !           680: 
        !           681: void
        !           682: iperf_set_test_bidirectional(struct iperf_test* ipt, int bidirectional)
        !           683: {
        !           684:     ipt->bidirectional = bidirectional;
        !           685:     if (bidirectional)
        !           686:         ipt->mode = BIDIRECTIONAL;
        !           687:     else
        !           688:         iperf_set_test_reverse(ipt, ipt->reverse);
        !           689: }
        !           690: 
        !           691: void
        !           692: iperf_set_test_no_delay(struct iperf_test* ipt, int no_delay)
        !           693: {
        !           694:     ipt->no_delay = no_delay;
        !           695: }
        !           696: 
        !           697: void
        !           698: iperf_set_test_connect_timeout(struct iperf_test* ipt, int ct)
        !           699: {
        !           700:     ipt->settings->connect_timeout = ct;
        !           701: }
        !           702: 
        !           703: 
1.1       misho     704: /********************** Get/set test protocol structure ***********************/
                    705: 
                    706: struct protocol *
                    707: get_protocol(struct iperf_test *test, int prot_id)
                    708: {
                    709:     struct protocol *prot;
                    710: 
                    711:     SLIST_FOREACH(prot, &test->protocols, protocols) {
                    712:         if (prot->id == prot_id)
                    713:             break;
                    714:     }
                    715: 
                    716:     if (prot == NULL)
                    717:         i_errno = IEPROTOCOL;
                    718: 
                    719:     return prot;
                    720: }
                    721: 
                    722: int
                    723: set_protocol(struct iperf_test *test, int prot_id)
                    724: {
                    725:     struct protocol *prot = NULL;
                    726: 
                    727:     SLIST_FOREACH(prot, &test->protocols, protocols) {
                    728:         if (prot->id == prot_id) {
                    729:             test->protocol = prot;
                    730:            check_sender_has_retransmits(test);
                    731:             return 0;
                    732:         }
                    733:     }
                    734: 
                    735:     i_errno = IEPROTOCOL;
                    736:     return -1;
                    737: }
                    738: 
                    739: 
                    740: /************************** Iperf callback functions **************************/
                    741: 
                    742: void
                    743: iperf_on_new_stream(struct iperf_stream *sp)
                    744: {
                    745:     connect_msg(sp);
                    746: }
                    747: 
                    748: void
                    749: iperf_on_test_start(struct iperf_test *test)
                    750: {
                    751:     if (test->json_output) {
1.1.1.2 ! misho     752:        cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s  num_streams: %d  blksize: %d  omit: %d  duration: %d  bytes: %d  blocks: %d  reverse: %d  tos: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->omit, (int64_t) test->duration, (int64_t) test->settings->bytes, (int64_t) test->settings->blocks, test->reverse?(int64_t)1:(int64_t)0, (int64_t) test->settings->tos));
1.1       misho     753:     } else {
                    754:        if (test->verbose) {
                    755:            if (test->settings->bytes)
1.1.1.2 ! misho     756:                iperf_printf(test, test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->bytes, test->settings->tos);
1.1       misho     757:            else if (test->settings->blocks)
1.1.1.2 ! misho     758:                iperf_printf(test, test_start_blocks, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->blocks, test->settings->tos);
1.1       misho     759:            else
1.1.1.2 ! misho     760:                iperf_printf(test, test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->duration, test->settings->tos);
1.1       misho     761:        }
                    762:     }
                    763: }
                    764: 
                    765: /* This converts an IPv6 string address from IPv4-mapped format into regular
                    766: ** old IPv4 format, which is easier on the eyes of network veterans.
                    767: **
                    768: ** If the v6 address is not v4-mapped it is left alone.
                    769: */
                    770: static void
                    771: mapped_v4_to_regular_v4(char *str)
                    772: {
                    773:     char *prefix = "::ffff:";
                    774:     int prefix_len;
                    775: 
                    776:     prefix_len = strlen(prefix);
                    777:     if (strncmp(str, prefix, prefix_len) == 0) {
                    778:        int str_len = strlen(str);
                    779:        memmove(str, str + prefix_len, str_len - prefix_len + 1);
                    780:     }
                    781: }
                    782: 
                    783: void
                    784: iperf_on_connect(struct iperf_test *test)
                    785: {
                    786:     time_t now_secs;
1.1.1.2 ! misho     787:     const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S %Z";
1.1       misho     788:     char now_str[100];
                    789:     char ipr[INET6_ADDRSTRLEN];
                    790:     int port;
                    791:     struct sockaddr_storage sa;
                    792:     struct sockaddr_in *sa_inP;
                    793:     struct sockaddr_in6 *sa_in6P;
                    794:     socklen_t len;
                    795: 
                    796:     now_secs = time((time_t*) 0);
                    797:     (void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));
                    798:     if (test->json_output)
                    799:        cJSON_AddItemToObject(test->json_start, "timestamp", iperf_json_printf("time: %s  timesecs: %d", now_str, (int64_t) now_secs));
                    800:     else if (test->verbose)
1.1.1.2 ! misho     801:        iperf_printf(test, report_time, now_str);
1.1       misho     802: 
                    803:     if (test->role == 'c') {
                    804:        if (test->json_output)
                    805:            cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s  port: %d", test->server_hostname, (int64_t) test->server_port));
                    806:        else {
1.1.1.2 ! misho     807:            iperf_printf(test, report_connecting, test->server_hostname, test->server_port);
1.1       misho     808:            if (test->reverse)
1.1.1.2 ! misho     809:                iperf_printf(test, report_reverse, test->server_hostname);
1.1       misho     810:        }
                    811:     } else {
                    812:         len = sizeof(sa);
                    813:         getpeername(test->ctrl_sck, (struct sockaddr *) &sa, &len);
                    814:         if (getsockdomain(test->ctrl_sck) == AF_INET) {
                    815:            sa_inP = (struct sockaddr_in *) &sa;
                    816:             inet_ntop(AF_INET, &sa_inP->sin_addr, ipr, sizeof(ipr));
                    817:            port = ntohs(sa_inP->sin_port);
                    818:         } else {
                    819:            sa_in6P = (struct sockaddr_in6 *) &sa;
                    820:             inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
                    821:            port = ntohs(sa_in6P->sin6_port);
                    822:         }
                    823:        mapped_v4_to_regular_v4(ipr);
                    824:        if (test->json_output)
                    825:            cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s  port: %d", ipr, (int64_t) port));
                    826:        else
1.1.1.2 ! misho     827:            iperf_printf(test, report_accepted, ipr, port);
1.1       misho     828:     }
                    829:     if (test->json_output) {
                    830:        cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
                    831:         if (test->protocol->id == SOCK_STREAM) {
                    832:            if (test->settings->mss)
                    833:                cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
                    834:            else {
1.1.1.2 ! misho     835:                cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);
1.1       misho     836:            }
1.1.1.2 ! misho     837:         if (test->settings->rate)
        !           838:             cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
        !           839:         }
1.1       misho     840:     } else if (test->verbose) {
1.1.1.2 ! misho     841:         iperf_printf(test, report_cookie, test->cookie);
1.1       misho     842:         if (test->protocol->id == SOCK_STREAM) {
                    843:             if (test->settings->mss)
1.1.1.2 ! misho     844:                 iperf_printf(test, "      TCP MSS: %d\n", test->settings->mss);
1.1       misho     845:             else {
1.1.1.2 ! misho     846:                 iperf_printf(test, "      TCP MSS: %d (default)\n", test->ctrl_sck_mss);
1.1       misho     847:             }
                    848:         }
1.1.1.2 ! misho     849:         if (test->settings->rate)
        !           850:             iperf_printf(test, "      Target Bitrate: %"PRIu64"\n", test->settings->rate);
1.1       misho     851:     }
                    852: }
                    853: 
                    854: void
                    855: iperf_on_test_finish(struct iperf_test *test)
                    856: {
                    857: }
                    858: 
                    859: 
                    860: /******************************************************************************/
                    861: 
                    862: int
                    863: iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
                    864: {
                    865:     static struct option longopts[] =
                    866:     {
                    867:         {"port", required_argument, NULL, 'p'},
                    868:         {"format", required_argument, NULL, 'f'},
                    869:         {"interval", required_argument, NULL, 'i'},
                    870:         {"daemon", no_argument, NULL, 'D'},
                    871:         {"one-off", no_argument, NULL, '1'},
                    872:         {"verbose", no_argument, NULL, 'V'},
                    873:         {"json", no_argument, NULL, 'J'},
                    874:         {"version", no_argument, NULL, 'v'},
                    875:         {"server", no_argument, NULL, 's'},
                    876:         {"client", required_argument, NULL, 'c'},
                    877:         {"udp", no_argument, NULL, 'u'},
1.1.1.2 ! misho     878:         {"bitrate", required_argument, NULL, 'b'},
1.1       misho     879:         {"bandwidth", required_argument, NULL, 'b'},
1.1.1.2 ! misho     880:        {"server-bitrate-limit", required_argument, NULL, OPT_SERVER_BITRATE_LIMIT},
1.1       misho     881:         {"time", required_argument, NULL, 't'},
                    882:         {"bytes", required_argument, NULL, 'n'},
                    883:         {"blockcount", required_argument, NULL, 'k'},
                    884:         {"length", required_argument, NULL, 'l'},
                    885:         {"parallel", required_argument, NULL, 'P'},
                    886:         {"reverse", no_argument, NULL, 'R'},
1.1.1.2 ! misho     887:         {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL},
1.1       misho     888:         {"window", required_argument, NULL, 'w'},
                    889:         {"bind", required_argument, NULL, 'B'},
                    890:         {"cport", required_argument, NULL, OPT_CLIENT_PORT},
                    891:         {"set-mss", required_argument, NULL, 'M'},
                    892:         {"no-delay", no_argument, NULL, 'N'},
                    893:         {"version4", no_argument, NULL, '4'},
                    894:         {"version6", no_argument, NULL, '6'},
                    895:         {"tos", required_argument, NULL, 'S'},
1.1.1.2 ! misho     896:         {"dscp", required_argument, NULL, OPT_DSCP},
        !           897:        {"extra-data", required_argument, NULL, OPT_EXTRA_DATA},
1.1       misho     898: #if defined(HAVE_FLOWLABEL)
                    899:         {"flowlabel", required_argument, NULL, 'L'},
                    900: #endif /* HAVE_FLOWLABEL */
                    901:         {"zerocopy", no_argument, NULL, 'Z'},
                    902:         {"omit", required_argument, NULL, 'O'},
                    903:         {"file", required_argument, NULL, 'F'},
1.1.1.2 ! misho     904:         {"repeating-payload", no_argument, NULL, OPT_REPEATING_PAYLOAD},
        !           905:         {"timestamps", optional_argument, NULL, OPT_TIMESTAMPS},
1.1       misho     906: #if defined(HAVE_CPU_AFFINITY)
                    907:         {"affinity", required_argument, NULL, 'A'},
                    908: #endif /* HAVE_CPU_AFFINITY */
                    909:         {"title", required_argument, NULL, 'T'},
                    910: #if defined(HAVE_TCP_CONGESTION)
                    911:         {"congestion", required_argument, NULL, 'C'},
                    912:         {"linux-congestion", required_argument, NULL, 'C'},
                    913: #endif /* HAVE_TCP_CONGESTION */
1.1.1.2 ! misho     914: #if defined(HAVE_SCTP_H)
1.1       misho     915:         {"sctp", no_argument, NULL, OPT_SCTP},
                    916:         {"nstreams", required_argument, NULL, OPT_NUMSTREAMS},
                    917:         {"xbind", required_argument, NULL, 'X'},
                    918: #endif
                    919:        {"pidfile", required_argument, NULL, 'I'},
                    920:        {"logfile", required_argument, NULL, OPT_LOGFILE},
1.1.1.2 ! misho     921:        {"forceflush", no_argument, NULL, OPT_FORCEFLUSH},
1.1       misho     922:        {"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
                    923:        {"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
1.1.1.2 ! misho     924:        {"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
        !           925: #if defined(HAVE_SSL)
        !           926:     {"username", required_argument, NULL, OPT_CLIENT_USERNAME},
        !           927:     {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
        !           928:     {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
        !           929:     {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
        !           930: #endif /* HAVE_SSL */
        !           931:        {"fq-rate", required_argument, NULL, OPT_FQ_RATE},
        !           932:        {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER},
        !           933:        {"connect-timeout", required_argument, NULL, OPT_CONNECT_TIMEOUT},
1.1       misho     934:         {"debug", no_argument, NULL, 'd'},
                    935:         {"help", no_argument, NULL, 'h'},
                    936:         {NULL, 0, NULL, 0}
                    937:     };
                    938:     int flag;
1.1.1.2 ! misho     939:     int portno;
1.1       misho     940:     int blksize;
                    941:     int server_flag, client_flag, rate_flag, duration_flag;
                    942:     char *endptr;
                    943: #if defined(HAVE_CPU_AFFINITY)
                    944:     char* comma;
                    945: #endif /* HAVE_CPU_AFFINITY */
                    946:     char* slash;
                    947:     struct xbind_entry *xbe;
1.1.1.2 ! misho     948:     double farg;
1.1       misho     949: 
                    950:     blksize = 0;
                    951:     server_flag = client_flag = rate_flag = duration_flag = 0;
1.1.1.2 ! misho     952: #if defined(HAVE_SSL)
        !           953:     char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;
        !           954: #endif /* HAVE_SSL */
        !           955: 
1.1       misho     956:     while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
                    957:         switch (flag) {
                    958:             case 'p':
1.1.1.2 ! misho     959:                portno = atoi(optarg);
        !           960:                if (portno < 1 || portno > 65535) {
        !           961:                    i_errno = IEBADPORT;
        !           962:                    return -1;
        !           963:                }
        !           964:                test->server_port = portno;
1.1       misho     965:                 break;
                    966:             case 'f':
1.1.1.2 ! misho     967:                if (!optarg) {
        !           968:                    i_errno = IEBADFORMAT;
        !           969:                    return -1;
        !           970:                }
        !           971:                test->settings->unit_format = *optarg;
        !           972:                if (test->settings->unit_format == 'k' ||
        !           973:                    test->settings->unit_format == 'K' ||
        !           974:                    test->settings->unit_format == 'm' ||
        !           975:                    test->settings->unit_format == 'M' ||
        !           976:                    test->settings->unit_format == 'g' ||
        !           977:                    test->settings->unit_format == 'G' ||
        !           978:                    test->settings->unit_format == 't' ||
        !           979:                    test->settings->unit_format == 'T') {
        !           980:                        break;
        !           981:                }
        !           982:                else {
        !           983:                    i_errno = IEBADFORMAT;
        !           984:                    return -1;
        !           985:                }
1.1       misho     986:                 break;
                    987:             case 'i':
                    988:                 /* XXX: could potentially want separate stat collection and reporting intervals,
                    989:                    but just set them to be the same for now */
                    990:                 test->stats_interval = test->reporter_interval = atof(optarg);
                    991:                 if ((test->stats_interval < MIN_INTERVAL || test->stats_interval > MAX_INTERVAL) && test->stats_interval != 0) {
                    992:                     i_errno = IEINTERVAL;
                    993:                     return -1;
                    994:                 }
                    995:                 break;
                    996:             case 'D':
                    997:                test->daemon = 1;
                    998:                server_flag = 1;
                    999:                break;
                   1000:             case '1':
                   1001:                test->one_off = 1;
                   1002:                server_flag = 1;
                   1003:                break;
                   1004:             case 'V':
                   1005:                 test->verbose = 1;
                   1006:                 break;
                   1007:             case 'J':
                   1008:                 test->json_output = 1;
                   1009:                 break;
                   1010:             case 'v':
1.1.1.2 ! misho    1011:                 printf("%s (cJSON %s)\n%s\n%s\n", version, cJSON_Version(), get_system_info(),
1.1       misho    1012:                       get_optional_features());
                   1013:                 exit(0);
                   1014:             case 's':
                   1015:                 if (test->role == 'c') {
                   1016:                     i_errno = IESERVCLIENT;
                   1017:                     return -1;
                   1018:                 }
                   1019:                iperf_set_test_role(test, 's');
                   1020:                 break;
                   1021:             case 'c':
                   1022:                 if (test->role == 's') {
                   1023:                     i_errno = IESERVCLIENT;
                   1024:                     return -1;
                   1025:                 }
                   1026:                iperf_set_test_role(test, 'c');
                   1027:                iperf_set_test_server_hostname(test, optarg);
                   1028:                 break;
                   1029:             case 'u':
                   1030:                 set_protocol(test, Pudp);
                   1031:                client_flag = 1;
                   1032:                 break;
                   1033:             case OPT_SCTP:
1.1.1.2 ! misho    1034: #if defined(HAVE_SCTP_H)
1.1       misho    1035:                 set_protocol(test, Psctp);
                   1036:                 client_flag = 1;
1.1.1.2 ! misho    1037:                 break;
        !          1038: #else /* HAVE_SCTP_H */
1.1       misho    1039:                 i_errno = IEUNIMP;
                   1040:                 return -1;
1.1.1.2 ! misho    1041: #endif /* HAVE_SCTP_H */
1.1       misho    1042: 
                   1043:             case OPT_NUMSTREAMS:
                   1044: #if defined(linux) || defined(__FreeBSD__)
                   1045:                 test->settings->num_ostreams = unit_atoi(optarg);
                   1046:                 client_flag = 1;
                   1047: #else /* linux */
                   1048:                 i_errno = IEUNIMP;
                   1049:                 return -1;
                   1050: #endif /* linux */
                   1051:             case 'b':
                   1052:                slash = strchr(optarg, '/');
                   1053:                if (slash) {
                   1054:                    *slash = '\0';
                   1055:                    ++slash;
                   1056:                    test->settings->burst = atoi(slash);
                   1057:                    if (test->settings->burst <= 0 ||
                   1058:                        test->settings->burst > MAX_BURST) {
                   1059:                        i_errno = IEBURST;
                   1060:                        return -1;
                   1061:                    }
                   1062:                }
                   1063:                 test->settings->rate = unit_atof_rate(optarg);
                   1064:                rate_flag = 1;
                   1065:                client_flag = 1;
                   1066:                 break;
1.1.1.2 ! misho    1067:             case OPT_SERVER_BITRATE_LIMIT:
        !          1068:                slash = strchr(optarg, '/');
        !          1069:                if (slash) {
        !          1070:                    *slash = '\0';
        !          1071:                    ++slash;
        !          1072:                    test->settings->bitrate_limit_interval = atof(slash);
        !          1073:                    if (test->settings->bitrate_limit_interval != 0 &&  /* Using same Max/Min limits as for Stats Interval */
        !          1074:                        (test->settings->bitrate_limit_interval < MIN_INTERVAL || test->settings->bitrate_limit_interval > MAX_INTERVAL) ) {
        !          1075:                        i_errno = IETOTALINTERVAL;
        !          1076:                        return -1;
        !          1077:                    }
        !          1078:                }
        !          1079:                test->settings->bitrate_limit = unit_atof_rate(optarg);
        !          1080:                server_flag = 1;
        !          1081:                break;
1.1       misho    1082:             case 't':
                   1083:                 test->duration = atoi(optarg);
                   1084:                 if (test->duration > MAX_TIME) {
                   1085:                     i_errno = IEDURATION;
                   1086:                     return -1;
                   1087:                 }
                   1088:                duration_flag = 1;
                   1089:                client_flag = 1;
                   1090:                 break;
                   1091:             case 'n':
                   1092:                 test->settings->bytes = unit_atoi(optarg);
                   1093:                client_flag = 1;
                   1094:                 break;
                   1095:             case 'k':
                   1096:                 test->settings->blocks = unit_atoi(optarg);
                   1097:                client_flag = 1;
                   1098:                 break;
                   1099:             case 'l':
                   1100:                 blksize = unit_atoi(optarg);
                   1101:                client_flag = 1;
                   1102:                 break;
                   1103:             case 'P':
                   1104:                 test->num_streams = atoi(optarg);
                   1105:                 if (test->num_streams > MAX_STREAMS) {
                   1106:                     i_errno = IENUMSTREAMS;
                   1107:                     return -1;
                   1108:                 }
                   1109:                client_flag = 1;
                   1110:                 break;
                   1111:             case 'R':
1.1.1.2 ! misho    1112:                 if (test->bidirectional) {
        !          1113:                     i_errno = IEREVERSEBIDIR;
        !          1114:                     return -1;
        !          1115:                 }
1.1       misho    1116:                iperf_set_test_reverse(test, 1);
                   1117:                client_flag = 1;
                   1118:                 break;
1.1.1.2 ! misho    1119:             case OPT_BIDIRECTIONAL:
        !          1120:                 if (test->reverse) {
        !          1121:                     i_errno = IEREVERSEBIDIR;
        !          1122:                     return -1;
        !          1123:                 }
        !          1124:                 iperf_set_test_bidirectional(test, 1);
        !          1125:                 client_flag = 1;
        !          1126:                 break;
1.1       misho    1127:             case 'w':
                   1128:                 // XXX: This is a socket buffer, not specific to TCP
1.1.1.2 ! misho    1129:                // Do sanity checks as double-precision floating point 
        !          1130:                // to avoid possible integer overflows.
        !          1131:                 farg = unit_atof(optarg);
        !          1132:                 if (farg > (double) MAX_TCP_BUFFER) {
1.1       misho    1133:                     i_errno = IEBUFSIZE;
                   1134:                     return -1;
                   1135:                 }
1.1.1.2 ! misho    1136:                 test->settings->socket_bufsize = (int) farg;
1.1       misho    1137:                client_flag = 1;
                   1138:                 break;
                   1139:             case 'B':
                   1140:                 test->bind_address = strdup(optarg);
                   1141:                 break;
                   1142:             case OPT_CLIENT_PORT:
1.1.1.2 ! misho    1143:                portno = atoi(optarg);
        !          1144:                if (portno < 1 || portno > 65535) {
        !          1145:                    i_errno = IEBADPORT;
        !          1146:                    return -1;
        !          1147:                }
        !          1148:                 test->bind_port = portno;
1.1       misho    1149:                 break;
                   1150:             case 'M':
                   1151:                 test->settings->mss = atoi(optarg);
                   1152:                 if (test->settings->mss > MAX_MSS) {
                   1153:                     i_errno = IEMSS;
                   1154:                     return -1;
                   1155:                 }
                   1156:                client_flag = 1;
                   1157:                 break;
                   1158:             case 'N':
                   1159:                 test->no_delay = 1;
                   1160:                client_flag = 1;
                   1161:                 break;
                   1162:             case '4':
                   1163:                 test->settings->domain = AF_INET;
                   1164:                 break;
                   1165:             case '6':
                   1166:                 test->settings->domain = AF_INET6;
                   1167:                 break;
                   1168:             case 'S':
                   1169:                 test->settings->tos = strtol(optarg, &endptr, 0);
                   1170:                if (endptr == optarg ||
                   1171:                    test->settings->tos < 0 ||
                   1172:                    test->settings->tos > 255) {
                   1173:                    i_errno = IEBADTOS;
                   1174:                    return -1;
                   1175:                }
                   1176:                client_flag = 1;
                   1177:                 break;
1.1.1.2 ! misho    1178:            case OPT_DSCP:
        !          1179:                 test->settings->tos = parse_qos(optarg);
        !          1180:                if(test->settings->tos < 0) {
        !          1181:                        i_errno = IEBADTOS;
        !          1182:                        return -1;
        !          1183:                }
        !          1184:                client_flag = 1;
        !          1185:                 break;
        !          1186:            case OPT_EXTRA_DATA:
        !          1187:                test->extra_data = strdup(optarg);
        !          1188:                client_flag = 1;
        !          1189:                break;
1.1       misho    1190:             case 'L':
                   1191: #if defined(HAVE_FLOWLABEL)
                   1192:                 test->settings->flowlabel = strtol(optarg, &endptr, 0);
                   1193:                if (endptr == optarg ||
                   1194:                    test->settings->flowlabel < 1 || test->settings->flowlabel > 0xfffff) {
                   1195:                     i_errno = IESETFLOW;
                   1196:                     return -1;
                   1197:                }
                   1198:                client_flag = 1;
                   1199: #else /* HAVE_FLOWLABEL */
                   1200:                 i_errno = IEUNIMP;
                   1201:                 return -1;
                   1202: #endif /* HAVE_FLOWLABEL */
                   1203:                 break;
                   1204:             case 'X':
                   1205:                xbe = (struct xbind_entry *)malloc(sizeof(struct xbind_entry));
                   1206:                 if (!xbe) {
                   1207:                    i_errno = IESETSCTPBINDX;
                   1208:                     return -1;
                   1209:                 }
                   1210:                memset(xbe, 0, sizeof(*xbe));
                   1211:                 xbe->name = strdup(optarg);
                   1212:                 if (!xbe->name) {
                   1213:                    i_errno = IESETSCTPBINDX;
                   1214:                     return -1;
                   1215:                 }
                   1216:                TAILQ_INSERT_TAIL(&test->xbind_addrs, xbe, link);
                   1217:                 break;
                   1218:             case 'Z':
                   1219:                 if (!has_sendfile()) {
                   1220:                     i_errno = IENOSENDFILE;
                   1221:                     return -1;
                   1222:                 }
                   1223:                 test->zerocopy = 1;
                   1224:                client_flag = 1;
                   1225:                 break;
1.1.1.2 ! misho    1226:             case OPT_REPEATING_PAYLOAD:
        !          1227:                 test->repeating_payload = 1;
        !          1228:                 client_flag = 1;
        !          1229:                 break;
        !          1230:             case OPT_TIMESTAMPS:
        !          1231:                 iperf_set_test_timestamps(test, 1);
        !          1232:                if (optarg) {
        !          1233:                    iperf_set_test_timestamp_format(test, optarg);
        !          1234:                }
        !          1235:                else {
        !          1236:                    iperf_set_test_timestamp_format(test, TIMESTAMP_FORMAT);
        !          1237:                }
        !          1238:                 break;
1.1       misho    1239:             case 'O':
                   1240:                 test->omit = atoi(optarg);
                   1241:                 if (test->omit < 0 || test->omit > 60) {
                   1242:                     i_errno = IEOMIT;
                   1243:                     return -1;
                   1244:                 }
                   1245:                client_flag = 1;
                   1246:                 break;
                   1247:             case 'F':
                   1248:                 test->diskfile_name = optarg;
                   1249:                 break;
                   1250:             case 'A':
                   1251: #if defined(HAVE_CPU_AFFINITY)
                   1252:                 test->affinity = strtol(optarg, &endptr, 0);
                   1253:                 if (endptr == optarg || 
                   1254:                    test->affinity < 0 || test->affinity > 1024) {
                   1255:                     i_errno = IEAFFINITY;
                   1256:                     return -1;
                   1257:                 }
                   1258:                comma = strchr(optarg, ',');
                   1259:                if (comma != NULL) {
                   1260:                    test->server_affinity = atoi(comma+1);
                   1261:                    if (test->server_affinity < 0 || test->server_affinity > 1024) {
                   1262:                        i_errno = IEAFFINITY;
                   1263:                        return -1;
                   1264:                    }
                   1265:                    client_flag = 1;
                   1266:                }
                   1267: #else /* HAVE_CPU_AFFINITY */
                   1268:                 i_errno = IEUNIMP;
                   1269:                 return -1;
                   1270: #endif /* HAVE_CPU_AFFINITY */
                   1271:                 break;
                   1272:             case 'T':
                   1273:                 test->title = strdup(optarg);
                   1274:                client_flag = 1;
                   1275:                 break;
                   1276:            case 'C':
                   1277: #if defined(HAVE_TCP_CONGESTION)
                   1278:                test->congestion = strdup(optarg);
                   1279:                client_flag = 1;
                   1280: #else /* HAVE_TCP_CONGESTION */
                   1281:                i_errno = IEUNIMP;
                   1282:                return -1;
                   1283: #endif /* HAVE_TCP_CONGESTION */
                   1284:                break;
                   1285:            case 'd':
                   1286:                test->debug = 1;
                   1287:                break;
                   1288:            case 'I':
                   1289:                test->pidfile = strdup(optarg);
                   1290:                server_flag = 1;
                   1291:                break;
                   1292:            case OPT_LOGFILE:
                   1293:                test->logfile = strdup(optarg);
                   1294:                break;
1.1.1.2 ! misho    1295:            case OPT_FORCEFLUSH:
        !          1296:                test->forceflush = 1;
        !          1297:                break;
1.1       misho    1298:            case OPT_GET_SERVER_OUTPUT:
                   1299:                test->get_server_output = 1;
                   1300:                client_flag = 1;
                   1301:                break;
                   1302:            case OPT_UDP_COUNTERS_64BIT:
                   1303:                test->udp_counters_64bit = 1;
                   1304:                break;
                   1305:            case OPT_NO_FQ_SOCKET_PACING:
                   1306: #if defined(HAVE_SO_MAX_PACING_RATE)
1.1.1.2 ! misho    1307:                printf("Warning:  --no-fq-socket-pacing is deprecated\n");
        !          1308:                test->settings->fqrate = 0;
        !          1309:                client_flag = 1;
1.1       misho    1310: #else /* HAVE_SO_MAX_PACING_RATE */
                   1311:                i_errno = IEUNIMP;
                   1312:                return -1;
                   1313: #endif
                   1314:                break;
1.1.1.2 ! misho    1315:            case OPT_FQ_RATE:
        !          1316: #if defined(HAVE_SO_MAX_PACING_RATE)
        !          1317:                test->settings->fqrate = unit_atof_rate(optarg);
        !          1318:                client_flag = 1;
        !          1319: #else /* HAVE_SO_MAX_PACING_RATE */
        !          1320:                i_errno = IEUNIMP;
        !          1321:                return -1;
        !          1322: #endif
        !          1323:                break;
        !          1324: #if defined(HAVE_SSL)
        !          1325:         case OPT_CLIENT_USERNAME:
        !          1326:             client_username = strdup(optarg);
        !          1327:             break;
        !          1328:         case OPT_CLIENT_RSA_PUBLIC_KEY:
        !          1329:             client_rsa_public_key = strdup(optarg);
        !          1330:             break;
        !          1331:         case OPT_SERVER_RSA_PRIVATE_KEY:
        !          1332:             server_rsa_private_key = strdup(optarg);
        !          1333:             break;
        !          1334:         case OPT_SERVER_AUTHORIZED_USERS:
        !          1335:             test->server_authorized_users = strdup(optarg);
        !          1336:             break;
        !          1337: #endif /* HAVE_SSL */
        !          1338:            case OPT_PACING_TIMER:
        !          1339:                test->settings->pacing_timer = unit_atoi(optarg);
        !          1340:                client_flag = 1;
        !          1341:                break;
        !          1342:            case OPT_CONNECT_TIMEOUT:
        !          1343:                test->settings->connect_timeout = unit_atoi(optarg);
        !          1344:                client_flag = 1;
        !          1345:                break;
        !          1346:            case 'h':
        !          1347:                usage_long(stdout);
        !          1348:                exit(0);
1.1       misho    1349:             default:
1.1.1.2 ! misho    1350:                 usage_long(stderr);
1.1       misho    1351:                 exit(1);
                   1352:         }
                   1353:     }
                   1354: 
                   1355:     /* Check flag / role compatibility. */
                   1356:     if (test->role == 'c' && server_flag) {
1.1.1.2 ! misho    1357:         i_errno = IESERVERONLY;
        !          1358:         return -1;
1.1       misho    1359:     }
                   1360:     if (test->role == 's' && client_flag) {
1.1.1.2 ! misho    1361:         i_errno = IECLIENTONLY;
        !          1362:         return -1;
        !          1363:     }
        !          1364: 
        !          1365: #if defined(HAVE_SSL)
        !          1366: 
        !          1367:     if (test->role == 's' && (client_username || client_rsa_public_key)){
        !          1368:         i_errno = IECLIENTONLY;
        !          1369:         return -1;
        !          1370:     } else if (test->role == 'c' && (client_username || client_rsa_public_key) && 
        !          1371:         !(client_username && client_rsa_public_key)) {
        !          1372:         i_errno = IESETCLIENTAUTH;
        !          1373:         return -1;
        !          1374:     } else if (test->role == 'c' && (client_username && client_rsa_public_key)){
        !          1375: 
        !          1376:         char *client_password = NULL;
        !          1377:         size_t s;
        !          1378:         /* Need to copy env var, so we can do a common free */
        !          1379:         if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)
        !          1380:              client_password = strdup(client_password);
        !          1381:         else if (iperf_getpass(&client_password, &s, stdin) < 0){
        !          1382:             i_errno = IESETCLIENTAUTH;
        !          1383:             return -1;
        !          1384:         } 
        !          1385:         if (test_load_pubkey_from_file(client_rsa_public_key) < 0){
        !          1386:             i_errno = IESETCLIENTAUTH;
        !          1387:             return -1;
        !          1388:         }
        !          1389: 
        !          1390:         test->settings->client_username = client_username;
        !          1391:         test->settings->client_password = client_password;
        !          1392:         test->settings->client_rsa_pubkey = load_pubkey_from_file(client_rsa_public_key);
        !          1393:        free(client_rsa_public_key);
        !          1394:        client_rsa_public_key = NULL;
1.1       misho    1395:     }
                   1396: 
1.1.1.2 ! misho    1397:     if (test->role == 'c' && (server_rsa_private_key || test->server_authorized_users)){
        !          1398:         i_errno = IESERVERONLY;
1.1       misho    1399:         return -1;
1.1.1.2 ! misho    1400:     } else if (test->role == 's' && (server_rsa_private_key || test->server_authorized_users) && 
        !          1401:         !(server_rsa_private_key && test->server_authorized_users)) {
        !          1402:          i_errno = IESETSERVERAUTH;
        !          1403:         return -1;
        !          1404:     } else if (test->role == 's' && server_rsa_private_key) {
        !          1405:         test->server_rsa_private_key = load_privkey_from_file(server_rsa_private_key);
        !          1406:         if (test->server_rsa_private_key == NULL){
        !          1407:             i_errno = IESETSERVERAUTH;
        !          1408:             return -1;
        !          1409:         }
        !          1410:        free(server_rsa_private_key);
        !          1411:        server_rsa_private_key = NULL;
1.1       misho    1412:     }
1.1.1.2 ! misho    1413: 
        !          1414: #endif //HAVE_SSL
1.1       misho    1415:     if (blksize == 0) {
                   1416:        if (test->protocol->id == Pudp)
1.1.1.2 ! misho    1417:            blksize = 0;        /* try to dynamically determine from MSS */
1.1       misho    1418:        else if (test->protocol->id == Psctp)
                   1419:            blksize = DEFAULT_SCTP_BLKSIZE;
                   1420:        else
                   1421:            blksize = DEFAULT_TCP_BLKSIZE;
                   1422:     }
1.1.1.2 ! misho    1423:     if ((test->protocol->id != Pudp && blksize <= 0) 
        !          1424:        || blksize > MAX_BLOCKSIZE) {
1.1       misho    1425:        i_errno = IEBLOCKSIZE;
                   1426:        return -1;
                   1427:     }
                   1428:     if (test->protocol->id == Pudp &&
1.1.1.2 ! misho    1429:        (blksize > 0 &&
        !          1430:            (blksize < MIN_UDP_BLOCKSIZE || blksize > MAX_UDP_BLOCKSIZE))) {
1.1       misho    1431:        i_errno = IEUDPBLOCKSIZE;
                   1432:        return -1;
                   1433:     }
                   1434:     test->settings->blksize = blksize;
                   1435: 
                   1436:     if (!rate_flag)
                   1437:        test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;
                   1438: 
                   1439:     if ((test->settings->bytes != 0 || test->settings->blocks != 0) && ! duration_flag)
                   1440:         test->duration = 0;
                   1441: 
                   1442:     /* Disallow specifying multiple test end conditions. The code actually
                   1443:     ** works just fine without this prohibition. As soon as any one of the
                   1444:     ** three possible end conditions is met, the test ends. So this check
                   1445:     ** could be removed if desired.
                   1446:     */
                   1447:     if ((duration_flag && test->settings->bytes != 0) ||
                   1448:         (duration_flag && test->settings->blocks != 0) ||
                   1449:        (test->settings->bytes != 0 && test->settings->blocks != 0)) {
                   1450:         i_errno = IEENDCONDITIONS;
                   1451:         return -1;
                   1452:     }
                   1453: 
                   1454:     /* For subsequent calls to getopt */
                   1455: #ifdef __APPLE__
                   1456:     optreset = 1;
                   1457: #endif
                   1458:     optind = 0;
                   1459: 
                   1460:     if ((test->role != 'c') && (test->role != 's')) {
                   1461:         i_errno = IENOROLE;
                   1462:         return -1;
                   1463:     }
                   1464: 
1.1.1.2 ! misho    1465:     /* Set Total-rate average interval to multiplicity of State interval */
        !          1466:     if (test->settings->bitrate_limit_interval != 0) {
        !          1467:        test->settings->bitrate_limit_stats_per_interval =
        !          1468:            (test->settings->bitrate_limit_interval <= test->stats_interval ?
        !          1469:            1 : round(test->settings->bitrate_limit_interval/test->stats_interval) );
        !          1470:     }
        !          1471: 
        !          1472:     /* Show warning if JSON output is used with explicit report format */
        !          1473:     if ((test->json_output) && (test->settings->unit_format != 'a')) {
        !          1474:         warning("Report format (-f) flag ignored with JSON output (-J)");
        !          1475:     }
        !          1476: 
        !          1477:     /* Show warning if JSON output is used with verbose or debug flags */
        !          1478:     if (test->json_output && test->verbose) {
        !          1479:         warning("Verbose output (-v) may interfere with JSON output (-J)");
        !          1480:     }
        !          1481:     if (test->json_output && test->debug) {
        !          1482:         warning("Debug output (-d) may interfere with JSON output (-J)");
        !          1483:     }
        !          1484: 
        !          1485:     return 0;
        !          1486: }
        !          1487: 
        !          1488: /*
        !          1489:  * Open the file specified by test->logfile and set test->outfile to its' FD.
        !          1490:  */
        !          1491: int iperf_open_logfile(struct iperf_test *test)
        !          1492: {
        !          1493:     test->outfile = fopen(test->logfile, "a+");
        !          1494:     if (test->outfile == NULL) {
        !          1495:         i_errno = IELOGFILE;
        !          1496:         return -1;
        !          1497:     }
        !          1498: 
1.1       misho    1499:     return 0;
                   1500: }
                   1501: 
                   1502: int
                   1503: iperf_set_send_state(struct iperf_test *test, signed char state)
                   1504: {
                   1505:     test->state = state;
                   1506:     if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) {
                   1507:        i_errno = IESENDMESSAGE;
                   1508:        return -1;
                   1509:     }
                   1510:     return 0;
                   1511: }
                   1512: 
                   1513: void
1.1.1.2 ! misho    1514: iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
1.1       misho    1515: {
1.1.1.2 ! misho    1516:     struct iperf_time temp_time;
1.1       misho    1517:     double seconds;
                   1518:     uint64_t bits_per_second;
                   1519: 
1.1.1.2 ! misho    1520:     if (sp->test->done || sp->test->settings->rate == 0 || sp->test->settings->burst != 0)
1.1       misho    1521:         return;
1.1.1.2 ! misho    1522:     iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
        !          1523:     seconds = iperf_time_in_secs(&temp_time);
1.1       misho    1524:     bits_per_second = sp->result->bytes_sent * 8 / seconds;
                   1525:     if (bits_per_second < sp->test->settings->rate) {
                   1526:         sp->green_light = 1;
                   1527:         FD_SET(sp->socket, &sp->test->write_set);
                   1528:     } else {
                   1529:         sp->green_light = 0;
                   1530:         FD_CLR(sp->socket, &sp->test->write_set);
                   1531:     }
                   1532: }
                   1533: 
1.1.1.2 ! misho    1534: /* Verify that average traffic is not greater than the specifid limit */
        !          1535: void
        !          1536: iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)
        !          1537: {
        !          1538:     double seconds;
        !          1539:     uint64_t bits_per_second;
        !          1540:     iperf_size_t total_bytes;
        !          1541:     int i;
        !          1542: 
        !          1543:     if (test->done || test->settings->bitrate_limit == 0)    // Continue only if check should be done
        !          1544:         return;
        !          1545:     
        !          1546:     /* Add last inetrval's transffered bytes to the array */
        !          1547:     if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)
        !          1548:         test->bitrate_limit_last_interval_index = 0;
        !          1549:     test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;
        !          1550: 
        !          1551:     /* Ensure that enough stats periods passed to allow averaging throughput */
        !          1552:     test->bitrate_limit_stats_count += 1;
        !          1553:     if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)
        !          1554:         return;
        !          1555:  
        !          1556:      /* Calculating total bytes traffic to be averaged */
        !          1557:     for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {
        !          1558:         total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];
        !          1559:     }
        !          1560: 
        !          1561:     seconds = test->stats_interval * test->settings->bitrate_limit_stats_per_interval;
        !          1562:     bits_per_second = total_bytes * 8 / seconds;
        !          1563:     if (test->debug) {
        !          1564:         iperf_printf(test,"Interval %" PRIu64 " - throughput %" PRIu64 " bps (limit %" PRIu64 ")\n", test->bitrate_limit_stats_count, bits_per_second, test->settings->bitrate_limit);
        !          1565:     }
        !          1566: 
        !          1567:     if (bits_per_second  > test->settings->bitrate_limit) {
        !          1568:        iperf_err(test, "Total throughput of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", bits_per_second, test->settings->bitrate_limit);
        !          1569:        test->bitrate_limit_exceeded = 1;
        !          1570:     }
        !          1571: }
        !          1572: 
1.1       misho    1573: int
                   1574: iperf_send(struct iperf_test *test, fd_set *write_setP)
                   1575: {
                   1576:     register int multisend, r, streams_active;
                   1577:     register struct iperf_stream *sp;
1.1.1.2 ! misho    1578:     struct iperf_time now;
1.1       misho    1579: 
                   1580:     /* Can we do multisend mode? */
                   1581:     if (test->settings->burst != 0)
                   1582:         multisend = test->settings->burst;
                   1583:     else if (test->settings->rate == 0)
                   1584:         multisend = test->multisend;
                   1585:     else
                   1586:         multisend = 1; /* nope */
                   1587: 
                   1588:     for (; multisend > 0; --multisend) {
                   1589:        if (test->settings->rate != 0 && test->settings->burst == 0)
1.1.1.2 ! misho    1590:            iperf_time_now(&now);
1.1       misho    1591:        streams_active = 0;
                   1592:        SLIST_FOREACH(sp, &test->streams, streams) {
1.1.1.2 ! misho    1593:            if ((sp->green_light && sp->sender &&
1.1       misho    1594:                 (write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {
                   1595:                if ((r = sp->snd(sp)) < 0) {
                   1596:                    if (r == NET_SOFTERROR)
                   1597:                        break;
                   1598:                    i_errno = IESTREAMWRITE;
                   1599:                    return r;
                   1600:                }
                   1601:                streams_active = 1;
                   1602:                test->bytes_sent += r;
                   1603:                ++test->blocks_sent;
1.1.1.2 ! misho    1604:                iperf_check_throttle(sp, &now);
1.1       misho    1605:                if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
                   1606:                    break;
                   1607:                if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)
                   1608:                    break;
                   1609:            }
                   1610:        }
                   1611:        if (!streams_active)
                   1612:            break;
                   1613:     }
                   1614:     if (test->settings->burst != 0) {
1.1.1.2 ! misho    1615:        iperf_time_now(&now);
1.1       misho    1616:        SLIST_FOREACH(sp, &test->streams, streams)
1.1.1.2 ! misho    1617:            if (sp->sender)
        !          1618:                iperf_check_throttle(sp, &now);
1.1       misho    1619:     }
                   1620:     if (write_setP != NULL)
                   1621:        SLIST_FOREACH(sp, &test->streams, streams)
                   1622:            if (FD_ISSET(sp->socket, write_setP))
                   1623:                FD_CLR(sp->socket, write_setP);
                   1624: 
                   1625:     return 0;
                   1626: }
                   1627: 
                   1628: int
                   1629: iperf_recv(struct iperf_test *test, fd_set *read_setP)
                   1630: {
                   1631:     int r;
                   1632:     struct iperf_stream *sp;
                   1633: 
                   1634:     SLIST_FOREACH(sp, &test->streams, streams) {
1.1.1.2 ! misho    1635:        if (FD_ISSET(sp->socket, read_setP) && !sp->sender) {
1.1       misho    1636:            if ((r = sp->rcv(sp)) < 0) {
                   1637:                i_errno = IESTREAMREAD;
                   1638:                return r;
                   1639:            }
1.1.1.2 ! misho    1640:            test->bytes_received += r;
        !          1641:            ++test->blocks_received;
1.1       misho    1642:            FD_CLR(sp->socket, read_setP);
                   1643:        }
                   1644:     }
                   1645: 
                   1646:     return 0;
                   1647: }
                   1648: 
                   1649: int
                   1650: iperf_init_test(struct iperf_test *test)
                   1651: {
1.1.1.2 ! misho    1652:     struct iperf_time now;
1.1       misho    1653:     struct iperf_stream *sp;
                   1654: 
                   1655:     if (test->protocol->init) {
                   1656:         if (test->protocol->init(test) < 0)
                   1657:             return -1;
                   1658:     }
                   1659: 
                   1660:     /* Init each stream. */
1.1.1.2 ! misho    1661:     if (iperf_time_now(&now) < 0) {
1.1       misho    1662:        i_errno = IEINITTEST;
                   1663:        return -1;
                   1664:     }
                   1665:     SLIST_FOREACH(sp, &test->streams, streams) {
                   1666:        sp->result->start_time = sp->result->start_time_fixed = now;
                   1667:     }
                   1668: 
                   1669:     if (test->on_test_start)
                   1670:         test->on_test_start(test);
                   1671: 
                   1672:     return 0;
                   1673: }
                   1674: 
                   1675: static void
1.1.1.2 ! misho    1676: send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1       misho    1677: {
                   1678:     struct iperf_stream *sp = client_data.p;
                   1679: 
                   1680:     /* All we do here is set or clear the flag saying that this stream may
                   1681:     ** be sent to.  The actual sending gets done in the send proc, after
                   1682:     ** checking the flag.
                   1683:     */
                   1684:     iperf_check_throttle(sp, nowP);
                   1685: }
                   1686: 
                   1687: int
                   1688: iperf_create_send_timers(struct iperf_test * test)
                   1689: {
1.1.1.2 ! misho    1690:     struct iperf_time now;
1.1       misho    1691:     struct iperf_stream *sp;
                   1692:     TimerClientData cd;
                   1693: 
1.1.1.2 ! misho    1694:     if (iperf_time_now(&now) < 0) {
1.1       misho    1695:        i_errno = IEINITTEST;
                   1696:        return -1;
                   1697:     }
                   1698:     SLIST_FOREACH(sp, &test->streams, streams) {
                   1699:         sp->green_light = 1;
1.1.1.2 ! misho    1700:        if (test->settings->rate != 0 && sp->sender) {
1.1       misho    1701:            cd.p = sp;
1.1.1.2 ! misho    1702:            sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
1.1       misho    1703:            if (sp->send_timer == NULL) {
                   1704:                i_errno = IEINITTEST;
                   1705:                return -1;
                   1706:            }
                   1707:        }
                   1708:     }
                   1709:     return 0;
                   1710: }
                   1711: 
1.1.1.2 ! misho    1712: #if defined(HAVE_SSL)
        !          1713: int test_is_authorized(struct iperf_test *test){
        !          1714:     if ( !(test->server_rsa_private_key && test->server_authorized_users)) {
        !          1715:         return 0;
        !          1716:     }
        !          1717: 
        !          1718:     if (test->settings->authtoken){
        !          1719:         char *username = NULL, *password = NULL;
        !          1720:         time_t ts;
        !          1721:         int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
        !          1722:        if (rc) {
        !          1723:            return -1;
        !          1724:        }
        !          1725:         int ret = check_authentication(username, password, ts, test->server_authorized_users);
        !          1726:         if (ret == 0){
        !          1727:             iperf_printf(test, report_authentication_succeeded, username, ts);
        !          1728:             free(username);
        !          1729:             free(password);
        !          1730:             return 0;
        !          1731:         } else {
        !          1732:             iperf_printf(test, report_authentication_failed, username, ts);
        !          1733:             free(username);
        !          1734:             free(password);
        !          1735:             return -1;
        !          1736:         }
        !          1737:     }
        !          1738:     return -1;
        !          1739: }
        !          1740: #endif //HAVE_SSL
        !          1741: 
1.1       misho    1742: /**
                   1743:  * iperf_exchange_parameters - handles the param_Exchange part for client
                   1744:  *
                   1745:  */
                   1746: 
                   1747: int
                   1748: iperf_exchange_parameters(struct iperf_test *test)
                   1749: {
                   1750:     int s;
                   1751:     int32_t err;
                   1752: 
                   1753:     if (test->role == 'c') {
                   1754: 
                   1755:         if (send_parameters(test) < 0)
                   1756:             return -1;
                   1757: 
                   1758:     } else {
                   1759: 
                   1760:         if (get_parameters(test) < 0)
                   1761:             return -1;
                   1762: 
1.1.1.2 ! misho    1763: #if defined(HAVE_SSL)
        !          1764:         if (test_is_authorized(test) < 0){
        !          1765:             if (iperf_set_send_state(test, SERVER_ERROR) != 0)
        !          1766:                 return -1;
        !          1767:             i_errno = IEAUTHTEST;
        !          1768:             err = htonl(i_errno);
        !          1769:             if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
        !          1770:                 i_errno = IECTRLWRITE;
        !          1771:                 return -1;
        !          1772:             }
        !          1773:             return -1;
        !          1774:         }
        !          1775: #endif //HAVE_SSL
        !          1776: 
1.1       misho    1777:         if ((s = test->protocol->listen(test)) < 0) {
1.1.1.2 ! misho    1778:                if (iperf_set_send_state(test, SERVER_ERROR) != 0)
1.1       misho    1779:                 return -1;
                   1780:             err = htonl(i_errno);
                   1781:             if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
                   1782:                 i_errno = IECTRLWRITE;
                   1783:                 return -1;
                   1784:             }
                   1785:             err = htonl(errno);
                   1786:             if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
                   1787:                 i_errno = IECTRLWRITE;
                   1788:                 return -1;
                   1789:             }
                   1790:             return -1;
                   1791:         }
1.1.1.2 ! misho    1792: 
1.1       misho    1793:         FD_SET(s, &test->read_set);
                   1794:         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
                   1795:         test->prot_listener = s;
                   1796: 
                   1797:         // Send the control message to create streams and start the test
                   1798:        if (iperf_set_send_state(test, CREATE_STREAMS) != 0)
                   1799:             return -1;
                   1800: 
                   1801:     }
                   1802: 
                   1803:     return 0;
                   1804: }
                   1805: 
                   1806: /*************************************************************/
                   1807: 
                   1808: int
                   1809: iperf_exchange_results(struct iperf_test *test)
                   1810: {
                   1811:     if (test->role == 'c') {
                   1812:         /* Send results to server. */
                   1813:        if (send_results(test) < 0)
                   1814:             return -1;
                   1815:         /* Get server results. */
                   1816:         if (get_results(test) < 0)
                   1817:             return -1;
                   1818:     } else {
                   1819:         /* Get client results. */
                   1820:         if (get_results(test) < 0)
                   1821:             return -1;
                   1822:         /* Send results to client. */
                   1823:        if (send_results(test) < 0)
                   1824:             return -1;
                   1825:     }
                   1826:     return 0;
                   1827: }
                   1828: 
                   1829: /*************************************************************/
                   1830: 
                   1831: static int
                   1832: send_parameters(struct iperf_test *test)
                   1833: {
                   1834:     int r = 0;
                   1835:     cJSON *j;
                   1836: 
                   1837:     j = cJSON_CreateObject();
                   1838:     if (j == NULL) {
                   1839:        i_errno = IESENDPARAMS;
                   1840:        r = -1;
                   1841:     } else {
                   1842:        if (test->protocol->id == Ptcp)
                   1843:            cJSON_AddTrueToObject(j, "tcp");
                   1844:        else if (test->protocol->id == Pudp)
                   1845:            cJSON_AddTrueToObject(j, "udp");
                   1846:         else if (test->protocol->id == Psctp)
                   1847:             cJSON_AddTrueToObject(j, "sctp");
                   1848:        cJSON_AddNumberToObject(j, "omit", test->omit);
                   1849:        if (test->server_affinity != -1)
                   1850:            cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
1.1.1.2 ! misho    1851:        cJSON_AddNumberToObject(j, "time", test->duration);
1.1       misho    1852:        if (test->settings->bytes)
                   1853:            cJSON_AddNumberToObject(j, "num", test->settings->bytes);
                   1854:        if (test->settings->blocks)
                   1855:            cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
                   1856:        if (test->settings->mss)
                   1857:            cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
                   1858:        if (test->no_delay)
                   1859:            cJSON_AddTrueToObject(j, "nodelay");
                   1860:        cJSON_AddNumberToObject(j, "parallel", test->num_streams);
                   1861:        if (test->reverse)
                   1862:            cJSON_AddTrueToObject(j, "reverse");
1.1.1.2 ! misho    1863:        if (test->bidirectional)
        !          1864:                    cJSON_AddTrueToObject(j, "bidirectional");
1.1       misho    1865:        if (test->settings->socket_bufsize)
                   1866:            cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
                   1867:        if (test->settings->blksize)
                   1868:            cJSON_AddNumberToObject(j, "len", test->settings->blksize);
                   1869:        if (test->settings->rate)
                   1870:            cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
1.1.1.2 ! misho    1871:        if (test->settings->fqrate)
        !          1872:            cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
        !          1873:        if (test->settings->pacing_timer)
        !          1874:            cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer);
1.1       misho    1875:        if (test->settings->burst)
                   1876:            cJSON_AddNumberToObject(j, "burst", test->settings->burst);
                   1877:        if (test->settings->tos)
                   1878:            cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
                   1879:        if (test->settings->flowlabel)
                   1880:            cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
                   1881:        if (test->title)
                   1882:            cJSON_AddStringToObject(j, "title", test->title);
1.1.1.2 ! misho    1883:        if (test->extra_data)
        !          1884:            cJSON_AddStringToObject(j, "extra_data", test->extra_data);
1.1       misho    1885:        if (test->congestion)
                   1886:            cJSON_AddStringToObject(j, "congestion", test->congestion);
1.1.1.2 ! misho    1887:        if (test->congestion_used)
        !          1888:            cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
1.1       misho    1889:        if (test->get_server_output)
                   1890:            cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
                   1891:        if (test->udp_counters_64bit)
                   1892:            cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
1.1.1.2 ! misho    1893:        if (test->repeating_payload)
        !          1894:            cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
        !          1895: #if defined(HAVE_SSL)
        !          1896:        /* Send authentication parameters */
        !          1897:        if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
        !          1898:            int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
        !          1899: 
        !          1900:            if (rc) {
        !          1901:                cJSON_Delete(j);
        !          1902:                i_errno = IESENDPARAMS;
        !          1903:                return -1;
        !          1904:            }
        !          1905:            
        !          1906:            cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
        !          1907:        }
        !          1908: #endif // HAVE_SSL
1.1       misho    1909:        cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
                   1910: 
                   1911:        if (test->debug) {
1.1.1.2 ! misho    1912:            char *str = cJSON_Print(j);
        !          1913:            printf("send_parameters:\n%s\n", str);
        !          1914:            cJSON_free(str);
1.1       misho    1915:        }
                   1916: 
                   1917:        if (JSON_write(test->ctrl_sck, j) < 0) {
                   1918:            i_errno = IESENDPARAMS;
                   1919:            r = -1;
                   1920:        }
                   1921:        cJSON_Delete(j);
                   1922:     }
                   1923:     return r;
                   1924: }
                   1925: 
                   1926: /*************************************************************/
                   1927: 
                   1928: static int
                   1929: get_parameters(struct iperf_test *test)
                   1930: {
                   1931:     int r = 0;
                   1932:     cJSON *j;
                   1933:     cJSON *j_p;
                   1934: 
                   1935:     j = JSON_read(test->ctrl_sck);
                   1936:     if (j == NULL) {
                   1937:        i_errno = IERECVPARAMS;
                   1938:         r = -1;
                   1939:     } else {
                   1940:        if (test->debug) {
1.1.1.2 ! misho    1941:             char *str;
        !          1942:             str = cJSON_Print(j);
        !          1943:             printf("get_parameters:\n%s\n", str );
        !          1944:             cJSON_free(str);
1.1       misho    1945:        }
                   1946: 
                   1947:        if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
                   1948:            set_protocol(test, Ptcp);
                   1949:        if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
                   1950:            set_protocol(test, Pudp);
                   1951:         if ((j_p = cJSON_GetObjectItem(j, "sctp")) != NULL)
                   1952:             set_protocol(test, Psctp);
                   1953:        if ((j_p = cJSON_GetObjectItem(j, "omit")) != NULL)
                   1954:            test->omit = j_p->valueint;
                   1955:        if ((j_p = cJSON_GetObjectItem(j, "server_affinity")) != NULL)
                   1956:            test->server_affinity = j_p->valueint;
                   1957:        if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
                   1958:            test->duration = j_p->valueint;
                   1959:        if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
                   1960:            test->settings->bytes = j_p->valueint;
                   1961:        if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
                   1962:            test->settings->blocks = j_p->valueint;
                   1963:        if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
                   1964:            test->settings->mss = j_p->valueint;
                   1965:        if ((j_p = cJSON_GetObjectItem(j, "nodelay")) != NULL)
                   1966:            test->no_delay = 1;
                   1967:        if ((j_p = cJSON_GetObjectItem(j, "parallel")) != NULL)
                   1968:            test->num_streams = j_p->valueint;
                   1969:        if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
                   1970:            iperf_set_test_reverse(test, 1);
1.1.1.2 ! misho    1971:         if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
        !          1972:             iperf_set_test_bidirectional(test, 1);
1.1       misho    1973:        if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
                   1974:            test->settings->socket_bufsize = j_p->valueint;
                   1975:        if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
                   1976:            test->settings->blksize = j_p->valueint;
                   1977:        if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
                   1978:            test->settings->rate = j_p->valueint;
1.1.1.2 ! misho    1979:        if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
        !          1980:            test->settings->fqrate = j_p->valueint;
        !          1981:        if ((j_p = cJSON_GetObjectItem(j, "pacing_timer")) != NULL)
        !          1982:            test->settings->pacing_timer = j_p->valueint;
1.1       misho    1983:        if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
                   1984:            test->settings->burst = j_p->valueint;
                   1985:        if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
                   1986:            test->settings->tos = j_p->valueint;
                   1987:        if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL)
                   1988:            test->settings->flowlabel = j_p->valueint;
                   1989:        if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
                   1990:            test->title = strdup(j_p->valuestring);
1.1.1.2 ! misho    1991:        if ((j_p = cJSON_GetObjectItem(j, "extra_data")) != NULL)
        !          1992:            test->extra_data = strdup(j_p->valuestring);
1.1       misho    1993:        if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
                   1994:            test->congestion = strdup(j_p->valuestring);
1.1.1.2 ! misho    1995:        if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
        !          1996:            test->congestion_used = strdup(j_p->valuestring);
1.1       misho    1997:        if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
                   1998:            iperf_set_test_get_server_output(test, 1);
                   1999:        if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
                   2000:            iperf_set_test_udp_counters_64bit(test, 1);
1.1.1.2 ! misho    2001:        if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
        !          2002:            test->repeating_payload = 1;
        !          2003: #if defined(HAVE_SSL)
        !          2004:        if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
        !          2005:         test->settings->authtoken = strdup(j_p->valuestring);
        !          2006: #endif //HAVE_SSL
        !          2007:        if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
1.1       misho    2008:            test->sender_has_retransmits = 1;
1.1.1.2 ! misho    2009:        if (test->settings->rate)
        !          2010:            cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
1.1       misho    2011:        cJSON_Delete(j);
                   2012:     }
                   2013:     return r;
                   2014: }
                   2015: 
                   2016: /*************************************************************/
                   2017: 
                   2018: static int
                   2019: send_results(struct iperf_test *test)
                   2020: {
                   2021:     int r = 0;
                   2022:     cJSON *j;
                   2023:     cJSON *j_streams;
                   2024:     struct iperf_stream *sp;
                   2025:     cJSON *j_stream;
                   2026:     int sender_has_retransmits;
                   2027:     iperf_size_t bytes_transferred;
                   2028:     int retransmits;
1.1.1.2 ! misho    2029:     struct iperf_time temp_time;
        !          2030:     double start_time, end_time;
1.1       misho    2031: 
                   2032:     j = cJSON_CreateObject();
                   2033:     if (j == NULL) {
                   2034:        i_errno = IEPACKAGERESULTS;
                   2035:        r = -1;
                   2036:     } else {
                   2037:        cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
                   2038:        cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
                   2039:        cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
1.1.1.2 ! misho    2040:        if ( test->mode == RECEIVER )
1.1       misho    2041:            sender_has_retransmits = -1;
                   2042:        else
                   2043:            sender_has_retransmits = test->sender_has_retransmits;
                   2044:        cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
1.1.1.2 ! misho    2045:        if ( test->congestion_used ) {
        !          2046:            cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
        !          2047:        }
1.1       misho    2048: 
                   2049:        /* If on the server and sending server output, then do this */
                   2050:        if (test->role == 's' && test->get_server_output) {
                   2051:            if (test->json_output) {
                   2052:                /* Add JSON output */
                   2053:                cJSON_AddItemReferenceToObject(j, "server_output_json", test->json_top);
                   2054:            }
                   2055:            else {
                   2056:                /* Add textual output */
                   2057:                size_t buflen = 0;
                   2058: 
                   2059:                /* Figure out how much room we need to hold the complete output string */
                   2060:                struct iperf_textline *t;
                   2061:                TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
                   2062:                    buflen += strlen(t->line);
                   2063:                }
                   2064: 
                   2065:                /* Allocate and build it up from the component lines */
                   2066:                char *output = calloc(buflen + 1, 1);
                   2067:                TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
                   2068:                    strncat(output, t->line, buflen);
                   2069:                    buflen -= strlen(t->line);
                   2070:                }
                   2071: 
                   2072:                cJSON_AddStringToObject(j, "server_output_text", output);
1.1.1.2 ! misho    2073:         free(output);
1.1       misho    2074:            }
                   2075:        }
                   2076: 
                   2077:        j_streams = cJSON_CreateArray();
                   2078:        if (j_streams == NULL) {
                   2079:            i_errno = IEPACKAGERESULTS;
                   2080:            r = -1;
                   2081:        } else {
                   2082:            cJSON_AddItemToObject(j, "streams", j_streams);
                   2083:            SLIST_FOREACH(sp, &test->streams, streams) {
                   2084:                j_stream = cJSON_CreateObject();
                   2085:                if (j_stream == NULL) {
                   2086:                    i_errno = IEPACKAGERESULTS;
                   2087:                    r = -1;
                   2088:                } else {
                   2089:                    cJSON_AddItemToArray(j_streams, j_stream);
1.1.1.2 ! misho    2090:                    bytes_transferred = sp->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;
        !          2091:                    retransmits = (sp->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
1.1       misho    2092:                    cJSON_AddNumberToObject(j_stream, "id", sp->id);
                   2093:                    cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
                   2094:                    cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
                   2095:                    cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
                   2096:                    cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
                   2097:                    cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
1.1.1.2 ! misho    2098: 
        !          2099:                    iperf_time_diff(&sp->result->start_time, &sp->result->start_time, &temp_time);
        !          2100:                    start_time = iperf_time_in_secs(&temp_time);
        !          2101:                    iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
        !          2102:                    end_time = iperf_time_in_secs(&temp_time);
        !          2103:                    cJSON_AddNumberToObject(j_stream, "start_time", start_time);
        !          2104:                    cJSON_AddNumberToObject(j_stream, "end_time", end_time);
        !          2105: 
1.1       misho    2106:                }
                   2107:            }
                   2108:            if (r == 0 && test->debug) {
1.1.1.2 ! misho    2109:                 char *str = cJSON_Print(j);
        !          2110:                printf("send_results\n%s\n", str);
        !          2111:                 cJSON_free(str);
1.1       misho    2112:            }
                   2113:            if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
                   2114:                i_errno = IESENDRESULTS;
                   2115:                r = -1;
                   2116:            }
                   2117:        }
                   2118:        cJSON_Delete(j);
                   2119:     }
                   2120:     return r;
                   2121: }
                   2122: 
                   2123: /*************************************************************/
                   2124: 
                   2125: static int
                   2126: get_results(struct iperf_test *test)
                   2127: {
                   2128:     int r = 0;
                   2129:     cJSON *j;
                   2130:     cJSON *j_cpu_util_total;
                   2131:     cJSON *j_cpu_util_user;
                   2132:     cJSON *j_cpu_util_system;
1.1.1.2 ! misho    2133:     cJSON *j_remote_congestion_used;
1.1       misho    2134:     cJSON *j_sender_has_retransmits;
                   2135:     int result_has_retransmits;
                   2136:     cJSON *j_streams;
                   2137:     int n, i;
                   2138:     cJSON *j_stream;
                   2139:     cJSON *j_id;
                   2140:     cJSON *j_bytes;
                   2141:     cJSON *j_retransmits;
                   2142:     cJSON *j_jitter;
                   2143:     cJSON *j_errors;
                   2144:     cJSON *j_packets;
                   2145:     cJSON *j_server_output;
1.1.1.2 ! misho    2146:     cJSON *j_start_time, *j_end_time;
1.1       misho    2147:     int sid, cerror, pcount;
                   2148:     double jitter;
                   2149:     iperf_size_t bytes_transferred;
                   2150:     int retransmits;
                   2151:     struct iperf_stream *sp;
                   2152: 
                   2153:     j = JSON_read(test->ctrl_sck);
                   2154:     if (j == NULL) {
                   2155:        i_errno = IERECVRESULTS;
                   2156:         r = -1;
                   2157:     } else {
                   2158:        j_cpu_util_total = cJSON_GetObjectItem(j, "cpu_util_total");
                   2159:        j_cpu_util_user = cJSON_GetObjectItem(j, "cpu_util_user");
                   2160:        j_cpu_util_system = cJSON_GetObjectItem(j, "cpu_util_system");
                   2161:        j_sender_has_retransmits = cJSON_GetObjectItem(j, "sender_has_retransmits");
                   2162:        if (j_cpu_util_total == NULL || j_cpu_util_user == NULL || j_cpu_util_system == NULL || j_sender_has_retransmits == NULL) {
                   2163:            i_errno = IERECVRESULTS;
                   2164:            r = -1;
                   2165:        } else {
                   2166:            if (test->debug) {
1.1.1.2 ! misho    2167:                 char *str = cJSON_Print(j);
        !          2168:                 printf("get_results\n%s\n", str);
        !          2169:                 cJSON_free(str);
1.1       misho    2170:            }
                   2171: 
                   2172:            test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
                   2173:            test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
                   2174:            test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
                   2175:            result_has_retransmits = j_sender_has_retransmits->valueint;
1.1.1.2 ! misho    2176:            if ( test->mode == RECEIVER ) {
        !          2177:                test->sender_has_retransmits = result_has_retransmits;
        !          2178:                test->other_side_has_retransmits = 0;
        !          2179:            }
        !          2180:            else if ( test->mode == BIDIRECTIONAL )
        !          2181:                test->other_side_has_retransmits = result_has_retransmits;
        !          2182: 
1.1       misho    2183:            j_streams = cJSON_GetObjectItem(j, "streams");
                   2184:            if (j_streams == NULL) {
                   2185:                i_errno = IERECVRESULTS;
                   2186:                r = -1;
                   2187:            } else {
                   2188:                n = cJSON_GetArraySize(j_streams);
                   2189:                for (i=0; i<n; ++i) {
                   2190:                    j_stream = cJSON_GetArrayItem(j_streams, i);
                   2191:                    if (j_stream == NULL) {
                   2192:                        i_errno = IERECVRESULTS;
                   2193:                        r = -1;
                   2194:                    } else {
                   2195:                        j_id = cJSON_GetObjectItem(j_stream, "id");
                   2196:                        j_bytes = cJSON_GetObjectItem(j_stream, "bytes");
                   2197:                        j_retransmits = cJSON_GetObjectItem(j_stream, "retransmits");
                   2198:                        j_jitter = cJSON_GetObjectItem(j_stream, "jitter");
                   2199:                        j_errors = cJSON_GetObjectItem(j_stream, "errors");
                   2200:                        j_packets = cJSON_GetObjectItem(j_stream, "packets");
1.1.1.2 ! misho    2201:                        j_start_time = cJSON_GetObjectItem(j_stream, "start_time");
        !          2202:                        j_end_time = cJSON_GetObjectItem(j_stream, "end_time");
1.1       misho    2203:                        if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {
                   2204:                            i_errno = IERECVRESULTS;
                   2205:                            r = -1;
                   2206:                        } else {
                   2207:                            sid = j_id->valueint;
                   2208:                            bytes_transferred = j_bytes->valueint;
                   2209:                            retransmits = j_retransmits->valueint;
                   2210:                            jitter = j_jitter->valuedouble;
                   2211:                            cerror = j_errors->valueint;
                   2212:                            pcount = j_packets->valueint;
                   2213:                            SLIST_FOREACH(sp, &test->streams, streams)
                   2214:                                if (sp->id == sid) break;
                   2215:                            if (sp == NULL) {
                   2216:                                i_errno = IESTREAMID;
                   2217:                                r = -1;
                   2218:                            } else {
1.1.1.2 ! misho    2219:                                if (sp->sender) {
1.1       misho    2220:                                    sp->jitter = jitter;
                   2221:                                    sp->cnt_error = cerror;
1.1.1.2 ! misho    2222:                                    sp->peer_packet_count = pcount;
1.1       misho    2223:                                    sp->result->bytes_received = bytes_transferred;
1.1.1.2 ! misho    2224:                                    /*
        !          2225:                                     * We have to handle the possibilty that
        !          2226:                                     * start_time and end_time might not be
        !          2227:                                     * available; this is the case for older (pre-3.2)
        !          2228:                                     * servers.
        !          2229:                                     *
        !          2230:                                     * We need to have result structure members to hold
        !          2231:                                     * the both sides' start_time and end_time.
        !          2232:                                     */
        !          2233:                                    if (j_start_time && j_end_time) {
        !          2234:                                        sp->result->receiver_time = j_end_time->valuedouble - j_start_time->valuedouble;
        !          2235:                                    }
        !          2236:                                    else {
        !          2237:                                        sp->result->receiver_time = 0.0;
        !          2238:                                    }
1.1       misho    2239:                                } else {
1.1.1.2 ! misho    2240:                                    sp->peer_packet_count = pcount;
1.1       misho    2241:                                    sp->result->bytes_sent = bytes_transferred;
                   2242:                                    sp->result->stream_retrans = retransmits;
1.1.1.2 ! misho    2243:                                    if (j_start_time && j_end_time) {
        !          2244:                                        sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble;
        !          2245:                                    }
        !          2246:                                    else {
        !          2247:                                        sp->result->sender_time = 0.0;
        !          2248:                                    }
1.1       misho    2249:                                }
                   2250:                            }
                   2251:                        }
                   2252:                    }
                   2253:                }
                   2254:                /*
                   2255:                 * If we're the client and we're supposed to get remote results,
                   2256:                 * look them up and process accordingly.
                   2257:                 */
                   2258:                if (test->role == 'c' && iperf_get_test_get_server_output(test)) {
                   2259:                    /* Look for JSON.  If we find it, grab the object so it doesn't get deleted. */
                   2260:                    j_server_output = cJSON_DetachItemFromObject(j, "server_output_json");
                   2261:                    if (j_server_output != NULL) {
                   2262:                        test->json_server_output = j_server_output;
                   2263:                    }
                   2264:                    else {
                   2265:                        /* No JSON, look for textual output.  Make a copy of the text for later. */
                   2266:                        j_server_output = cJSON_GetObjectItem(j, "server_output_text");
                   2267:                        if (j_server_output != NULL) {
                   2268:                            test->server_output_text = strdup(j_server_output->valuestring);
                   2269:                        }
                   2270:                    }
                   2271:                }
                   2272:            }
                   2273:        }
1.1.1.2 ! misho    2274: 
        !          2275:        j_remote_congestion_used = cJSON_GetObjectItem(j, "congestion_used");
        !          2276:        if (j_remote_congestion_used != NULL) {
        !          2277:            test->remote_congestion_used = strdup(j_remote_congestion_used->valuestring);
        !          2278:        }
        !          2279: 
1.1       misho    2280:        cJSON_Delete(j);
                   2281:     }
                   2282:     return r;
                   2283: }
                   2284: 
                   2285: /*************************************************************/
                   2286: 
                   2287: static int
                   2288: JSON_write(int fd, cJSON *json)
                   2289: {
                   2290:     uint32_t hsize, nsize;
                   2291:     char *str;
                   2292:     int r = 0;
                   2293: 
                   2294:     str = cJSON_PrintUnformatted(json);
                   2295:     if (str == NULL)
                   2296:        r = -1;
                   2297:     else {
                   2298:        hsize = strlen(str);
                   2299:        nsize = htonl(hsize);
                   2300:        if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp) < 0)
                   2301:            r = -1;
                   2302:        else {
                   2303:            if (Nwrite(fd, str, hsize, Ptcp) < 0)
                   2304:                r = -1;
                   2305:        }
1.1.1.2 ! misho    2306:        cJSON_free(str);
1.1       misho    2307:     }
                   2308:     return r;
                   2309: }
                   2310: 
                   2311: /*************************************************************/
                   2312: 
                   2313: static cJSON *
                   2314: JSON_read(int fd)
                   2315: {
                   2316:     uint32_t hsize, nsize;
                   2317:     char *str;
                   2318:     cJSON *json = NULL;
                   2319:     int rc;
                   2320: 
                   2321:     /*
                   2322:      * Read a four-byte integer, which is the length of the JSON to follow.
                   2323:      * Then read the JSON into a buffer and parse it.  Return a parsed JSON
                   2324:      * structure, NULL if there was an error.
                   2325:      */
                   2326:     if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
                   2327:        hsize = ntohl(nsize);
                   2328:        /* Allocate a buffer to hold the JSON */
                   2329:        str = (char *) calloc(sizeof(char), hsize+1);   /* +1 for trailing null */
                   2330:        if (str != NULL) {
                   2331:            rc = Nread(fd, str, hsize, Ptcp);
                   2332:            if (rc >= 0) {
                   2333:                /*
                   2334:                 * We should be reading in the number of bytes corresponding to the
                   2335:                 * length in that 4-byte integer.  If we don't the socket might have
                   2336:                 * prematurely closed.  Only do the JSON parsing if we got the
                   2337:                 * correct number of bytes.
                   2338:                 */
                   2339:                if (rc == hsize) {
                   2340:                    json = cJSON_Parse(str);
                   2341:                }
                   2342:                else {
                   2343:                    printf("WARNING:  Size of data read does not correspond to offered length\n");
                   2344:                }
                   2345:            }
                   2346:        }
                   2347:        free(str);
                   2348:     }
                   2349:     return json;
                   2350: }
                   2351: 
                   2352: /*************************************************************/
                   2353: /**
                   2354:  * add_to_interval_list -- adds new interval to the interval_list
                   2355:  */
                   2356: 
                   2357: void
                   2358: add_to_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results * new)
                   2359: {
                   2360:     struct iperf_interval_results *irp;
                   2361: 
                   2362:     irp = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results));
                   2363:     memcpy(irp, new, sizeof(struct iperf_interval_results));
                   2364:     TAILQ_INSERT_TAIL(&rp->interval_results, irp, irlistentries);
                   2365: }
                   2366: 
                   2367: 
                   2368: /************************************************************/
                   2369: 
                   2370: /**
                   2371:  * connect_msg -- displays connection message
                   2372:  * denoting sender/receiver details
                   2373:  *
                   2374:  */
                   2375: 
                   2376: void
                   2377: connect_msg(struct iperf_stream *sp)
                   2378: {
                   2379:     char ipl[INET6_ADDRSTRLEN], ipr[INET6_ADDRSTRLEN];
                   2380:     int lport, rport;
                   2381: 
                   2382:     if (getsockdomain(sp->socket) == AF_INET) {
                   2383:         inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
                   2384:        mapped_v4_to_regular_v4(ipl);
                   2385:         inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
                   2386:        mapped_v4_to_regular_v4(ipr);
                   2387:         lport = ntohs(((struct sockaddr_in *) &sp->local_addr)->sin_port);
                   2388:         rport = ntohs(((struct sockaddr_in *) &sp->remote_addr)->sin_port);
                   2389:     } else {
                   2390:         inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
                   2391:        mapped_v4_to_regular_v4(ipl);
                   2392:         inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
                   2393:        mapped_v4_to_regular_v4(ipr);
                   2394:         lport = ntohs(((struct sockaddr_in6 *) &sp->local_addr)->sin6_port);
                   2395:         rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
                   2396:     }
                   2397: 
                   2398:     if (sp->test->json_output)
                   2399:         cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("socket: %d  local_host: %s  local_port: %d  remote_host: %s  remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport));
                   2400:     else
1.1.1.2 ! misho    2401:        iperf_printf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport);
1.1       misho    2402: }
                   2403: 
                   2404: 
                   2405: /**************************************************************************/
                   2406: 
                   2407: struct iperf_test *
                   2408: iperf_new_test()
                   2409: {
                   2410:     struct iperf_test *test;
                   2411: 
                   2412:     test = (struct iperf_test *) malloc(sizeof(struct iperf_test));
                   2413:     if (!test) {
                   2414:         i_errno = IENEWTEST;
                   2415:         return NULL;
                   2416:     }
                   2417:     /* initialize everything to zero */
                   2418:     memset(test, 0, sizeof(struct iperf_test));
                   2419: 
                   2420:     test->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings));
                   2421:     if (!test->settings) {
                   2422:         free(test);
                   2423:        i_errno = IENEWTEST;
                   2424:        return NULL;
                   2425:     }
                   2426:     memset(test->settings, 0, sizeof(struct iperf_settings));
                   2427: 
1.1.1.2 ! misho    2428:     test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);
        !          2429:     if (!test->bitrate_limit_intervals_traffic_bytes) {
        !          2430:         free(test);
        !          2431:        i_errno = IENEWTEST;
        !          2432:        return NULL;
        !          2433:     }
        !          2434:     memset(test->bitrate_limit_intervals_traffic_bytes, 0, sizeof(sizeof(iperf_size_t) * MAX_INTERVAL));   
        !          2435: 
1.1       misho    2436:     /* By default all output goes to stdout */
                   2437:     test->outfile = stdout;
                   2438: 
                   2439:     return test;
                   2440: }
                   2441: 
                   2442: /**************************************************************************/
                   2443: 
                   2444: struct protocol *
                   2445: protocol_new(void)
                   2446: {
                   2447:     struct protocol *proto;
                   2448: 
                   2449:     proto = malloc(sizeof(struct protocol));
                   2450:     if(!proto) {
                   2451:         return NULL;
                   2452:     }
                   2453:     memset(proto, 0, sizeof(struct protocol));
                   2454: 
                   2455:     return proto;
                   2456: }
                   2457: 
                   2458: void
                   2459: protocol_free(struct protocol *proto)
                   2460: {
                   2461:     free(proto); 
                   2462: }
                   2463: 
                   2464: /**************************************************************************/
                   2465: int
                   2466: iperf_defaults(struct iperf_test *testp)
                   2467: {
                   2468:     struct protocol *tcp, *udp;
1.1.1.2 ! misho    2469: #if defined(HAVE_SCTP_H)
1.1       misho    2470:     struct protocol *sctp;
1.1.1.2 ! misho    2471: #endif /* HAVE_SCTP_H */
1.1       misho    2472: 
                   2473:     testp->omit = OMIT;
                   2474:     testp->duration = DURATION;
                   2475:     testp->diskfile_name = (char*) 0;
                   2476:     testp->affinity = -1;
                   2477:     testp->server_affinity = -1;
                   2478:     TAILQ_INIT(&testp->xbind_addrs);
                   2479: #if defined(HAVE_CPUSET_SETAFFINITY)
                   2480:     CPU_ZERO(&testp->cpumask);
                   2481: #endif /* HAVE_CPUSET_SETAFFINITY */
                   2482:     testp->title = NULL;
1.1.1.2 ! misho    2483:     testp->extra_data = NULL;
1.1       misho    2484:     testp->congestion = NULL;
1.1.1.2 ! misho    2485:     testp->congestion_used = NULL;
        !          2486:     testp->remote_congestion_used = NULL;
1.1       misho    2487:     testp->server_port = PORT;
                   2488:     testp->ctrl_sck = -1;
                   2489:     testp->prot_listener = -1;
1.1.1.2 ! misho    2490:     testp->other_side_has_retransmits = 0;
1.1       misho    2491: 
                   2492:     testp->stats_callback = iperf_stats_callback;
                   2493:     testp->reporter_callback = iperf_reporter_callback;
                   2494: 
                   2495:     testp->stats_interval = testp->reporter_interval = 1;
                   2496:     testp->num_streams = 1;
                   2497: 
                   2498:     testp->settings->domain = AF_UNSPEC;
                   2499:     testp->settings->unit_format = 'a';
                   2500:     testp->settings->socket_bufsize = 0;    /* use autotuning */
                   2501:     testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
                   2502:     testp->settings->rate = 0;
1.1.1.2 ! misho    2503:     testp->settings->bitrate_limit = 0;
        !          2504:     testp->settings->bitrate_limit_interval = 5;
        !          2505:     testp->settings->bitrate_limit_stats_per_interval = 0;
        !          2506:     testp->settings->fqrate = 0;
        !          2507:     testp->settings->pacing_timer = 1000;
1.1       misho    2508:     testp->settings->burst = 0;
                   2509:     testp->settings->mss = 0;
                   2510:     testp->settings->bytes = 0;
                   2511:     testp->settings->blocks = 0;
1.1.1.2 ! misho    2512:     testp->settings->connect_timeout = -1;
1.1       misho    2513:     memset(testp->cookie, 0, COOKIE_SIZE);
                   2514: 
                   2515:     testp->multisend = 10;     /* arbitrary */
                   2516: 
                   2517:     /* Set up protocol list */
                   2518:     SLIST_INIT(&testp->streams);
                   2519:     SLIST_INIT(&testp->protocols);
                   2520: 
                   2521:     tcp = protocol_new();
                   2522:     if (!tcp)
                   2523:         return -1;
                   2524: 
                   2525:     tcp->id = Ptcp;
                   2526:     tcp->name = "TCP";
                   2527:     tcp->accept = iperf_tcp_accept;
                   2528:     tcp->listen = iperf_tcp_listen;
                   2529:     tcp->connect = iperf_tcp_connect;
                   2530:     tcp->send = iperf_tcp_send;
                   2531:     tcp->recv = iperf_tcp_recv;
                   2532:     tcp->init = NULL;
                   2533:     SLIST_INSERT_HEAD(&testp->protocols, tcp, protocols);
                   2534: 
                   2535:     udp = protocol_new();
                   2536:     if (!udp) {
                   2537:         protocol_free(tcp);
                   2538:         return -1;
                   2539:     }
                   2540: 
                   2541:     udp->id = Pudp;
                   2542:     udp->name = "UDP";
                   2543:     udp->accept = iperf_udp_accept;
                   2544:     udp->listen = iperf_udp_listen;
                   2545:     udp->connect = iperf_udp_connect;
                   2546:     udp->send = iperf_udp_send;
                   2547:     udp->recv = iperf_udp_recv;
                   2548:     udp->init = iperf_udp_init;
                   2549:     SLIST_INSERT_AFTER(tcp, udp, protocols);
                   2550: 
                   2551:     set_protocol(testp, Ptcp);
                   2552: 
1.1.1.2 ! misho    2553: #if defined(HAVE_SCTP_H)
1.1       misho    2554:     sctp = protocol_new();
                   2555:     if (!sctp) {
                   2556:         protocol_free(tcp);
                   2557:         protocol_free(udp);
                   2558:         return -1;
                   2559:     }
                   2560: 
                   2561:     sctp->id = Psctp;
                   2562:     sctp->name = "SCTP";
                   2563:     sctp->accept = iperf_sctp_accept;
                   2564:     sctp->listen = iperf_sctp_listen;
                   2565:     sctp->connect = iperf_sctp_connect;
                   2566:     sctp->send = iperf_sctp_send;
                   2567:     sctp->recv = iperf_sctp_recv;
                   2568:     sctp->init = iperf_sctp_init;
                   2569: 
                   2570:     SLIST_INSERT_AFTER(udp, sctp, protocols);
1.1.1.2 ! misho    2571: #endif /* HAVE_SCTP_H */
1.1       misho    2572: 
                   2573:     testp->on_new_stream = iperf_on_new_stream;
                   2574:     testp->on_test_start = iperf_on_test_start;
                   2575:     testp->on_connect = iperf_on_connect;
                   2576:     testp->on_test_finish = iperf_on_test_finish;
                   2577: 
                   2578:     TAILQ_INIT(&testp->server_output_list);
                   2579: 
                   2580:     return 0;
                   2581: }
                   2582: 
                   2583: 
                   2584: /**************************************************************************/
                   2585: void
                   2586: iperf_free_test(struct iperf_test *test)
                   2587: {
                   2588:     struct protocol *prot;
                   2589:     struct iperf_stream *sp;
                   2590: 
                   2591:     /* Free streams */
                   2592:     while (!SLIST_EMPTY(&test->streams)) {
                   2593:         sp = SLIST_FIRST(&test->streams);
                   2594:         SLIST_REMOVE_HEAD(&test->streams, streams);
                   2595:         iperf_free_stream(sp);
                   2596:     }
                   2597:     if (test->server_hostname)
                   2598:        free(test->server_hostname);
                   2599:     if (test->tmp_template)
                   2600:        free(test->tmp_template);
                   2601:     if (test->bind_address)
                   2602:        free(test->bind_address);
                   2603:     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
                   2604:         struct xbind_entry *xbe;
                   2605: 
                   2606:         while (!TAILQ_EMPTY(&test->xbind_addrs)) {
                   2607:             xbe = TAILQ_FIRST(&test->xbind_addrs);
                   2608:             TAILQ_REMOVE(&test->xbind_addrs, xbe, link);
                   2609:             if (xbe->ai)
                   2610:                 freeaddrinfo(xbe->ai);
                   2611:             free(xbe->name);
                   2612:             free(xbe);
                   2613:         }
                   2614:     }
1.1.1.2 ! misho    2615: #if defined(HAVE_SSL)
        !          2616: 
        !          2617:     if (test->server_rsa_private_key)
        !          2618:       EVP_PKEY_free(test->server_rsa_private_key);
        !          2619:     test->server_rsa_private_key = NULL;
        !          2620: 
        !          2621:     free(test->settings->authtoken);
        !          2622:     test->settings->authtoken = NULL;
        !          2623: 
        !          2624:     free(test->settings->client_username);
        !          2625:     test->settings->client_username = NULL;
        !          2626: 
        !          2627:     free(test->settings->client_password);
        !          2628:     test->settings->client_password = NULL;
        !          2629: 
        !          2630:     if (test->settings->client_rsa_pubkey)
        !          2631:       EVP_PKEY_free(test->settings->client_rsa_pubkey);
        !          2632:     test->settings->client_rsa_pubkey = NULL;
        !          2633: #endif /* HAVE_SSL */
        !          2634: 
1.1       misho    2635:     if (test->settings)
                   2636:     free(test->settings);
                   2637:     if (test->title)
                   2638:        free(test->title);
1.1.1.2 ! misho    2639:     if (test->extra_data)
        !          2640:        free(test->extra_data);
1.1       misho    2641:     if (test->congestion)
                   2642:        free(test->congestion);
1.1.1.2 ! misho    2643:     if (test->congestion_used)
        !          2644:        free(test->congestion_used);
        !          2645:     if (test->remote_congestion_used)
        !          2646:        free(test->remote_congestion_used);
        !          2647:     if (test->timestamp_format)
        !          2648:        free(test->timestamp_format);
1.1       misho    2649:     if (test->omit_timer != NULL)
                   2650:        tmr_cancel(test->omit_timer);
                   2651:     if (test->timer != NULL)
                   2652:        tmr_cancel(test->timer);
                   2653:     if (test->stats_timer != NULL)
                   2654:        tmr_cancel(test->stats_timer);
                   2655:     if (test->reporter_timer != NULL)
                   2656:        tmr_cancel(test->reporter_timer);
                   2657: 
                   2658:     /* Free protocol list */
                   2659:     while (!SLIST_EMPTY(&test->protocols)) {
                   2660:         prot = SLIST_FIRST(&test->protocols);
                   2661:         SLIST_REMOVE_HEAD(&test->protocols, protocols);        
                   2662:         free(prot);
                   2663:     }
                   2664: 
1.1.1.2 ! misho    2665:     if (test->logfile) {
        !          2666:        free(test->logfile);
        !          2667:        test->logfile = NULL;
        !          2668:        if (test->outfile) {
        !          2669:            fclose(test->outfile);
        !          2670:            test->outfile = NULL;
        !          2671:        }
        !          2672:     }
        !          2673: 
1.1       misho    2674:     if (test->server_output_text) {
                   2675:        free(test->server_output_text);
                   2676:        test->server_output_text = NULL;
                   2677:     }
                   2678: 
                   2679:     if (test->json_output_string) {
                   2680:        free(test->json_output_string);
                   2681:        test->json_output_string = NULL;
                   2682:     }
                   2683: 
                   2684:     /* Free output line buffers, if any (on the server only) */
                   2685:     struct iperf_textline *t;
                   2686:     while (!TAILQ_EMPTY(&test->server_output_list)) {
                   2687:        t = TAILQ_FIRST(&test->server_output_list);
                   2688:        TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
                   2689:        free(t->line);
                   2690:        free(t);
                   2691:     }
                   2692: 
                   2693:     /* sctp_bindx: do not free the arguments, only the resolver results */
                   2694:     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
                   2695:         struct xbind_entry *xbe;
                   2696: 
                   2697:         TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
                   2698:             if (xbe->ai) {
                   2699:                 freeaddrinfo(xbe->ai);
                   2700:                 xbe->ai = NULL;
                   2701:             }
                   2702:         }
                   2703:     }
                   2704: 
1.1.1.2 ! misho    2705:     /* Free interval's traffic array for avrage rate calculations */
        !          2706:     if (test->bitrate_limit_intervals_traffic_bytes != NULL)
        !          2707:         free(test->bitrate_limit_intervals_traffic_bytes);
        !          2708: 
1.1       misho    2709:     /* XXX: Why are we setting these values to NULL? */
                   2710:     // test->streams = NULL;
                   2711:     test->stats_callback = NULL;
                   2712:     test->reporter_callback = NULL;
                   2713:     free(test);
                   2714: }
                   2715: 
                   2716: 
                   2717: void
                   2718: iperf_reset_test(struct iperf_test *test)
                   2719: {
                   2720:     struct iperf_stream *sp;
1.1.1.2 ! misho    2721:     int i;
1.1       misho    2722: 
                   2723:     /* Free streams */
                   2724:     while (!SLIST_EMPTY(&test->streams)) {
                   2725:         sp = SLIST_FIRST(&test->streams);
                   2726:         SLIST_REMOVE_HEAD(&test->streams, streams);
                   2727:         iperf_free_stream(sp);
                   2728:     }
                   2729:     if (test->omit_timer != NULL) {
                   2730:        tmr_cancel(test->omit_timer);
                   2731:        test->omit_timer = NULL;
                   2732:     }
                   2733:     if (test->timer != NULL) {
                   2734:        tmr_cancel(test->timer);
                   2735:        test->timer = NULL;
                   2736:     }
                   2737:     if (test->stats_timer != NULL) {
                   2738:        tmr_cancel(test->stats_timer);
                   2739:        test->stats_timer = NULL;
                   2740:     }
                   2741:     if (test->reporter_timer != NULL) {
                   2742:        tmr_cancel(test->reporter_timer);
                   2743:        test->reporter_timer = NULL;
                   2744:     }
                   2745:     test->done = 0;
                   2746: 
                   2747:     SLIST_INIT(&test->streams);
                   2748: 
1.1.1.2 ! misho    2749:     if (test->remote_congestion_used)
        !          2750:         free(test->remote_congestion_used);
        !          2751:     test->remote_congestion_used = NULL;
1.1       misho    2752:     test->role = 's';
1.1.1.2 ! misho    2753:     test->mode = RECEIVER;
1.1       misho    2754:     test->sender_has_retransmits = 0;
                   2755:     set_protocol(test, Ptcp);
                   2756:     test->omit = OMIT;
                   2757:     test->duration = DURATION;
                   2758:     test->server_affinity = -1;
                   2759: #if defined(HAVE_CPUSET_SETAFFINITY)
                   2760:     CPU_ZERO(&test->cpumask);
                   2761: #endif /* HAVE_CPUSET_SETAFFINITY */
                   2762:     test->state = 0;
                   2763:     
                   2764:     test->ctrl_sck = -1;
                   2765:     test->prot_listener = -1;
                   2766: 
                   2767:     test->bytes_sent = 0;
                   2768:     test->blocks_sent = 0;
                   2769: 
1.1.1.2 ! misho    2770:     test->bytes_received = 0;
        !          2771:     test->blocks_received = 0;
        !          2772: 
        !          2773:     test->other_side_has_retransmits = 0;
        !          2774: 
        !          2775:     test->bitrate_limit_stats_count = 0;
        !          2776:     test->bitrate_limit_last_interval_index = 0;
        !          2777:     test->bitrate_limit_exceeded = 0;
        !          2778: 
        !          2779:     for (i = 0; i < MAX_INTERVAL; i++)
        !          2780:         test->bitrate_limit_intervals_traffic_bytes[i] = 0;
        !          2781: 
1.1       misho    2782:     test->reverse = 0;
1.1.1.2 ! misho    2783:     test->bidirectional = 0;
1.1       misho    2784:     test->no_delay = 0;
                   2785: 
                   2786:     FD_ZERO(&test->read_set);
                   2787:     FD_ZERO(&test->write_set);
                   2788:     
                   2789:     test->num_streams = 1;
                   2790:     test->settings->socket_bufsize = 0;
                   2791:     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
                   2792:     test->settings->rate = 0;
                   2793:     test->settings->burst = 0;
                   2794:     test->settings->mss = 0;
1.1.1.2 ! misho    2795:     test->settings->tos = 0;
        !          2796: 
        !          2797: #if defined(HAVE_SSL)
        !          2798:     if (test->settings->authtoken) {
        !          2799:         free(test->settings->authtoken);
        !          2800:         test->settings->authtoken = NULL;
        !          2801:     }
        !          2802:     if (test->settings->client_username) {
        !          2803:         free(test->settings->client_username);
        !          2804:         test->settings->client_username = NULL;
        !          2805:     }
        !          2806:     if (test->settings->client_password) {
        !          2807:         free(test->settings->client_password);
        !          2808:         test->settings->client_password = NULL;
        !          2809:     }
        !          2810:     if (test->settings->client_rsa_pubkey) {
        !          2811:         EVP_PKEY_free(test->settings->client_rsa_pubkey);
        !          2812:         test->settings->client_rsa_pubkey = NULL;
        !          2813:     }
        !          2814: #endif /* HAVE_SSL */
        !          2815: 
1.1       misho    2816:     memset(test->cookie, 0, COOKIE_SIZE);
                   2817:     test->multisend = 10;      /* arbitrary */
                   2818:     test->udp_counters_64bit = 0;
1.1.1.2 ! misho    2819:     if (test->title) {
        !          2820:        free(test->title);
        !          2821:        test->title = NULL;
        !          2822:     }
        !          2823:     if (test->extra_data) {
        !          2824:        free(test->extra_data);
        !          2825:        test->extra_data = NULL;
        !          2826:     }
1.1       misho    2827: 
                   2828:     /* Free output line buffers, if any (on the server only) */
                   2829:     struct iperf_textline *t;
                   2830:     while (!TAILQ_EMPTY(&test->server_output_list)) {
                   2831:        t = TAILQ_FIRST(&test->server_output_list);
                   2832:        TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
                   2833:        free(t->line);
                   2834:        free(t);
                   2835:     }
                   2836: }
                   2837: 
                   2838: 
                   2839: /* Reset all of a test's stats back to zero.  Called when the omitting
                   2840: ** period is over.
                   2841: */
                   2842: void
                   2843: iperf_reset_stats(struct iperf_test *test)
                   2844: {
1.1.1.2 ! misho    2845:     struct iperf_time now;
1.1       misho    2846:     struct iperf_stream *sp;
                   2847:     struct iperf_stream_result *rp;
                   2848: 
                   2849:     test->bytes_sent = 0;
                   2850:     test->blocks_sent = 0;
1.1.1.2 ! misho    2851:     iperf_time_now(&now);
1.1       misho    2852:     SLIST_FOREACH(sp, &test->streams, streams) {
                   2853:        sp->omitted_packet_count = sp->packet_count;
                   2854:         sp->omitted_cnt_error = sp->cnt_error;
                   2855:         sp->omitted_outoforder_packets = sp->outoforder_packets;
                   2856:        sp->jitter = 0;
                   2857:        rp = sp->result;
                   2858:         rp->bytes_sent_omit = rp->bytes_sent;
                   2859:         rp->bytes_received = 0;
                   2860:         rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
1.1.1.2 ! misho    2861:        if (test->sender_has_retransmits == 1) {
1.1       misho    2862:            struct iperf_interval_results ir; /* temporary results structure */
                   2863:            save_tcpinfo(sp, &ir);
                   2864:            rp->stream_prev_total_retrans = get_total_retransmits(&ir);
                   2865:        }
                   2866:        rp->stream_retrans = 0;
                   2867:        rp->start_time = now;
                   2868:     }
                   2869: }
                   2870: 
                   2871: 
                   2872: /**************************************************************************/
                   2873: 
                   2874: /**
                   2875:  * Gather statistics during a test.
                   2876:  * This function works for both the client and server side.
                   2877:  */
                   2878: void
                   2879: iperf_stats_callback(struct iperf_test *test)
                   2880: {
                   2881:     struct iperf_stream *sp;
                   2882:     struct iperf_stream_result *rp = NULL;
                   2883:     struct iperf_interval_results *irp, temp;
1.1.1.2 ! misho    2884:     struct iperf_time temp_time;
        !          2885:     iperf_size_t total_interval_bytes_transferred = 0;
1.1       misho    2886: 
                   2887:     temp.omitted = test->omitting;
                   2888:     SLIST_FOREACH(sp, &test->streams, streams) {
                   2889:         rp = sp->result;
1.1.1.2 ! misho    2890:        temp.bytes_transferred = sp->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;
1.1       misho    2891: 
1.1.1.2 ! misho    2892:         // Total bytes transferred this interval
        !          2893:        total_interval_bytes_transferred += rp->bytes_sent_this_interval + rp->bytes_received_this_interval;
        !          2894:     
1.1       misho    2895:        irp = TAILQ_LAST(&rp->interval_results, irlisthead);
                   2896:         /* result->end_time contains timestamp of previous interval */
                   2897:         if ( irp != NULL ) /* not the 1st interval */
1.1.1.2 ! misho    2898:             memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct iperf_time));
1.1       misho    2899:         else /* or use timestamp from beginning */
1.1.1.2 ! misho    2900:             memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct iperf_time));
1.1       misho    2901:         /* now save time of end of this interval */
1.1.1.2 ! misho    2902:         iperf_time_now(&rp->end_time);
        !          2903:         memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct iperf_time));
        !          2904:         iperf_time_diff(&temp.interval_start_time, &temp.interval_end_time, &temp_time);
        !          2905:         temp.interval_duration = iperf_time_in_secs(&temp_time);
1.1       misho    2906:        if (test->protocol->id == Ptcp) {
                   2907:            if ( has_tcpinfo()) {
                   2908:                save_tcpinfo(sp, &temp);
1.1.1.2 ! misho    2909:                if (test->sender_has_retransmits == 1) {
1.1       misho    2910:                    long total_retrans = get_total_retransmits(&temp);
                   2911:                    temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;
                   2912:                    rp->stream_retrans += temp.interval_retrans;
                   2913:                    rp->stream_prev_total_retrans = total_retrans;
                   2914: 
                   2915:                    temp.snd_cwnd = get_snd_cwnd(&temp);
                   2916:                    if (temp.snd_cwnd > rp->stream_max_snd_cwnd) {
                   2917:                        rp->stream_max_snd_cwnd = temp.snd_cwnd;
                   2918:                    }
                   2919:                    
                   2920:                    temp.rtt = get_rtt(&temp);
                   2921:                    if (temp.rtt > rp->stream_max_rtt) {
                   2922:                        rp->stream_max_rtt = temp.rtt;
                   2923:                    }
                   2924:                    if (rp->stream_min_rtt == 0 ||
                   2925:                        temp.rtt < rp->stream_min_rtt) {
                   2926:                        rp->stream_min_rtt = temp.rtt;
                   2927:                    }
                   2928:                    rp->stream_sum_rtt += temp.rtt;
                   2929:                    rp->stream_count_rtt++;
1.1.1.2 ! misho    2930: 
        !          2931:                    temp.rttvar = get_rttvar(&temp);
        !          2932:                    temp.pmtu = get_pmtu(&temp);
1.1       misho    2933:                }
                   2934:            }
                   2935:        } else {
                   2936:            if (irp == NULL) {
                   2937:                temp.interval_packet_count = sp->packet_count;
                   2938:                temp.interval_outoforder_packets = sp->outoforder_packets;
                   2939:                temp.interval_cnt_error = sp->cnt_error;
                   2940:            } else {
                   2941:                temp.interval_packet_count = sp->packet_count - irp->packet_count;
                   2942:                temp.interval_outoforder_packets = sp->outoforder_packets - irp->outoforder_packets;
                   2943:                temp.interval_cnt_error = sp->cnt_error - irp->cnt_error;
                   2944:            }
                   2945:            temp.packet_count = sp->packet_count;
                   2946:            temp.jitter = sp->jitter;
                   2947:            temp.outoforder_packets = sp->outoforder_packets;
                   2948:            temp.cnt_error = sp->cnt_error;
                   2949:        }
                   2950:         add_to_interval_list(rp, &temp);
                   2951:         rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
                   2952:     }
1.1.1.2 ! misho    2953: 
        !          2954:     /* Verify that total server's throughput is not above specified limit */
        !          2955:     if (test->role == 's') {
        !          2956:        iperf_check_total_rate(test, total_interval_bytes_transferred);
        !          2957:     }
1.1       misho    2958: }
                   2959: 
                   2960: /**
                   2961:  * Print intermediate results during a test (interval report).
                   2962:  * Uses print_interval_results to print the results for each stream,
                   2963:  * then prints an interval summary for all streams in this
                   2964:  * interval.
                   2965:  */
                   2966: static void
                   2967: iperf_print_intermediate(struct iperf_test *test)
                   2968: {
                   2969:     struct iperf_stream *sp = NULL;
                   2970:     struct iperf_interval_results *irp;
1.1.1.2 ! misho    2971:     struct iperf_time temp_time;
1.1       misho    2972:     cJSON *json_interval;
                   2973:     cJSON *json_interval_streams;
1.1.1.2 ! misho    2974: 
        !          2975:     int lower_mode, upper_mode;
        !          2976:     int current_mode;
        !          2977: 
        !          2978:     /*
        !          2979:      * Due to timing oddities, there can be cases, especially on the
        !          2980:      * server side, where at the end of a test there is a fairly short
        !          2981:      * interval with no data transferred.  This could caused by
        !          2982:      * the control and data flows sharing the same path in the network,
        !          2983:      * and having the control messages for stopping the test being
        !          2984:      * queued behind the data packets.
        !          2985:      *
        !          2986:      * We'd like to try to omit that last interval when it happens, to
        !          2987:      * avoid cluttering data and output with useless stuff.
        !          2988:      * So we're going to try to ignore very short intervals (less than
        !          2989:      * 10% of the interval time) that have no data.
        !          2990:      */
        !          2991:     int interval_ok = 0;
        !          2992:     SLIST_FOREACH(sp, &test->streams, streams) {
        !          2993:        irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
        !          2994:        if (irp) {
        !          2995:            iperf_time_diff(&irp->interval_start_time, &irp->interval_end_time, &temp_time);
        !          2996:            double interval_len = iperf_time_in_secs(&temp_time);
        !          2997:            if (test->debug) {
        !          2998:                printf("interval_len %f bytes_transferred %" PRIu64 "\n", interval_len, irp->bytes_transferred);
        !          2999:            }
        !          3000: 
        !          3001:            /*
        !          3002:             * If the interval is at least 10% the normal interval
        !          3003:             * length, or if there were actual bytes transferrred,
        !          3004:             * then we want to keep this interval.
        !          3005:             */
        !          3006:            if (interval_len >= test->stats_interval * 0.10 ||
        !          3007:                irp->bytes_transferred > 0) {
        !          3008:                interval_ok = 1;
        !          3009:                if (test->debug) {
        !          3010:                    printf("interval forces keep\n");
        !          3011:                }
        !          3012:            }
        !          3013:        }
        !          3014:     }
        !          3015:     if (!interval_ok) {
        !          3016:        if (test->debug) {
        !          3017:            printf("ignoring short interval with no data\n");
        !          3018:        }
        !          3019:        return;
        !          3020:     }
1.1       misho    3021: 
                   3022:     if (test->json_output) {
                   3023:         json_interval = cJSON_CreateObject();
                   3024:        if (json_interval == NULL)
                   3025:            return;
                   3026:        cJSON_AddItemToArray(test->json_intervals, json_interval);
                   3027:         json_interval_streams = cJSON_CreateArray();
                   3028:        if (json_interval_streams == NULL)
                   3029:            return;
                   3030:        cJSON_AddItemToObject(json_interval, "streams", json_interval_streams);
                   3031:     } else {
                   3032:         json_interval = NULL;
                   3033:         json_interval_streams = NULL;
                   3034:     }
                   3035: 
1.1.1.2 ! misho    3036:     /*
        !          3037:      * We must to sum streams separately.
        !          3038:      * For bidirectional mode we must to display
        !          3039:      * information about sender and receiver streams.
        !          3040:      * For client side we must handle sender streams
        !          3041:      * firstly and receiver streams for server side.
        !          3042:      * The following design allows us to do this.
        !          3043:      */
        !          3044: 
        !          3045:     if (test->mode == BIDIRECTIONAL) {
        !          3046:         if (test->role == 'c') {
        !          3047:             lower_mode = -1;
        !          3048:             upper_mode = 0;
        !          3049:         } else {
        !          3050:             lower_mode = 0;
        !          3051:             upper_mode = 1;
        !          3052:         }
        !          3053:     } else {
        !          3054:         lower_mode = test->mode;
        !          3055:         upper_mode = lower_mode;
1.1       misho    3056:     }
                   3057: 
                   3058: 
1.1.1.2 ! misho    3059:     for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
        !          3060:         char ubuf[UNIT_LEN];
        !          3061:         char nbuf[UNIT_LEN];
        !          3062:         char mbuf[UNIT_LEN];
        !          3063:         char zbuf[] = "          ";
1.1       misho    3064: 
1.1.1.2 ! misho    3065:         iperf_size_t bytes = 0;
        !          3066:         double bandwidth;
        !          3067:         int retransmits = 0;
        !          3068:         double start_time, end_time;
        !          3069: 
        !          3070:         int total_packets = 0, lost_packets = 0;
        !          3071:         double avg_jitter = 0.0, lost_percent;
        !          3072:         int stream_must_be_sender = current_mode * current_mode;
        !          3073: 
        !          3074:         /*  Print stream role just for bidirectional mode. */
        !          3075: 
        !          3076:         if (test->mode == BIDIRECTIONAL) {
        !          3077:             sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
        !          3078:         } else {
        !          3079:             mbuf[0] = '\0';
        !          3080:             zbuf[0] = '\0';
        !          3081:         }
        !          3082: 
        !          3083:         SLIST_FOREACH(sp, &test->streams, streams) {
        !          3084:             if (sp->sender == stream_must_be_sender) {
        !          3085:                 print_interval_results(test, sp, json_interval_streams);
        !          3086:                 /* sum up all streams */
        !          3087:                 irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
        !          3088:                 if (irp == NULL) {
        !          3089:                     iperf_err(test,
        !          3090:                             "iperf_print_intermediate error: interval_results is NULL");
        !          3091:                     return;
        !          3092:                 }
        !          3093:                 bytes += irp->bytes_transferred;
        !          3094:                 if (test->protocol->id == Ptcp) {
        !          3095:                     if (test->sender_has_retransmits == 1) {
        !          3096:                         retransmits += irp->interval_retrans;
        !          3097:                     }
        !          3098:                 } else {
        !          3099:                     total_packets += irp->interval_packet_count;
        !          3100:                     lost_packets += irp->interval_cnt_error;
        !          3101:                     avg_jitter += irp->jitter;
        !          3102:                 }
        !          3103:             }
        !          3104:         }
        !          3105: 
        !          3106:         /* next build string with sum of all streams */
        !          3107:         if (test->num_streams > 1 || test->json_output) {
        !          3108:             sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
        !          3109:             /* Only do this of course if there was a first stream */
        !          3110:             if (sp) {
        !          3111:            irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);    /* use 1st stream for timing info */
        !          3112: 
        !          3113:            unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
        !          3114:            bandwidth = (double) bytes / (double) irp->interval_duration;
        !          3115:            unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3116: 
        !          3117:            iperf_time_diff(&sp->result->start_time,&irp->interval_start_time, &temp_time);
        !          3118:            start_time = iperf_time_in_secs(&temp_time);
        !          3119:            iperf_time_diff(&sp->result->start_time,&irp->interval_end_time, &temp_time);
        !          3120:            end_time = iperf_time_in_secs(&temp_time);
        !          3121:                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
        !          3122:                     if (test->sender_has_retransmits == 1 && stream_must_be_sender) {
        !          3123:                         /* Interval sum, TCP with retransmits. */
        !          3124:                         if (test->json_output)
        !          3125:                             cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted, stream_must_be_sender)); /* XXX irp->omitted or test->omitting? */
        !          3126:                         else
        !          3127:                             iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */
        !          3128:                     } else {
        !          3129:                         /* Interval sum, TCP without retransmits. */
        !          3130:                         if (test->json_output)
        !          3131:                             cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting, stream_must_be_sender));
        !          3132:                         else
        !          3133:                             iperf_printf(test, report_sum_bw_format, mbuf, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");
        !          3134:                     }
        !          3135:                 } else {
        !          3136:                     /* Interval sum, UDP. */
        !          3137:                     if (stream_must_be_sender) {
        !          3138:                         if (test->json_output)
        !          3139:                             cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  packets: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting, stream_must_be_sender));
        !          3140:                         else
        !          3141:                             iperf_printf(test, report_sum_bw_udp_sender_format, mbuf, start_time, end_time, ubuf, nbuf, zbuf, total_packets, test->omitting?report_omitted:"");
        !          3142:                     } else {
        !          3143:                         avg_jitter /= test->num_streams;
        !          3144:                         if (total_packets > 0) {
        !          3145:                             lost_percent = 100.0 * lost_packets / total_packets;
        !          3146:                         }
        !          3147:                         else {
        !          3148:                             lost_percent = 0.0;
        !          3149:                         }
        !          3150:                         if (test->json_output)
        !          3151:                             cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, test->omitting, stream_must_be_sender));
        !          3152:                         else
        !          3153:                             iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");
        !          3154:                     }
        !          3155:                 }
        !          3156:             }
        !          3157:         }
1.1       misho    3158:     }
                   3159: }
                   3160: 
                   3161: /**
                   3162:  * Print overall summary statistics at the end of a test.
                   3163:  */
                   3164: static void
                   3165: iperf_print_results(struct iperf_test *test)
                   3166: {
                   3167: 
                   3168:     cJSON *json_summary_streams = NULL;
1.1.1.2 ! misho    3169: 
        !          3170:     int lower_mode, upper_mode;
        !          3171:     int current_mode;
        !          3172: 
        !          3173:     int tmp_sender_has_retransmits = test->sender_has_retransmits;
1.1       misho    3174: 
                   3175:     /* print final summary for all intervals */
                   3176: 
                   3177:     if (test->json_output) {
                   3178:         json_summary_streams = cJSON_CreateArray();
                   3179:        if (json_summary_streams == NULL)
                   3180:            return;
                   3181:        cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);
                   3182:     } else {
1.1.1.2 ! misho    3183:        iperf_printf(test, "%s", report_bw_separator);
1.1       misho    3184:        if (test->verbose)
1.1.1.2 ! misho    3185:            iperf_printf(test, "%s", report_summary);
1.1       misho    3186:        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 ! misho    3187:            if (test->sender_has_retransmits || test->other_side_has_retransmits) {
        !          3188:                if (test->bidirectional)
        !          3189:                    iperf_printf(test, "%s", report_bw_retrans_header_bidir);
        !          3190:                else
        !          3191:                    iperf_printf(test, "%s", report_bw_retrans_header);
        !          3192:            }
        !          3193:            else {
        !          3194:                if (test->bidirectional)
        !          3195:                    iperf_printf(test, "%s", report_bw_header_bidir);
        !          3196:                else
        !          3197:                    iperf_printf(test, "%s", report_bw_header);
        !          3198:            }
        !          3199:        } else {
        !          3200:            if (test->bidirectional)
        !          3201:                iperf_printf(test, "%s", report_bw_udp_header_bidir);
1.1       misho    3202:            else
1.1.1.2 ! misho    3203:                iperf_printf(test, "%s", report_bw_udp_header);
        !          3204:        }
1.1       misho    3205:     }
                   3206: 
1.1.1.2 ! misho    3207:     /*
        !          3208:      * We must to sum streams separately.
        !          3209:      * For bidirectional mode we must to display
        !          3210:      * information about sender and receiver streams.
        !          3211:      * For client side we must handle sender streams
        !          3212:      * firstly and receiver streams for server side.
        !          3213:      * The following design allows us to do this.
1.1       misho    3214:      */
                   3215: 
1.1.1.2 ! misho    3216:     if (test->mode == BIDIRECTIONAL) {
        !          3217:         if (test->role == 'c') {
        !          3218:             lower_mode = -1;
        !          3219:             upper_mode = 0;
        !          3220:         } else {
        !          3221:             lower_mode = 0;
        !          3222:             upper_mode = 1;
1.1       misho    3223:         }
1.1.1.2 ! misho    3224:     } else {
        !          3225:         lower_mode = test->mode;
        !          3226:         upper_mode = lower_mode;
        !          3227:     }
1.1       misho    3228: 
                   3229: 
1.1.1.2 ! misho    3230:     for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
        !          3231:         cJSON *json_summary_stream = NULL;
        !          3232:         int total_retransmits = 0;
        !          3233:         int total_packets = 0, lost_packets = 0;
        !          3234:         int sender_packet_count = 0, receiver_packet_count = 0; /* for this stream, this interval */
        !          3235:         int sender_total_packets = 0, receiver_total_packets = 0; /* running total */
        !          3236:         char ubuf[UNIT_LEN];
        !          3237:         char nbuf[UNIT_LEN];
        !          3238:         struct stat sb;
        !          3239:         char sbuf[UNIT_LEN];
        !          3240:         struct iperf_stream *sp = NULL;
        !          3241:         iperf_size_t bytes_sent, total_sent = 0;
        !          3242:         iperf_size_t bytes_received, total_received = 0;
        !          3243:         double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent = 0.0;
        !          3244:         double sender_time = 0.0, receiver_time = 0.0;
        !          3245:     struct iperf_time temp_time;
        !          3246:         double bandwidth;
1.1       misho    3247: 
1.1.1.2 ! misho    3248:         char mbuf[UNIT_LEN];
        !          3249:         int stream_must_be_sender = current_mode * current_mode;
1.1       misho    3250: 
1.1.1.2 ! misho    3251: 
        !          3252:         /*  Print stream role just for bidirectional mode. */
        !          3253: 
        !          3254:         if (test->mode == BIDIRECTIONAL) {
        !          3255:             sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
1.1       misho    3256:         } else {
1.1.1.2 ! misho    3257:             mbuf[0] = '\0';
1.1       misho    3258:         }
                   3259: 
1.1.1.2 ! misho    3260:         /* Get sender_has_retransmits for each sender side (client and server) */
        !          3261:         if (test->mode == BIDIRECTIONAL && stream_must_be_sender)
        !          3262:             test->sender_has_retransmits = tmp_sender_has_retransmits;
        !          3263:         else if (test->mode == BIDIRECTIONAL && !stream_must_be_sender)
        !          3264:             test->sender_has_retransmits = test->other_side_has_retransmits;
1.1       misho    3265: 
1.1.1.2 ! misho    3266:         start_time = 0.;
        !          3267:         sp = SLIST_FIRST(&test->streams);
        !          3268: 
        !          3269:         /*
        !          3270:          * If there is at least one stream, then figure out the length of time
        !          3271:          * we were running the tests and print out some statistics about
        !          3272:          * the streams.  It's possible to not have any streams at all
        !          3273:          * if the client got interrupted before it got to do anything.
        !          3274:          *
        !          3275:          * Also note that we try to keep seperate values for the sender
        !          3276:          * and receiver ending times.  Earlier iperf (3.1 and earlier)
        !          3277:          * servers didn't send that to the clients, so in this case we fall
        !          3278:          * back to using the client's ending timestamp.  The fallback is
        !          3279:          * basically emulating what iperf 3.1 did.
        !          3280:          */
        !          3281: 
        !          3282:         if (sp) {
        !          3283:     iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
        !          3284:     end_time = iperf_time_in_secs(&temp_time);
        !          3285:         if (sp->sender) {
        !          3286:             sp->result->sender_time = end_time;
        !          3287:             if (sp->result->receiver_time == 0.0) {
        !          3288:                 sp->result->receiver_time = sp->result->sender_time;
        !          3289:             }
        !          3290:         }
        !          3291:         else {
        !          3292:             sp->result->receiver_time = end_time;
        !          3293:             if (sp->result->sender_time == 0.0) {
        !          3294:                 sp->result->sender_time = sp->result->receiver_time;
        !          3295:             }
        !          3296:         }
        !          3297:         sender_time = sp->result->sender_time;
        !          3298:         receiver_time = sp->result->receiver_time;
        !          3299:         SLIST_FOREACH(sp, &test->streams, streams) {
        !          3300:             if (sp->sender == stream_must_be_sender) {
        !          3301:                 if (test->json_output) {
        !          3302:                     json_summary_stream = cJSON_CreateObject();
        !          3303:                     if (json_summary_stream == NULL)
        !          3304:                         return;
        !          3305:                     cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
        !          3306:                 }
        !          3307: 
        !          3308:                 bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;
        !          3309:                 bytes_received = sp->result->bytes_received;
        !          3310:                 total_sent += bytes_sent;
        !          3311:                 total_received += bytes_received;
        !          3312: 
        !          3313:                 if (sp->sender) {
        !          3314:                     sender_packet_count = sp->packet_count;
        !          3315:                     receiver_packet_count = sp->peer_packet_count;
        !          3316:                 }
        !          3317:                 else {
        !          3318:                     sender_packet_count = sp->peer_packet_count;
        !          3319:                     receiver_packet_count = sp->packet_count;
        !          3320:                 }
        !          3321: 
        !          3322:                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
        !          3323:                     if (test->sender_has_retransmits) {
        !          3324:                         total_retransmits += sp->result->stream_retrans;
        !          3325:                     }
        !          3326:                 } else {
        !          3327:                     /*
        !          3328:                      * Running total of the total number of packets.  Use the sender packet count if we
        !          3329:                      * have it, otherwise use the receiver packet count.
        !          3330:                      */
        !          3331:                     int packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
        !          3332:                     total_packets += (packet_count - sp->omitted_packet_count);
        !          3333:                     sender_total_packets += (sender_packet_count - sp->omitted_packet_count);
        !          3334:                     receiver_total_packets += (receiver_packet_count - sp->omitted_packet_count);
        !          3335:                     lost_packets += (sp->cnt_error - sp->omitted_cnt_error);
        !          3336:                     avg_jitter += sp->jitter;
        !          3337:                 }
        !          3338: 
        !          3339:                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
        !          3340:                 if (sender_time > 0.0) {
        !          3341:                     bandwidth = (double) bytes_sent / (double) sender_time;
        !          3342:                 }
        !          3343:                 else {
        !          3344:                     bandwidth = 0.0;
        !          3345:                 }
        !          3346:                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3347:                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
        !          3348:                     if (test->sender_has_retransmits) {
        !          3349:                         /* Sender summary, TCP and SCTP with retransmits. */
        !          3350:                         if (test->json_output)
        !          3351:                             cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  max_snd_cwnd:  %d  max_rtt:  %d  min_rtt:  %d  mean_rtt:  %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender));
        !          3352:                         else
        !          3353:                             if (test->role == 's' && !sp->sender) {
        !          3354:                                 if (test->verbose)
        !          3355:                                     iperf_printf(test, report_sender_not_available_format, sp->socket);
        !          3356:                             }
        !          3357:                             else {
        !          3358:                                 iperf_printf(test, report_bw_retrans_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender);
        !          3359:                             }
        !          3360:                     } else {
        !          3361:                         /* Sender summary, TCP and SCTP without retransmits. */
        !          3362:                         if (test->json_output)
        !          3363:                             cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8,  stream_must_be_sender));
        !          3364:                         else
        !          3365:                             if (test->role == 's' && !sp->sender) {
        !          3366:                                 if (test->verbose)
        !          3367:                                     iperf_printf(test, report_sender_not_available_format, sp->socket);
        !          3368:                             }
        !          3369:                             else {
        !          3370:                                 iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
        !          3371:                             }
        !          3372:                     }
        !          3373:                 } else {
        !          3374:                     /* Sender summary, UDP. */
        !          3375:                     if (sender_packet_count - sp->omitted_packet_count > 0) {
        !          3376:                         lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sender_packet_count - sp->omitted_packet_count);
        !          3377:                     }
        !          3378:                     else {
        !          3379:                         lost_percent = 0.0;
        !          3380:                     }
        !          3381:                     if (test->json_output) {
        !          3382:                         /*
        !          3383:                          * For hysterical raisins, we only emit one JSON
        !          3384:                          * object for the UDP summary, and it contains
        !          3385:                          * information for both the sender and receiver
        !          3386:                          * side.
        !          3387:                          *
        !          3388:                          * The JSON format as currently defined only includes one
        !          3389:                          * value for the number of packets.  We usually want that
        !          3390:                          * to be the sender's value (how many packets were sent
        !          3391:                          * by the sender).  However this value might not be
        !          3392:                          * available on the receiver in certain circumstances
        !          3393:                          * specifically on the server side for a normal test or
        !          3394:                          * the client side for a reverse-mode test.  If this
        !          3395:                          * is the case, then use the receiver's count of packets
        !          3396:                          * instead.
        !          3397:                          */
        !          3398:                         int packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
        !          3399:                         cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  out_of_order: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), stream_must_be_sender));
        !          3400:                     }
        !          3401:                     else {
        !          3402:                         /*
        !          3403:                          * Due to ordering of messages on the control channel,
        !          3404:                          * the server cannot report on client-side summary
        !          3405:                          * statistics.  If we're the server, omit one set of
        !          3406:                          * summary statistics to avoid giving meaningless
        !          3407:                          * results.
        !          3408:                          */
        !          3409:                         if (test->role == 's' && !sp->sender) {
        !          3410:                             if (test->verbose)
        !          3411:                                 iperf_printf(test, report_sender_not_available_format, sp->socket);
        !          3412:                         }
        !          3413:                         else {
        !          3414:                             iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender);
        !          3415:                         }
        !          3416:                         if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)
        !          3417:                           iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
        !          3418:                     }
        !          3419:                 }
        !          3420: 
        !          3421:                 if (sp->diskfile_fd >= 0) {
        !          3422:                     if (fstat(sp->diskfile_fd, &sb) == 0) {
        !          3423:                         /* In the odd case that it's a zero-sized file, say it was all transferred. */
        !          3424:                         int percent_sent = 100, percent_received = 100;
        !          3425:                         if (sb.st_size > 0) {
        !          3426:                             percent_sent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
        !          3427:                             percent_received = (int) ( ( (double) bytes_received / (double) sb.st_size ) * 100.0 );
        !          3428:                         }
        !          3429:                         unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
        !          3430:                         if (test->json_output)
        !          3431:                             cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d  received: %d  size: %d  percent_sent: %d  percent_received: %d  filename: %s", (int64_t) bytes_sent, (int64_t) bytes_received, (int64_t) sb.st_size, (int64_t) percent_sent, (int64_t) percent_received, test->diskfile_name));
        !          3432:                         else
        !          3433:                             if (stream_must_be_sender) {
        !          3434:                                 iperf_printf(test, report_diskfile, ubuf, sbuf, percent_sent, test->diskfile_name);
        !          3435:                             }
        !          3436:                             else {
        !          3437:                                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
        !          3438:                                 iperf_printf(test, report_diskfile, ubuf, sbuf, percent_received, test->diskfile_name);
        !          3439:                             }
        !          3440:                     }
        !          3441:                 }
        !          3442: 
        !          3443:                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
        !          3444:                 if (receiver_time > 0) {
        !          3445:                     bandwidth = (double) bytes_received / (double) receiver_time;
        !          3446:                 }
        !          3447:                 else {
        !          3448:                     bandwidth = 0.0;
        !          3449:                 }
        !          3450:                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3451:                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
        !          3452:                     /* Receiver summary, TCP and SCTP */
        !          3453:                     if (test->json_output)
        !          3454:                         cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender));
        !          3455:                     else
        !          3456:                         if (test->role == 's' && sp->sender) {
        !          3457:                             if (test->verbose)
        !          3458:                                 iperf_printf(test, report_receiver_not_available_format, sp->socket);
        !          3459:                         }
        !          3460:                         else {
        !          3461:                             iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
        !          3462:                         }
        !          3463:                 }
        !          3464:                 else {
        !          3465:                     /*
        !          3466:                      * Receiver summary, UDP.  Note that JSON was emitted with
        !          3467:                      * the sender summary, so we only deal with human-readable
        !          3468:                      * data here.
        !          3469:                      */
        !          3470:                     if (! test->json_output) {
        !          3471:                         if (receiver_packet_count - sp->omitted_packet_count > 0) {
        !          3472:                             lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (receiver_packet_count - sp->omitted_packet_count);
        !          3473:                         }
        !          3474:                         else {
        !          3475:                             lost_percent = 0.0;
        !          3476:                         }
        !          3477: 
        !          3478:                         if (test->role == 's' && sp->sender) {
        !          3479:                             if (test->verbose)
        !          3480:                                 iperf_printf(test, report_receiver_not_available_format, sp->socket);
        !          3481:                         }
        !          3482:                         else {
        !          3483:                             iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver);
        !          3484:                         }
        !          3485:                     }
        !          3486:                 }
        !          3487:             }
        !          3488:         }
        !          3489:         }
        !          3490: 
        !          3491:         if (test->num_streams > 1 || test->json_output) {
        !          3492:             unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
        !          3493:             /* If no tests were run, arbitrarily set bandwidth to 0. */
        !          3494:             if (sender_time > 0.0) {
        !          3495:                 bandwidth = (double) total_sent / (double) sender_time;
        !          3496:             }
        !          3497:             else {
        !          3498:                 bandwidth = 0.0;
        !          3499:             }
        !          3500:             unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3501:             if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
        !          3502:                 if (test->sender_has_retransmits) {
        !          3503:                     /* Summary sum, TCP with retransmits. */
        !          3504:                     if (test->json_output)
        !          3505:                         cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, stream_must_be_sender));
        !          3506:                     else
        !          3507:                         if (test->role == 's' && !stream_must_be_sender) {
        !          3508:                             if (test->verbose)
        !          3509:                                 iperf_printf(test, report_sender_not_available_summary_format, "SUM");
        !          3510:                         }
        !          3511:                         else {
        !          3512:                           iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, sender_time, ubuf, nbuf, total_retransmits, report_sender);
        !          3513:                         }
        !          3514:                 } else {
        !          3515:                     /* Summary sum, TCP without retransmits. */
        !          3516:                     if (test->json_output)
        !          3517:                         cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, stream_must_be_sender));
        !          3518:                     else
        !          3519:                         if (test->role == 's' && !stream_must_be_sender) {
        !          3520:                             if (test->verbose)
        !          3521:                                 iperf_printf(test, report_sender_not_available_summary_format, "SUM");
        !          3522:                         }
        !          3523:                         else {
        !          3524:                             iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
        !          3525:                         }
        !          3526:                 }
        !          3527:                 unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
        !          3528:                 /* If no tests were run, set received bandwidth to 0 */
        !          3529:                 if (receiver_time > 0.0) {
        !          3530:                     bandwidth = (double) total_received / (double) receiver_time;
        !          3531:                 }
        !          3532:                 else {
        !          3533:                     bandwidth = 0.0;
        !          3534:                 }
        !          3535:                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3536:                 if (test->json_output)
        !          3537:                     cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender));
        !          3538:                 else
        !          3539:                     if (test->role == 's' && stream_must_be_sender) {
        !          3540:                         if (test->verbose)
        !          3541:                             iperf_printf(test, report_receiver_not_available_summary_format, "SUM");
        !          3542:                     }
        !          3543:                     else {
        !          3544:                         iperf_printf(test, report_sum_bw_format, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
        !          3545:                     }
        !          3546:             } else {
        !          3547:                 /* Summary sum, UDP. */
        !          3548:                 avg_jitter /= test->num_streams;
        !          3549:                 /* If no packets were sent, arbitrarily set loss percentage to 0. */
        !          3550:                 if (total_packets > 0) {
        !          3551:                     lost_percent = 100.0 * lost_packets / total_packets;
        !          3552:                 }
        !          3553:                 else {
        !          3554:                     lost_percent = 0.0;
        !          3555:                 }
        !          3556:                 if (test->json_output)
        !          3557:                     cJSON_AddItemToObject(test->json_end, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, stream_must_be_sender));
        !          3558:                 else {
        !          3559:                     /*
        !          3560:                      * On the client we have both sender and receiver overall summary
        !          3561:                      * stats.  On the server we have only the side that was on the
        !          3562:                      * server.  Output whatever we have.
        !          3563:                      */
        !          3564:                     if (! (test->role == 's' && !stream_must_be_sender) ) {
        !          3565:                         unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
        !          3566:                         iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, sender_total_packets, 0.0, "sender");
        !          3567:                     }
        !          3568:                     if (! (test->role == 's' && stream_must_be_sender) ) {
        !          3569: 
        !          3570:                         unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
        !          3571:                         /* Compute received bandwidth. */
        !          3572:                         if (end_time > 0.0) {
        !          3573:                             bandwidth = (double) total_received / (double) receiver_time;
        !          3574:                         }
        !          3575:                         else {
        !          3576:                             bandwidth = 0.0;
        !          3577:                         }
        !          3578:                         unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
        !          3579:                         iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, "receiver");
        !          3580:                     }
        !          3581:                 }
        !          3582:             }
        !          3583:         }
        !          3584: 
        !          3585:         if (test->json_output && current_mode == upper_mode) {
        !          3586:             cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f  host_user: %f  host_system: %f  remote_total: %f  remote_user: %f  remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2]));
        !          3587:             if (test->protocol->id == Ptcp) {
        !          3588:                 char *snd_congestion = NULL, *rcv_congestion = NULL;
        !          3589:                 if (stream_must_be_sender) {
        !          3590:                     snd_congestion = test->congestion_used;
        !          3591:                     rcv_congestion = test->remote_congestion_used;
        !          3592:                 }
        !          3593:                 else {
        !          3594:                     snd_congestion = test->remote_congestion_used;
        !          3595:                     rcv_congestion = test->congestion_used;
        !          3596:                 }
        !          3597:                 if (snd_congestion) {
        !          3598:                     cJSON_AddStringToObject(test->json_end, "sender_tcp_congestion", snd_congestion);
        !          3599:                 }
        !          3600:                 if (rcv_congestion) {
        !          3601:                     cJSON_AddStringToObject(test->json_end, "receiver_tcp_congestion", rcv_congestion);
        !          3602:                 }
        !          3603:             }
        !          3604:         }
        !          3605:         else {
        !          3606:             if (test->verbose) {
        !          3607:                 if (stream_must_be_sender) {
        !          3608:                     if (test->bidirectional) {
        !          3609:                         iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
        !          3610:                         iperf_printf(test, report_cpu, report_local, !stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, !stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
        !          3611:                     } else
        !          3612:                         iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
        !          3613:                 }
        !          3614:                 if (test->protocol->id == Ptcp) {
        !          3615:                     char *snd_congestion = NULL, *rcv_congestion = NULL;
        !          3616:                     if (stream_must_be_sender) {
        !          3617:                         snd_congestion = test->congestion_used;
        !          3618:                         rcv_congestion = test->remote_congestion_used;
        !          3619:                     }
        !          3620:                     else {
        !          3621:                         snd_congestion = test->remote_congestion_used;
        !          3622:                         rcv_congestion = test->congestion_used;
        !          3623:                     }
        !          3624:                     if (snd_congestion) {
        !          3625:                         iperf_printf(test, "snd_tcp_congestion %s\n", snd_congestion);
        !          3626:                     }
        !          3627:                     if (rcv_congestion) {
        !          3628:                         iperf_printf(test, "rcv_tcp_congestion %s\n", rcv_congestion);
        !          3629:                     }
        !          3630:                 }
        !          3631:             }
        !          3632: 
        !          3633:             /* Print server output if we're on the client and it was requested/provided */
        !          3634:             if (test->role == 'c' && iperf_get_test_get_server_output(test) && !test->json_output) {
        !          3635:                 if (test->json_server_output) {
        !          3636:                    char *str = cJSON_Print(test->json_server_output);
        !          3637:                     iperf_printf(test, "\nServer JSON output:\n%s\n", str);
        !          3638:                    cJSON_free(str);
        !          3639:                     cJSON_Delete(test->json_server_output);
        !          3640:                     test->json_server_output = NULL;
        !          3641:                 }
        !          3642:                 if (test->server_output_text) {
        !          3643:                     iperf_printf(test, "\nServer output:\n%s\n", test->server_output_text);
        !          3644:                     test->server_output_text = NULL;
        !          3645:                 }
        !          3646:             }
        !          3647:         }
1.1       misho    3648:     }
1.1.1.2 ! misho    3649: 
        !          3650:     /* Set real sender_has_retransmits for current side */
        !          3651:     if (test->mode == BIDIRECTIONAL)
        !          3652:         test->sender_has_retransmits = tmp_sender_has_retransmits;
1.1       misho    3653: }
                   3654: 
                   3655: /**************************************************************************/
                   3656: 
                   3657: /**
                   3658:  * Main report-printing callback.
                   3659:  * Prints results either during a test (interval report only) or 
                   3660:  * after the entire test has been run (last interval report plus 
                   3661:  * overall summary).
                   3662:  */
                   3663: void
                   3664: iperf_reporter_callback(struct iperf_test *test)
                   3665: {
                   3666:     switch (test->state) {
                   3667:         case TEST_RUNNING:
                   3668:         case STREAM_RUNNING:
                   3669:             /* print interval results for each stream */
                   3670:             iperf_print_intermediate(test);
                   3671:             break;
                   3672:         case TEST_END:
                   3673:         case DISPLAY_RESULTS:
                   3674:             iperf_print_intermediate(test);
                   3675:             iperf_print_results(test);
                   3676:             break;
                   3677:     } 
                   3678: 
                   3679: }
                   3680: 
                   3681: /**
                   3682:  * Print the interval results for one stream.
                   3683:  * This function needs to know about the overall test so it can determine the
                   3684:  * context for printing headers, separators, etc.
                   3685:  */
                   3686: static void
                   3687: print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams)
                   3688: {
                   3689:     char ubuf[UNIT_LEN];
                   3690:     char nbuf[UNIT_LEN];
                   3691:     char cbuf[UNIT_LEN];
1.1.1.2 ! misho    3692:     char mbuf[UNIT_LEN];
        !          3693:     char zbuf[] = "          ";
1.1       misho    3694:     double st = 0., et = 0.;
1.1.1.2 ! misho    3695:     struct iperf_time temp_time;
1.1       misho    3696:     struct iperf_interval_results *irp = NULL;
                   3697:     double bandwidth, lost_percent;
                   3698: 
1.1.1.2 ! misho    3699:     if (test->mode == BIDIRECTIONAL) {
        !          3700:         sprintf(mbuf, "[%s-%s]", sp->sender?"TX":"RX", test->role == 'c'?"C":"S");
        !          3701:     } else {
        !          3702:         mbuf[0] = '\0';
        !          3703:         zbuf[0] = '\0';
        !          3704:     }
        !          3705: 
1.1       misho    3706:     irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
                   3707:     if (irp == NULL) {
                   3708:        iperf_err(test, "print_interval_results error: interval_results is NULL");
                   3709:         return;
                   3710:     }
                   3711:     if (!test->json_output) {
                   3712:        /* First stream? */
                   3713:        if (sp == SLIST_FIRST(&test->streams)) {
                   3714:            /* It it's the first interval, print the header;
                   3715:            ** else if there's more than one stream, print the separator;
                   3716:            ** else nothing.
                   3717:            */
1.1.1.2 ! misho    3718:            if (iperf_time_compare(&sp->result->start_time, &irp->interval_start_time) == 0) {
1.1       misho    3719:                if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 ! misho    3720:                    if (test->sender_has_retransmits == 1) {
        !          3721:                        if (test->bidirectional)
        !          3722:                            iperf_printf(test, "%s", report_bw_retrans_cwnd_header_bidir);
        !          3723:                        else
        !          3724:                            iperf_printf(test, "%s", report_bw_retrans_cwnd_header);
        !          3725:                    }
        !          3726:                    else {
        !          3727:                        if (test->bidirectional)
        !          3728:                            iperf_printf(test, "%s", report_bw_header_bidir);
        !          3729:                        else
        !          3730:                            iperf_printf(test, "%s", report_bw_header);
        !          3731:                    }
1.1       misho    3732:                } else {
1.1.1.2 ! misho    3733:                    if (test->mode == SENDER) {
        !          3734:                        iperf_printf(test, "%s", report_bw_udp_sender_header);
        !          3735:                    } else if (test->mode == RECEIVER){
        !          3736:                        iperf_printf(test, "%s", report_bw_udp_header);
        !          3737:                    } else {
        !          3738:                        /* BIDIRECTIONAL */
        !          3739:                        iperf_printf(test, "%s", report_bw_udp_header_bidir);
        !          3740:                    }
1.1       misho    3741:                }
                   3742:            } else if (test->num_streams > 1)
1.1.1.2 ! misho    3743:                iperf_printf(test, "%s", report_bw_separator);
1.1       misho    3744:        }
                   3745:     }
                   3746: 
                   3747:     unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
1.1.1.2 ! misho    3748:     if (irp->interval_duration > 0.0) {
        !          3749:        bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
        !          3750:     }
        !          3751:     else {
        !          3752:        bandwidth = 0.0;
        !          3753:     }
1.1       misho    3754:     unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                   3755:     
1.1.1.2 ! misho    3756:     iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);
        !          3757:     st = iperf_time_in_secs(&temp_time);
        !          3758:     iperf_time_diff(&sp->result->start_time, &irp->interval_end_time, &temp_time);
        !          3759:     et = iperf_time_in_secs(&temp_time);
1.1       misho    3760:     
                   3761:     if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 ! misho    3762:        if (test->sender_has_retransmits == 1 && sp->sender) {
1.1       misho    3763:            /* Interval, TCP with retransmits. */
                   3764:            if (test->json_output)
1.1.1.2 ! misho    3765:                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  snd_cwnd:  %d  rtt:  %d  rttvar: %d  pmtu: %d  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender));
1.1       misho    3766:            else {
                   3767:                unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
1.1.1.2 ! misho    3768:                iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
1.1       misho    3769:            }
                   3770:        } else {
                   3771:            /* Interval, TCP without retransmits. */
                   3772:            if (test->json_output)
1.1.1.2 ! misho    3773:                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted, sp->sender));
1.1       misho    3774:            else
1.1.1.2 ! misho    3775:                iperf_printf(test, report_bw_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->omitted?report_omitted:"");
1.1       misho    3776:        }
                   3777:     } else {
                   3778:        /* Interval, UDP. */
1.1.1.2 ! misho    3779:        if (sp->sender) {
1.1       misho    3780:            if (test->json_output)
1.1.1.2 ! misho    3781:                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  packets: %d  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_packet_count, irp->omitted, sp->sender));
1.1       misho    3782:            else
1.1.1.2 ! misho    3783:                iperf_printf(test, report_bw_udp_sender_format, sp->socket, mbuf, st, et, ubuf, nbuf, zbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");
1.1       misho    3784:        } else {
                   3785:            if (irp->interval_packet_count > 0) {
                   3786:                lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
                   3787:            }
                   3788:            else {
                   3789:                lost_percent = 0.0;
                   3790:            }
                   3791:            if (test->json_output)
1.1.1.2 ! misho    3792:                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted, sp->sender));
1.1       misho    3793:            else
1.1.1.2 ! misho    3794:                iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:"");
1.1       misho    3795:        }
                   3796:     }
                   3797: 
1.1.1.2 ! misho    3798:     if (test->logfile || test->forceflush)
1.1       misho    3799:         iflush(test);
                   3800: }
                   3801: 
                   3802: /**************************************************************************/
                   3803: void
                   3804: iperf_free_stream(struct iperf_stream *sp)
                   3805: {
                   3806:     struct iperf_interval_results *irp, *nirp;
                   3807: 
                   3808:     /* XXX: need to free interval list too! */
                   3809:     munmap(sp->buffer, sp->test->settings->blksize);
                   3810:     close(sp->buffer_fd);
                   3811:     if (sp->diskfile_fd >= 0)
                   3812:        close(sp->diskfile_fd);
                   3813:     for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != NULL; irp = nirp) {
                   3814:         nirp = TAILQ_NEXT(irp, irlistentries);
                   3815:         free(irp);
                   3816:     }
                   3817:     free(sp->result);
                   3818:     if (sp->send_timer != NULL)
                   3819:        tmr_cancel(sp->send_timer);
                   3820:     free(sp);
                   3821: }
                   3822: 
                   3823: /**************************************************************************/
                   3824: struct iperf_stream *
1.1.1.2 ! misho    3825: iperf_new_stream(struct iperf_test *test, int s, int sender)
1.1       misho    3826: {
                   3827:     struct iperf_stream *sp;
1.1.1.2 ! misho    3828:     int ret = 0;
        !          3829: 
1.1       misho    3830:     char template[1024];
                   3831:     if (test->tmp_template) {
                   3832:         snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
                   3833:     } else {
1.1.1.2 ! misho    3834:         //find the system temporary dir *unix, windows, cygwin support
        !          3835:         char* tempdir = getenv("TMPDIR");
        !          3836:         if (tempdir == 0){
        !          3837:             tempdir = getenv("TEMP");
        !          3838:         }
        !          3839:         if (tempdir == 0){
        !          3840:             tempdir = getenv("TMP");
        !          3841:         }
        !          3842:         if (tempdir == 0){
        !          3843:             tempdir = "/tmp";
        !          3844:         }
        !          3845:         snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);
1.1       misho    3846:     }
                   3847: 
                   3848:     sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
                   3849:     if (!sp) {
                   3850:         i_errno = IECREATESTREAM;
                   3851:         return NULL;
                   3852:     }
                   3853: 
                   3854:     memset(sp, 0, sizeof(struct iperf_stream));
                   3855: 
1.1.1.2 ! misho    3856:     sp->sender = sender;
1.1       misho    3857:     sp->test = test;
                   3858:     sp->settings = test->settings;
                   3859:     sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
                   3860:     if (!sp->result) {
                   3861:         free(sp);
                   3862:         i_errno = IECREATESTREAM;
                   3863:         return NULL;
                   3864:     }
                   3865: 
                   3866:     memset(sp->result, 0, sizeof(struct iperf_stream_result));
                   3867:     TAILQ_INIT(&sp->result->interval_results);
                   3868:     
                   3869:     /* Create and randomize the buffer */
                   3870:     sp->buffer_fd = mkstemp(template);
                   3871:     if (sp->buffer_fd == -1) {
                   3872:         i_errno = IECREATESTREAM;
                   3873:         free(sp->result);
                   3874:         free(sp);
                   3875:         return NULL;
                   3876:     }
                   3877:     if (unlink(template) < 0) {
                   3878:         i_errno = IECREATESTREAM;
                   3879:         free(sp->result);
                   3880:         free(sp);
                   3881:         return NULL;
                   3882:     }
                   3883:     if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
                   3884:         i_errno = IECREATESTREAM;
                   3885:         free(sp->result);
                   3886:         free(sp);
                   3887:         return NULL;
                   3888:     }
                   3889:     sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
                   3890:     if (sp->buffer == MAP_FAILED) {
                   3891:         i_errno = IECREATESTREAM;
                   3892:         free(sp->result);
                   3893:         free(sp);
                   3894:         return NULL;
                   3895:     }
                   3896: 
                   3897:     /* Set socket */
                   3898:     sp->socket = s;
                   3899: 
                   3900:     sp->snd = test->protocol->send;
                   3901:     sp->rcv = test->protocol->recv;
                   3902: 
                   3903:     if (test->diskfile_name != (char*) 0) {
1.1.1.2 ! misho    3904:        sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
1.1       misho    3905:        if (sp->diskfile_fd == -1) {
                   3906:            i_errno = IEFILE;
                   3907:             munmap(sp->buffer, sp->test->settings->blksize);
                   3908:             free(sp->result);
                   3909:             free(sp);
                   3910:            return NULL;
                   3911:        }
                   3912:         sp->snd2 = sp->snd;
                   3913:        sp->snd = diskfile_send;
                   3914:        sp->rcv2 = sp->rcv;
                   3915:        sp->rcv = diskfile_recv;
                   3916:     } else
                   3917:         sp->diskfile_fd = -1;
                   3918: 
                   3919:     /* Initialize stream */
1.1.1.2 ! misho    3920:     if (test->repeating_payload)
        !          3921:         fill_with_repeating_pattern(sp->buffer, test->settings->blksize);
        !          3922:     else
        !          3923:         ret = readentropy(sp->buffer, test->settings->blksize);
        !          3924: 
        !          3925:     if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) {
1.1       misho    3926:         close(sp->buffer_fd);
                   3927:         munmap(sp->buffer, sp->test->settings->blksize);
                   3928:         free(sp->result);
                   3929:         free(sp);
                   3930:         return NULL;
                   3931:     }
                   3932:     iperf_add_stream(test, sp);
                   3933: 
                   3934:     return sp;
                   3935: }
                   3936: 
                   3937: /**************************************************************************/
                   3938: int
                   3939: iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
                   3940: {
                   3941:     socklen_t len;
                   3942:     int opt;
                   3943: 
                   3944:     len = sizeof(struct sockaddr_storage);
                   3945:     if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
                   3946:         i_errno = IEINITSTREAM;
                   3947:         return -1;
                   3948:     }
                   3949:     len = sizeof(struct sockaddr_storage);
                   3950:     if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
                   3951:         i_errno = IEINITSTREAM;
                   3952:         return -1;
                   3953:     }
                   3954: 
                   3955:     /* Set IP TOS */
                   3956:     if ((opt = test->settings->tos)) {
                   3957:         if (getsockdomain(sp->socket) == AF_INET6) {
                   3958: #ifdef IPV6_TCLASS
                   3959:             if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
                   3960:                 i_errno = IESETCOS;
                   3961:                 return -1;
                   3962:             }
                   3963: #else
                   3964:             i_errno = IESETCOS;
                   3965:             return -1;
                   3966: #endif
                   3967:         } else {
                   3968:             if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
                   3969:                 i_errno = IESETTOS;
                   3970:                 return -1;
                   3971:             }
                   3972:         }
                   3973:     }
                   3974: 
                   3975:     return 0;
                   3976: }
                   3977: 
                   3978: /**************************************************************************/
                   3979: void
                   3980: iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp)
                   3981: {
                   3982:     int i;
                   3983:     struct iperf_stream *n, *prev;
                   3984: 
                   3985:     if (SLIST_EMPTY(&test->streams)) {
                   3986:         SLIST_INSERT_HEAD(&test->streams, sp, streams);
                   3987:         sp->id = 1;
                   3988:     } else {
                   3989:         // for (n = test->streams, i = 2; n->next; n = n->next, ++i);
                   3990:         i = 2;
                   3991:         SLIST_FOREACH(n, &test->streams, streams) {
                   3992:             prev = n;
                   3993:             ++i;
                   3994:         }
                   3995:         SLIST_INSERT_AFTER(prev, sp, streams);
                   3996:         sp->id = i;
                   3997:     }
                   3998: }
                   3999: 
                   4000: /* This pair of routines gets inserted into the snd/rcv function pointers
                   4001: ** when there's a -F flag. They handle the file stuff and call the real
                   4002: ** snd/rcv functions, which have been saved in snd2/rcv2.
                   4003: **
                   4004: ** The advantage of doing it this way is that in the much more common
                   4005: ** case of no -F flag, there is zero extra overhead.
                   4006: */
                   4007: 
                   4008: static int
                   4009: diskfile_send(struct iperf_stream *sp)
                   4010: {
                   4011:     int r;
1.1.1.2 ! misho    4012:     static int rtot;
1.1       misho    4013: 
1.1.1.2 ! misho    4014:     /* if needed, read enough data from the disk to fill up the buffer */
        !          4015:     if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {
        !          4016:        r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -
        !          4017:                 sp->diskfile_left);
        !          4018:        rtot += r;
        !          4019:        if (sp->test->debug) {
        !          4020:            printf("read %d bytes from file, %d total\n", r, rtot);
        !          4021:            if (r != sp->test->settings->blksize - sp->diskfile_left)
        !          4022:                printf("possible eof\n");
        !          4023:        }
        !          4024:        /* If there's no data left in the file or in the buffer, we're done */
        !          4025:        if (r == 0 && sp->diskfile_left == 0) {
        !          4026:            sp->test->done = 1;
        !          4027:            if (sp->test->debug)
        !          4028:                printf("done\n");
        !          4029:        }
        !          4030:     }
        !          4031: 
        !          4032:     r = sp->snd2(sp);
        !          4033:     if (r < 0) {
        !          4034:        return r;
        !          4035:     }
        !          4036:     /*
        !          4037:      * Compute how much data is in the buffer but didn't get sent.
        !          4038:      * If there are bytes that got left behind, slide them to the
        !          4039:      * front of the buffer so they can hopefully go out on the next
        !          4040:      * pass.
        !          4041:      */
        !          4042:     sp->diskfile_left = sp->test->settings->blksize - r;
        !          4043:     if (sp->diskfile_left && sp->diskfile_left < sp->test->settings->blksize) {
        !          4044:        memcpy(sp->buffer,
        !          4045:               sp->buffer + (sp->test->settings->blksize - sp->diskfile_left),
        !          4046:               sp->diskfile_left);
        !          4047:        if (sp->test->debug)
        !          4048:            printf("Shifting %d bytes by %d\n", sp->diskfile_left, (sp->test->settings->blksize - sp->diskfile_left));
        !          4049:     }
1.1       misho    4050:     return r;
                   4051: }
                   4052: 
                   4053: static int
                   4054: diskfile_recv(struct iperf_stream *sp)
                   4055: {
                   4056:     int r;
                   4057: 
                   4058:     r = sp->rcv2(sp);
                   4059:     if (r > 0) {
                   4060:        (void) write(sp->diskfile_fd, sp->buffer, r);
                   4061:        (void) fsync(sp->diskfile_fd);
                   4062:     }
                   4063:     return r;
                   4064: }
                   4065: 
                   4066: 
                   4067: void
                   4068: iperf_catch_sigend(void (*handler)(int))
                   4069: {
1.1.1.2 ! misho    4070: #ifdef SIGINT
1.1       misho    4071:     signal(SIGINT, handler);
1.1.1.2 ! misho    4072: #endif
        !          4073: #ifdef SIGTERM
1.1       misho    4074:     signal(SIGTERM, handler);
1.1.1.2 ! misho    4075: #endif
        !          4076: #ifdef SIGHUP
1.1       misho    4077:     signal(SIGHUP, handler);
1.1.1.2 ! misho    4078: #endif
1.1       misho    4079: }
                   4080: 
                   4081: /**
                   4082:  * Called as a result of getting a signal.
                   4083:  * Depending on the current state of the test (and the role of this
                   4084:  * process) compute and report one more set of ending statistics
                   4085:  * before cleaning up and exiting.
                   4086:  */
                   4087: void
                   4088: iperf_got_sigend(struct iperf_test *test)
                   4089: {
                   4090:     /*
                   4091:      * If we're the client, or if we're a server and running a test,
                   4092:      * then dump out the accumulated stats so far.
                   4093:      */
                   4094:     if (test->role == 'c' ||
                   4095:       (test->role == 's' && test->state == TEST_RUNNING)) {
                   4096: 
                   4097:        test->done = 1;
                   4098:        cpu_util(test->cpu_util);
                   4099:        test->stats_callback(test);
                   4100:        test->state = DISPLAY_RESULTS; /* change local state only */
                   4101:        if (test->on_test_finish)
                   4102:            test->on_test_finish(test);
                   4103:        test->reporter_callback(test);
                   4104:     }
                   4105: 
                   4106:     if (test->ctrl_sck >= 0) {
                   4107:        test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE;
                   4108:        (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp);
                   4109:     }
                   4110:     i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM;
                   4111:     iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno));
                   4112: }
                   4113: 
                   4114: /* Try to write a PID file if requested, return -1 on an error. */
                   4115: int
                   4116: iperf_create_pidfile(struct iperf_test *test)
                   4117: {
                   4118:     if (test->pidfile) {
                   4119:        int fd;
                   4120:        char buf[8];
1.1.1.2 ! misho    4121: 
        !          4122:        /* See if the file already exists and we can read it. */
        !          4123:        fd = open(test->pidfile, O_RDONLY, 0);
        !          4124:        if (fd >= 0) {
        !          4125:            if (read(fd, buf, sizeof(buf) - 1) >= 0) {
        !          4126: 
        !          4127:                /* We read some bytes, see if they correspond to a valid PID */
        !          4128:                pid_t pid;
        !          4129:                pid = atoi(buf);
        !          4130:                if (pid > 0) {
        !          4131: 
        !          4132:                    /* See if the process exists. */
        !          4133:                    if (kill(pid, 0) == 0) {
        !          4134:                        /*
        !          4135:                         * Make sure not to try to delete existing PID file by
        !          4136:                         * scribbling over the pathname we'd use to refer to it.
        !          4137:                         * Then exit with an error.
        !          4138:                         */
        !          4139:                        free(test->pidfile);
        !          4140:                        test->pidfile = NULL;
        !          4141:                        iperf_errexit(test, "Another instance of iperf3 appears to be running");
        !          4142:                    }
        !          4143:                }
        !          4144:            }
        !          4145:        }
        !          4146:        
        !          4147:        /*
        !          4148:         * File didn't exist, we couldn't read it, or it didn't correspond to 
        !          4149:         * a running process.  Try to create it. 
        !          4150:         */
1.1       misho    4151:        fd = open(test->pidfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
                   4152:        if (fd < 0) {
                   4153:            return -1;
                   4154:        }
                   4155:        snprintf(buf, sizeof(buf), "%d", getpid()); /* no trailing newline */
                   4156:        if (write(fd, buf, strlen(buf) + 1) < 0) {
                   4157:            return -1;
                   4158:        }
                   4159:        if (close(fd) < 0) {
                   4160:            return -1;
                   4161:        };
                   4162:     }
                   4163:     return 0;
                   4164: }
                   4165: 
                   4166: /* Get rid of a PID file, return -1 on error. */
                   4167: int
                   4168: iperf_delete_pidfile(struct iperf_test *test)
                   4169: {
                   4170:     if (test->pidfile) {
                   4171:        if (unlink(test->pidfile) < 0) {
                   4172:            return -1;
                   4173:        }
                   4174:     }
                   4175:     return 0;
                   4176: }
                   4177: 
                   4178: int
                   4179: iperf_json_start(struct iperf_test *test)
                   4180: {
                   4181:     test->json_top = cJSON_CreateObject();
                   4182:     if (test->json_top == NULL)
                   4183:         return -1;
                   4184:     test->json_start = cJSON_CreateObject();
                   4185:     if (test->json_start == NULL)
                   4186:         return -1;
                   4187:     cJSON_AddItemToObject(test->json_top, "start", test->json_start);
                   4188:     test->json_connected = cJSON_CreateArray();
                   4189:     if (test->json_connected == NULL)
                   4190:         return -1;
                   4191:     cJSON_AddItemToObject(test->json_start, "connected", test->json_connected);
                   4192:     test->json_intervals = cJSON_CreateArray();
                   4193:     if (test->json_intervals == NULL)
                   4194:         return -1;
                   4195:     cJSON_AddItemToObject(test->json_top, "intervals", test->json_intervals);
                   4196:     test->json_end = cJSON_CreateObject();
                   4197:     if (test->json_end == NULL)
                   4198:         return -1;
                   4199:     cJSON_AddItemToObject(test->json_top, "end", test->json_end);
                   4200:     return 0;
                   4201: }
                   4202: 
                   4203: int
                   4204: iperf_json_finish(struct iperf_test *test)
                   4205: {
                   4206:     if (test->title)
                   4207:        cJSON_AddStringToObject(test->json_top, "title", test->title);
1.1.1.2 ! misho    4208:     if (test->extra_data)
        !          4209:        cJSON_AddStringToObject(test->json_top, "extra_data", test->extra_data);
1.1       misho    4210:     /* Include server output */
                   4211:     if (test->json_server_output) {
                   4212:        cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);
                   4213:     }
                   4214:     if (test->server_output_text) {
                   4215:        cJSON_AddStringToObject(test->json_top, "server_output_text", test->server_output_text);
                   4216:     }
                   4217:     test->json_output_string = cJSON_Print(test->json_top);
                   4218:     if (test->json_output_string == NULL)
                   4219:         return -1;
                   4220:     fprintf(test->outfile, "%s\n", test->json_output_string);
                   4221:     iflush(test);
1.1.1.2 ! misho    4222:     cJSON_free(test->json_output_string);
        !          4223:     test->json_output_string = NULL;
1.1       misho    4224:     cJSON_Delete(test->json_top);
                   4225:     test->json_top = test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL;
                   4226:     return 0;
                   4227: }
                   4228: 
                   4229: 
1.1.1.2 ! misho    4230: /* CPU affinity stuff - Linux, FreeBSD, and Windows only. */
1.1       misho    4231: 
                   4232: int
                   4233: iperf_setaffinity(struct iperf_test *test, int affinity)
                   4234: {
                   4235: #if defined(HAVE_SCHED_SETAFFINITY)
                   4236:     cpu_set_t cpu_set;
                   4237: 
                   4238:     CPU_ZERO(&cpu_set);
                   4239:     CPU_SET(affinity, &cpu_set);
                   4240:     if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
                   4241:        i_errno = IEAFFINITY;
                   4242:         return -1;
                   4243:     }
                   4244:     return 0;
                   4245: #elif defined(HAVE_CPUSET_SETAFFINITY)
                   4246:     cpuset_t cpumask;
                   4247: 
                   4248:     if(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
                   4249:                           sizeof(cpuset_t), &test->cpumask) != 0) {
                   4250:         i_errno = IEAFFINITY;
                   4251:         return -1;
                   4252:     }
                   4253: 
                   4254:     CPU_ZERO(&cpumask);
                   4255:     CPU_SET(affinity, &cpumask);
                   4256: 
                   4257:     if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
                   4258:                           sizeof(cpuset_t), &cpumask) != 0) {
                   4259:         i_errno = IEAFFINITY;
                   4260:         return -1;
                   4261:     }
                   4262:     return 0;
1.1.1.2 ! misho    4263: #elif defined(HAVE_SETPROCESSAFFINITYMASK)
        !          4264:        HANDLE process = GetCurrentProcess();
        !          4265:        DWORD_PTR processAffinityMask = 1 << affinity;
        !          4266: 
        !          4267:        if (SetProcessAffinityMask(process, processAffinityMask) == 0) {
        !          4268:                i_errno = IEAFFINITY;
        !          4269:                return -1;
        !          4270:        }
        !          4271:        return 0;
        !          4272: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1       misho    4273:     i_errno = IEAFFINITY;
                   4274:     return -1;
1.1.1.2 ! misho    4275: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1       misho    4276: }
                   4277: 
                   4278: int
                   4279: iperf_clearaffinity(struct iperf_test *test)
                   4280: {
                   4281: #if defined(HAVE_SCHED_SETAFFINITY)
                   4282:     cpu_set_t cpu_set;
                   4283:     int i;
                   4284: 
                   4285:     CPU_ZERO(&cpu_set);
                   4286:     for (i = 0; i < CPU_SETSIZE; ++i)
                   4287:        CPU_SET(i, &cpu_set);
                   4288:     if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
                   4289:        i_errno = IEAFFINITY;
                   4290:         return -1;
                   4291:     }
                   4292:     return 0;
                   4293: #elif defined(HAVE_CPUSET_SETAFFINITY)
                   4294:     if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
                   4295:                           sizeof(cpuset_t), &test->cpumask) != 0) {
                   4296:         i_errno = IEAFFINITY;
                   4297:         return -1;
                   4298:     }
                   4299:     return 0;
1.1.1.2 ! misho    4300: #elif defined(HAVE_SETPROCESSAFFINITYMASK)
        !          4301:        HANDLE process = GetCurrentProcess();
        !          4302:        DWORD_PTR processAffinityMask;
        !          4303:        DWORD_PTR lpSystemAffinityMask;
        !          4304: 
        !          4305:        if (GetProcessAffinityMask(process, &processAffinityMask, &lpSystemAffinityMask) == 0
        !          4306:                        || SetProcessAffinityMask(process, lpSystemAffinityMask) == 0) {
        !          4307:                i_errno = IEAFFINITY;
        !          4308:                return -1;
        !          4309:        }
        !          4310:        return 0;
        !          4311: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1       misho    4312:     i_errno = IEAFFINITY;
                   4313:     return -1;
1.1.1.2 ! misho    4314: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1       misho    4315: }
                   4316: 
1.1.1.2 ! misho    4317: char iperf_timestr[100];
        !          4318: 
1.1       misho    4319: int
1.1.1.2 ! misho    4320: iperf_printf(struct iperf_test *test, const char* format, ...)
1.1       misho    4321: {
                   4322:     va_list argp;
                   4323:     int r = -1;
1.1.1.2 ! misho    4324:     time_t now;
        !          4325:     struct tm *ltm = NULL;
        !          4326:     char *ct = NULL;
        !          4327: 
        !          4328:     /* Timestamp if requested */
        !          4329:     if (iperf_get_test_timestamps(test)) {
        !          4330:        time(&now);
        !          4331:        ltm = localtime(&now);
        !          4332:        strftime(iperf_timestr, sizeof(iperf_timestr), iperf_get_test_timestamp_format(test), ltm);
        !          4333:        ct = iperf_timestr;
        !          4334:     }
1.1       misho    4335: 
                   4336:     /*
                   4337:      * There are roughly two use cases here.  If we're the client,
                   4338:      * want to print stuff directly to the output stream.
                   4339:      * If we're the sender we might need to buffer up output to send
                   4340:      * to the client.
                   4341:      *
                   4342:      * This doesn't make a whole lot of difference except there are
                   4343:      * some chunks of output on the client (on particular the whole
                   4344:      * of the server output with --get-server-output) that could
                   4345:      * easily exceed the size of the line buffer, but which don't need
                   4346:      * to be buffered up anyway.
                   4347:      */
                   4348:     if (test->role == 'c') {
1.1.1.2 ! misho    4349:        if (ct) {
        !          4350:            fprintf(test->outfile, "%s", ct);
        !          4351:        }
1.1       misho    4352:        if (test->title)
                   4353:            fprintf(test->outfile, "%s:  ", test->title);
                   4354:        va_start(argp, format);
                   4355:        r = vfprintf(test->outfile, format, argp);
                   4356:        va_end(argp);
                   4357:     }
                   4358:     else if (test->role == 's') {
                   4359:        char linebuffer[1024];
1.1.1.2 ! misho    4360:        int i = 0;
        !          4361:        if (ct) {
        !          4362:            i = sprintf(linebuffer, "%s", ct);
        !          4363:        }
1.1       misho    4364:        va_start(argp, format);
1.1.1.2 ! misho    4365:        r = vsnprintf(linebuffer + i, sizeof(linebuffer), format, argp);
1.1       misho    4366:        va_end(argp);
                   4367:        fprintf(test->outfile, "%s", linebuffer);
                   4368: 
                   4369:        if (test->role == 's' && iperf_get_test_get_server_output(test)) {
                   4370:            struct iperf_textline *l = (struct iperf_textline *) malloc(sizeof(struct iperf_textline));
                   4371:            l->line = strdup(linebuffer);
                   4372:            TAILQ_INSERT_TAIL(&(test->server_output_list), l, textlineentries);
                   4373:        }
                   4374:     }
                   4375:     return r;
                   4376: }
                   4377: 
                   4378: int
                   4379: iflush(struct iperf_test *test)
                   4380: {
                   4381:     return fflush(test->outfile);
                   4382: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>