Annotation of embedaddon/iperf/src/iperf_client_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
                     25:  * file for complete information.
                     26:  */
                     27: #include <errno.h>
                     28: #include <setjmp.h>
                     29: #include <stdio.h>
                     30: #include <stdlib.h>
                     31: #include <string.h>
                     32: #include <unistd.h>
                     33: #include <signal.h>
                     34: #include <sys/types.h>
1.1.1.2   misho      35: #include <netinet/in.h>
1.1       misho      36: #include <sys/select.h>
                     37: #include <sys/uio.h>
                     38: #include <arpa/inet.h>
                     39: 
                     40: #include "iperf.h"
                     41: #include "iperf_api.h"
                     42: #include "iperf_util.h"
                     43: #include "iperf_locale.h"
1.1.1.2   misho      44: #include "iperf_time.h"
1.1       misho      45: #include "net.h"
                     46: #include "timer.h"
                     47: 
1.1.1.2   misho      48: #if defined(HAVE_TCP_CONGESTION)
                     49: #if !defined(TCP_CA_NAME_MAX)
                     50: #define TCP_CA_NAME_MAX 16
                     51: #endif /* TCP_CA_NAME_MAX */
                     52: #endif /* HAVE_TCP_CONGESTION */
1.1       misho      53: 
                     54: int
1.1.1.2   misho      55: iperf_create_streams(struct iperf_test *test, int sender)
1.1       misho      56: {
1.1.1.3 ! misho      57:     if (NULL == test)
        !            58:     {
        !            59:         iperf_err(NULL, "No test\n");
        !            60:         return -1;
        !            61:     }
1.1       misho      62:     int i, s;
1.1.1.2   misho      63: #if defined(HAVE_TCP_CONGESTION)
                     64:     int saved_errno;
                     65: #endif /* HAVE_TCP_CONGESTION */
1.1       misho      66:     struct iperf_stream *sp;
                     67: 
                     68:     int orig_bind_port = test->bind_port;
                     69:     for (i = 0; i < test->num_streams; ++i) {
                     70: 
                     71:         test->bind_port = orig_bind_port;
1.1.1.3 ! misho      72:        if (orig_bind_port) {
1.1       misho      73:            test->bind_port += i;
1.1.1.3 ! misho      74:             // If Bidir make sure send and receive ports are different
        !            75:             if (!sender && test->mode == BIDIRECTIONAL)
        !            76:                 test->bind_port += test->num_streams;
        !            77:         }
        !            78:         s = test->protocol->connect(test);
        !            79:         test->bind_port = orig_bind_port;
        !            80:         if (s < 0)
1.1       misho      81:             return -1;
                     82: 
1.1.1.2   misho      83: #if defined(HAVE_TCP_CONGESTION)
                     84:        if (test->protocol->id == Ptcp) {
                     85:            if (test->congestion) {
                     86:                if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
                     87:                    saved_errno = errno;
                     88:                    close(s);
                     89:                    errno = saved_errno;
                     90:                    i_errno = IESETCONGESTION;
                     91:                    return -1;
1.1.1.3 ! misho      92:                }
1.1.1.2   misho      93:            }
                     94:            {
                     95:                socklen_t len = TCP_CA_NAME_MAX;
                     96:                char ca[TCP_CA_NAME_MAX + 1];
1.1.1.3 ! misho      97:                 int rc;
        !            98:                rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
        !            99:                 if (rc < 0 && test->congestion) {
1.1.1.2   misho     100:                    saved_errno = errno;
                    101:                    close(s);
                    102:                    errno = saved_errno;
                    103:                    i_errno = IESETCONGESTION;
                    104:                    return -1;
                    105:                }
1.1.1.3 ! misho     106:                 // Set actual used congestion alg, or set to unknown if could not get it
        !           107:                 if (rc < 0)
        !           108:                     test->congestion_used = strdup("unknown");
        !           109:                 else
        !           110:                     test->congestion_used = strdup(ca);
1.1.1.2   misho     111:                if (test->debug) {
                    112:                    printf("Congestion algorithm is %s\n", test->congestion_used);
                    113:                }
                    114:            }
                    115:        }
                    116: #endif /* HAVE_TCP_CONGESTION */
                    117: 
                    118:        if (sender)
1.1       misho     119:            FD_SET(s, &test->write_set);
                    120:        else
                    121:            FD_SET(s, &test->read_set);
                    122:        if (s > test->max_fd) test->max_fd = s;
                    123: 
1.1.1.2   misho     124:         sp = iperf_new_stream(test, s, sender);
1.1       misho     125:         if (!sp)
                    126:             return -1;
                    127: 
                    128:         /* Perform the new stream callback */
                    129:         if (test->on_new_stream)
                    130:             test->on_new_stream(sp);
                    131:     }
                    132: 
                    133:     return 0;
                    134: }
                    135: 
                    136: static void
1.1.1.2   misho     137: test_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1       misho     138: {
                    139:     struct iperf_test *test = client_data.p;
                    140: 
                    141:     test->timer = NULL;
                    142:     test->done = 1;
                    143: }
                    144: 
                    145: static void
1.1.1.2   misho     146: client_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1       misho     147: {
                    148:     struct iperf_test *test = client_data.p;
                    149: 
                    150:     if (test->done)
                    151:         return;
                    152:     if (test->stats_callback)
                    153:        test->stats_callback(test);
                    154: }
                    155: 
                    156: static void
1.1.1.2   misho     157: client_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1       misho     158: {
                    159:     struct iperf_test *test = client_data.p;
                    160: 
                    161:     if (test->done)
                    162:         return;
                    163:     if (test->reporter_callback)
                    164:        test->reporter_callback(test);
                    165: }
                    166: 
                    167: static int
                    168: create_client_timers(struct iperf_test * test)
                    169: {
1.1.1.2   misho     170:     struct iperf_time now;
1.1       misho     171:     TimerClientData cd;
1.1.1.3 ! misho     172:     if (NULL == test)
        !           173:     {
        !           174:         iperf_err(NULL, "No test\n");
        !           175:         i_errno = IEINITTEST;
        !           176:         return -1;
        !           177:     }
1.1       misho     178: 
1.1.1.2   misho     179:     if (iperf_time_now(&now) < 0) {
1.1       misho     180:        i_errno = IEINITTEST;
                    181:        return -1;
                    182:     }
                    183:     cd.p = test;
                    184:     test->timer = test->stats_timer = test->reporter_timer = NULL;
                    185:     if (test->duration != 0) {
                    186:        test->done = 0;
                    187:         test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0);
                    188:         if (test->timer == NULL) {
                    189:             i_errno = IEINITTEST;
                    190:             return -1;
                    191:        }
1.1.1.3 ! misho     192:     }
1.1       misho     193:     if (test->stats_interval != 0) {
                    194:         test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
                    195:         if (test->stats_timer == NULL) {
                    196:             i_errno = IEINITTEST;
                    197:             return -1;
                    198:        }
                    199:     }
                    200:     if (test->reporter_interval != 0) {
                    201:         test->reporter_timer = tmr_create(&now, client_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
                    202:         if (test->reporter_timer == NULL) {
                    203:             i_errno = IEINITTEST;
                    204:             return -1;
                    205:        }
                    206:     }
                    207:     return 0;
                    208: }
                    209: 
                    210: static void
1.1.1.2   misho     211: client_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1       misho     212: {
                    213:     struct iperf_test *test = client_data.p;
                    214: 
                    215:     test->omit_timer = NULL;
                    216:     test->omitting = 0;
                    217:     iperf_reset_stats(test);
                    218:     if (test->verbose && !test->json_output && test->reporter_interval == 0)
1.1.1.2   misho     219:         iperf_printf(test, "%s", report_omit_done);
1.1       misho     220: 
                    221:     /* Reset the timers. */
                    222:     if (test->stats_timer != NULL)
                    223:         tmr_reset(nowP, test->stats_timer);
                    224:     if (test->reporter_timer != NULL)
                    225:         tmr_reset(nowP, test->reporter_timer);
                    226: }
                    227: 
                    228: static int
                    229: create_client_omit_timer(struct iperf_test * test)
                    230: {
1.1.1.2   misho     231:     struct iperf_time now;
1.1       misho     232:     TimerClientData cd;
1.1.1.3 ! misho     233:     if (NULL == test)
        !           234:     {
        !           235:         iperf_err(NULL, "No test\n");
        !           236:         return -1;
        !           237:     }
1.1       misho     238: 
                    239:     if (test->omit == 0) {
                    240:        test->omit_timer = NULL;
                    241:         test->omitting = 0;
                    242:     } else {
1.1.1.2   misho     243:        if (iperf_time_now(&now) < 0) {
1.1       misho     244:            i_errno = IEINITTEST;
                    245:            return -1;
                    246:        }
                    247:        test->omitting = 1;
                    248:        cd.p = test;
                    249:        test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
                    250:        if (test->omit_timer == NULL) {
                    251:            i_errno = IEINITTEST;
                    252:            return -1;
                    253:        }
                    254:     }
                    255:     return 0;
                    256: }
                    257: 
                    258: int
                    259: iperf_handle_message_client(struct iperf_test *test)
                    260: {
                    261:     int rval;
                    262:     int32_t err;
                    263: 
1.1.1.3 ! misho     264:     if (NULL == test)
        !           265:     {
        !           266:         iperf_err(NULL, "No test\n");
        !           267:        i_errno = IEINITTEST;
        !           268:         return -1;
        !           269:     }
1.1       misho     270:     /*!!! Why is this read() and not Nread()? */
                    271:     if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
                    272:         if (rval == 0) {
                    273:             i_errno = IECTRLCLOSE;
                    274:             return -1;
                    275:         } else {
                    276:             i_errno = IERECVMESSAGE;
                    277:             return -1;
                    278:         }
                    279:     }
                    280: 
                    281:     switch (test->state) {
                    282:         case PARAM_EXCHANGE:
                    283:             if (iperf_exchange_parameters(test) < 0)
                    284:                 return -1;
                    285:             if (test->on_connect)
                    286:                 test->on_connect(test);
                    287:             break;
                    288:         case CREATE_STREAMS:
1.1.1.2   misho     289:             if (test->mode == BIDIRECTIONAL)
                    290:             {
                    291:                 if (iperf_create_streams(test, 1) < 0)
                    292:                     return -1;
                    293:                 if (iperf_create_streams(test, 0) < 0)
                    294:                     return -1;
                    295:             }
                    296:             else if (iperf_create_streams(test, test->mode) < 0)
1.1       misho     297:                 return -1;
                    298:             break;
                    299:         case TEST_START:
                    300:             if (iperf_init_test(test) < 0)
                    301:                 return -1;
                    302:             if (create_client_timers(test) < 0)
                    303:                 return -1;
                    304:             if (create_client_omit_timer(test) < 0)
                    305:                 return -1;
1.1.1.2   misho     306:            if (test->mode)
1.1       misho     307:                if (iperf_create_send_timers(test) < 0)
                    308:                    return -1;
                    309:             break;
                    310:         case TEST_RUNNING:
                    311:             break;
                    312:         case EXCHANGE_RESULTS:
                    313:             if (iperf_exchange_results(test) < 0)
                    314:                 return -1;
                    315:             break;
                    316:         case DISPLAY_RESULTS:
                    317:             if (test->on_test_finish)
                    318:                 test->on_test_finish(test);
                    319:             iperf_client_end(test);
                    320:             break;
                    321:         case IPERF_DONE:
                    322:             break;
                    323:         case SERVER_TERMINATE:
                    324:             i_errno = IESERVERTERM;
                    325: 
                    326:            /*
                    327:             * Temporarily be in DISPLAY_RESULTS phase so we can get
                    328:             * ending summary statistics.
                    329:             */
                    330:            signed char oldstate = test->state;
                    331:            cpu_util(test->cpu_util);
                    332:            test->state = DISPLAY_RESULTS;
                    333:            test->reporter_callback(test);
                    334:            test->state = oldstate;
                    335:             return -1;
                    336:         case ACCESS_DENIED:
                    337:             i_errno = IEACCESSDENIED;
                    338:             return -1;
                    339:         case SERVER_ERROR:
                    340:             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
                    341:                 i_errno = IECTRLREAD;
                    342:                 return -1;
                    343:             }
                    344:            i_errno = ntohl(err);
                    345:             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
                    346:                 i_errno = IECTRLREAD;
                    347:                 return -1;
                    348:             }
                    349:             errno = ntohl(err);
                    350:             return -1;
                    351:         default:
                    352:             i_errno = IEMESSAGE;
                    353:             return -1;
                    354:     }
                    355: 
                    356:     return 0;
                    357: }
                    358: 
                    359: 
                    360: 
                    361: /* iperf_connect -- client to server connection function */
                    362: int
                    363: iperf_connect(struct iperf_test *test)
                    364: {
1.1.1.3 ! misho     365:     int opt;
        !           366:     socklen_t len;
        !           367: 
        !           368:     if (NULL == test)
        !           369:     {
        !           370:         iperf_err(NULL, "No test\n");
        !           371:         return -1;
        !           372:     }
1.1       misho     373:     FD_ZERO(&test->read_set);
                    374:     FD_ZERO(&test->write_set);
                    375: 
                    376:     make_cookie(test->cookie);
                    377: 
                    378:     /* Create and connect the control channel */
                    379:     if (test->ctrl_sck < 0)
                    380:        // Create the control channel using an ephemeral port
1.1.1.3 ! misho     381:        test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout);
1.1       misho     382:     if (test->ctrl_sck < 0) {
                    383:         i_errno = IECONNECT;
                    384:         return -1;
                    385:     }
                    386: 
1.1.1.3 ! misho     387:     // set TCP_NODELAY for lower latency on control messages
        !           388:     int flag = 1;
        !           389:     if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
        !           390:         i_errno = IESETNODELAY;
        !           391:         return -1;
        !           392:     }
        !           393: 
        !           394: #if defined(HAVE_TCP_USER_TIMEOUT)
        !           395:     if ((opt = test->settings->snd_timeout)) {
        !           396:         if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
        !           397:         i_errno = IESETUSERTIMEOUT;
        !           398:         return -1;
        !           399:         }
        !           400:     }
        !           401: #endif /* HAVE_TCP_USER_TIMEOUT */
        !           402: 
1.1       misho     403:     if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
                    404:         i_errno = IESENDCOOKIE;
                    405:         return -1;
                    406:     }
                    407: 
                    408:     FD_SET(test->ctrl_sck, &test->read_set);
                    409:     if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
                    410: 
1.1.1.2   misho     411:     len = sizeof(opt);
                    412:     if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
                    413:         test->ctrl_sck_mss = 0;
                    414:     }
                    415:     else {
                    416:         if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
                    417:             test->ctrl_sck_mss = opt;
                    418:         }
                    419:         else {
1.1.1.3 ! misho     420:             char str[WARN_STR_LEN];
1.1.1.2   misho     421:             snprintf(str, sizeof(str),
                    422:                      "Ignoring nonsense TCP MSS %d", opt);
                    423:             warning(str);
                    424: 
                    425:             test->ctrl_sck_mss = 0;
                    426:         }
                    427:     }
                    428: 
                    429:     if (test->verbose) {
                    430:        printf("Control connection MSS %d\n", test->ctrl_sck_mss);
                    431:     }
                    432: 
                    433:     /*
                    434:      * If we're doing a UDP test and the block size wasn't explicitly
                    435:      * set, then use the known MSS of the control connection to pick
                    436:      * an appropriate default.  If we weren't able to get the
                    437:      * MSS for some reason, then default to something that should
                    438:      * work on non-jumbo-frame Ethernet networks.  The goal is to
                    439:      * pick a reasonable default that is large but should get from
                    440:      * sender to receiver without any IP fragmentation.
                    441:      *
                    442:      * We assume that the control connection is routed the same as the
                    443:      * data packets (thus has the same PMTU).  Also in the case of
                    444:      * --reverse tests, we assume that the MTU is the same in both
                    445:      * directions.  Note that even if the algorithm guesses wrong,
                    446:      * the user always has the option to override.
                    447:      */
                    448:     if (test->protocol->id == Pudp) {
                    449:        if (test->settings->blksize == 0) {
                    450:            if (test->ctrl_sck_mss) {
                    451:                test->settings->blksize = test->ctrl_sck_mss;
                    452:            }
                    453:            else {
                    454:                test->settings->blksize = DEFAULT_UDP_BLKSIZE;
                    455:            }
                    456:            if (test->verbose) {
                    457:                printf("Setting UDP block size to %d\n", test->settings->blksize);
                    458:            }
                    459:        }
                    460: 
                    461:        /*
                    462:         * Regardless of whether explicitly or implicitly set, if the
                    463:         * block size is larger than the MSS, print a warning.
                    464:         */
                    465:        if (test->ctrl_sck_mss > 0 &&
                    466:            test->settings->blksize > test->ctrl_sck_mss) {
1.1.1.3 ! misho     467:            char str[WARN_STR_LEN];
1.1.1.2   misho     468:            snprintf(str, sizeof(str),
                    469:                     "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
                    470:            warning(str);
                    471:        }
                    472:     }
                    473: 
1.1       misho     474:     return 0;
                    475: }
                    476: 
                    477: 
                    478: int
                    479: iperf_client_end(struct iperf_test *test)
                    480: {
1.1.1.3 ! misho     481:     if (NULL == test)
        !           482:     {
        !           483:         iperf_err(NULL, "No test\n");
        !           484:         return -1;
        !           485:     }
1.1       misho     486:     struct iperf_stream *sp;
                    487: 
                    488:     /* Close all stream sockets */
                    489:     SLIST_FOREACH(sp, &test->streams, streams) {
                    490:         close(sp->socket);
                    491:     }
                    492: 
                    493:     /* show final summary */
                    494:     test->reporter_callback(test);
                    495: 
1.1.1.3 ! misho     496:     /* Send response only if no error in server */
        !           497:     if (test->state > 0) {
        !           498:         if (iperf_set_send_state(test, IPERF_DONE) != 0)
        !           499:             return -1;
        !           500:     }
1.1       misho     501: 
1.1.1.2   misho     502:     /* Close control socket */
1.1.1.3 ! misho     503:     if (test->ctrl_sck >= 0)
1.1.1.2   misho     504:         close(test->ctrl_sck);
                    505: 
1.1       misho     506:     return 0;
                    507: }
                    508: 
                    509: 
                    510: int
                    511: iperf_run_client(struct iperf_test * test)
                    512: {
                    513:     int startup;
                    514:     int result = 0;
                    515:     fd_set read_set, write_set;
1.1.1.2   misho     516:     struct iperf_time now;
1.1       misho     517:     struct timeval* timeout = NULL;
                    518:     struct iperf_stream *sp;
1.1.1.3 ! misho     519:     struct iperf_time last_receive_time;
        !           520:     struct iperf_time diff_time;
        !           521:     struct timeval used_timeout;
        !           522:     int64_t t_usecs;
        !           523:     int64_t timeout_us;
        !           524:     int64_t rcv_timeout_us;
        !           525: 
        !           526:     if (NULL == test)
        !           527:     {
        !           528:         iperf_err(NULL, "No test\n");
        !           529:         return -1;
        !           530:     }
1.1       misho     531: 
1.1.1.2   misho     532:     if (test->logfile)
                    533:         if (iperf_open_logfile(test) < 0)
                    534:             return -1;
                    535: 
1.1       misho     536:     if (test->affinity != -1)
                    537:        if (iperf_setaffinity(test, test->affinity) != 0)
                    538:            return -1;
                    539: 
                    540:     if (test->json_output)
                    541:        if (iperf_json_start(test) < 0)
                    542:            return -1;
                    543: 
                    544:     if (test->json_output) {
                    545:        cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
                    546:        cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
                    547:     } else if (test->verbose) {
1.1.1.2   misho     548:        iperf_printf(test, "%s\n", version);
                    549:        iperf_printf(test, "%s", "");
                    550:        iperf_printf(test, "%s\n", get_system_info());
1.1       misho     551:        iflush(test);
                    552:     }
                    553: 
                    554:     /* Start the client and connect to the server */
                    555:     if (iperf_connect(test) < 0)
1.1.1.2   misho     556:         goto cleanup_and_fail;
1.1       misho     557: 
                    558:     /* Begin calculating CPU utilization */
                    559:     cpu_util(NULL);
1.1.1.3 ! misho     560:     if (test->mode != SENDER)
        !           561:         rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
        !           562:     else
        !           563:         rcv_timeout_us = 0;
1.1       misho     564: 
                    565:     startup = 1;
                    566:     while (test->state != IPERF_DONE) {
                    567:        memcpy(&read_set, &test->read_set, sizeof(fd_set));
                    568:        memcpy(&write_set, &test->write_set, sizeof(fd_set));
1.1.1.2   misho     569:        iperf_time_now(&now);
1.1       misho     570:        timeout = tmr_timeout(&now);
1.1.1.3 ! misho     571: 
        !           572:         // In reverse active mode client ensures data is received
        !           573:         if (test->state == TEST_RUNNING && rcv_timeout_us > 0) {
        !           574:             timeout_us = -1;
        !           575:             if (timeout != NULL) {
        !           576:                 used_timeout.tv_sec = timeout->tv_sec;
        !           577:                 used_timeout.tv_usec = timeout->tv_usec;
        !           578:                 timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec;
        !           579:             }
        !           580:             if (timeout_us < 0 || timeout_us > rcv_timeout_us) {
        !           581:                 used_timeout.tv_sec = test->settings->rcv_timeout.secs;
        !           582:                 used_timeout.tv_usec = test->settings->rcv_timeout.usecs;
        !           583:             }
        !           584:             timeout = &used_timeout;
        !           585:         }
        !           586: 
1.1       misho     587:        result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
                    588:        if (result < 0 && errno != EINTR) {
                    589:            i_errno = IESELECT;
1.1.1.2   misho     590:            goto cleanup_and_fail;
1.1.1.3 ! misho     591:         } else if (result == 0 && test->state == TEST_RUNNING && rcv_timeout_us > 0) {
        !           592:             // If nothing was received in non-reverse running state then probably something got stack -
        !           593:             // either client, server or network, and test should be terminated.
        !           594:             iperf_time_now(&now);
        !           595:             if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
        !           596:                 t_usecs = iperf_time_in_usecs(&diff_time);
        !           597:                 if (t_usecs > rcv_timeout_us) {
        !           598:                     i_errno = IENOMSG;
        !           599:                     goto cleanup_and_fail;
        !           600:                 }
        !           601: 
        !           602:             }
        !           603:         }
        !           604: 
1.1       misho     605:        if (result > 0) {
1.1.1.3 ! misho     606:             if (rcv_timeout_us > 0) {
        !           607:                 iperf_time_now(&last_receive_time);
        !           608:             }
1.1       misho     609:            if (FD_ISSET(test->ctrl_sck, &read_set)) {
                    610:                if (iperf_handle_message_client(test) < 0) {
1.1.1.2   misho     611:                    goto cleanup_and_fail;
1.1       misho     612:                }
                    613:                FD_CLR(test->ctrl_sck, &read_set);
                    614:            }
                    615:        }
                    616: 
                    617:        if (test->state == TEST_RUNNING) {
                    618: 
                    619:            /* Is this our first time really running? */
                    620:            if (startup) {
                    621:                startup = 0;
                    622: 
                    623:                // Set non-blocking for non-UDP tests
                    624:                if (test->protocol->id != Pudp) {
                    625:                    SLIST_FOREACH(sp, &test->streams, streams) {
                    626:                        setnonblocking(sp->socket, 1);
                    627:                    }
                    628:                }
                    629:            }
                    630: 
1.1.1.2   misho     631: 
                    632:            if (test->mode == BIDIRECTIONAL)
                    633:            {
                    634:                 if (iperf_send(test, &write_set) < 0)
                    635:                     goto cleanup_and_fail;
                    636:                 if (iperf_recv(test, &read_set) < 0)
                    637:                     goto cleanup_and_fail;
                    638:            } else if (test->mode == SENDER) {
                    639:                 // Regular mode. Client sends.
                    640:                 if (iperf_send(test, &write_set) < 0)
                    641:                     goto cleanup_and_fail;
1.1       misho     642:            } else {
1.1.1.2   misho     643:                 // Reverse mode. Client receives.
                    644:                 if (iperf_recv(test, &read_set) < 0)
                    645:                     goto cleanup_and_fail;
1.1       misho     646:            }
                    647: 
1.1.1.2   misho     648: 
1.1       misho     649:             /* Run the timers. */
1.1.1.2   misho     650:             iperf_time_now(&now);
1.1       misho     651:             tmr_run(&now);
                    652: 
1.1.1.3 ! misho     653:            /*
        !           654:             * Is the test done yet?  We have to be out of omitting
        !           655:             * mode, and then we have to have fulfilled one of the
        !           656:             * ending criteria, either by times, bytes, or blocks.
        !           657:             * The bytes and blocks tests needs to handle both the
        !           658:             * cases of the client being the sender and the client
        !           659:             * being the receiver.
        !           660:             */
1.1       misho     661:            if ((!test->omitting) &&
1.1.1.3 ! misho     662:                (test->done ||
        !           663:                 (test->settings->bytes != 0 && (test->bytes_sent >= test->settings->bytes ||
        !           664:                                                 test->bytes_received >= test->settings->bytes)) ||
        !           665:                 (test->settings->blocks != 0 && (test->blocks_sent >= test->settings->blocks ||
        !           666:                                                  test->blocks_received >= test->settings->blocks)))) {
1.1       misho     667: 
                    668:                // Unset non-blocking for non-UDP tests
                    669:                if (test->protocol->id != Pudp) {
                    670:                    SLIST_FOREACH(sp, &test->streams, streams) {
                    671:                        setnonblocking(sp->socket, 0);
                    672:                    }
                    673:                }
                    674: 
                    675:                /* Yes, done!  Send TEST_END. */
                    676:                test->done = 1;
                    677:                cpu_util(test->cpu_util);
                    678:                test->stats_callback(test);
                    679:                if (iperf_set_send_state(test, TEST_END) != 0)
1.1.1.2   misho     680:                     goto cleanup_and_fail;
1.1       misho     681:            }
                    682:        }
                    683:        // If we're in reverse mode, continue draining the data
                    684:        // connection(s) even if test is over.  This prevents a
                    685:        // deadlock where the server side fills up its pipe(s)
                    686:        // and gets blocked, so it can't receive state changes
                    687:        // from the client side.
1.1.1.2   misho     688:        else if (test->mode == RECEIVER && test->state == TEST_END) {
1.1       misho     689:            if (iperf_recv(test, &read_set) < 0)
1.1.1.2   misho     690:                goto cleanup_and_fail;
1.1       misho     691:        }
                    692:     }
                    693: 
                    694:     if (test->json_output) {
                    695:        if (iperf_json_finish(test) < 0)
                    696:            return -1;
                    697:     } else {
1.1.1.2   misho     698:        iperf_printf(test, "\n");
                    699:        iperf_printf(test, "%s", report_done);
1.1       misho     700:     }
                    701: 
                    702:     iflush(test);
                    703: 
                    704:     return 0;
1.1.1.2   misho     705: 
                    706:   cleanup_and_fail:
                    707:     iperf_client_end(test);
1.1.1.3 ! misho     708:     if (test->json_output) {
        !           709:         cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
        !           710:         iperf_json_finish(test);
        !           711:     }
1.1.1.2   misho     712:     iflush(test);
                    713:     return -1;
1.1       misho     714: }

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