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

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

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