/* * thrulay_tu.c -- a thrulay library test utility. * * Written by Huadong Liu, http://www.cs.utk.edu/~hliu/ * * Copyright 2005, Internet2. * Legal conditions are in file LICENSE * (MD5 = ecfa50d1b0bfbb81b658c810d0476a52). */ #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <unistd.h> #include <errno.h> #include <string.h> #include "thrulay.h" #define MAXLINE 128 /* * Type of tests. */ typedef enum _test_type { TEST_INIT = 0, TEST_TCP_PROG_NORMAL, /* Progressively report test status. */ TEST_TCP_PROG_STOP, /* Progressively report test status, stop in middle */ TEST_TCP_LAZY_NORMAL, /* Report test status when test exits. -- TCP */ TEST_TCP_LAZY_STOP, /* Wait half of test duration then cancel. -- TCP */ TEST_UDP_LAZY_NORMAL, /* Report test status when test exits. -- UDP */ TEST_UDP_LAZY_STOP, /* Wait half of test duration then cancel. -- UDP*/ TEST_EXIT } test_type_t; /* * Print test menu. */ void print_menu() { fprintf(stderr, "\n"); fprintf(stderr, "1. TCP PROGRESSIVE TEST -- NORMAL\n"); fprintf(stderr, "2. TCP PROGRESSIVE TEST -- STOP IN MIDDLE\n"); fprintf(stderr, "3. TCP LAZY TEST -- NORMAL\n"); fprintf(stderr, "4. TCP LAZY TEST -- STOP IN MIDDLE\n"); fprintf(stderr, "5. UDP LAZY TEST --NORMAL\n"); fprintf(stderr, "6. UDP LAZY TEST -- STOP IN MIDDLE\n"); fprintf(stderr, "7. EXIT\n"); fprintf(stderr, "Your choice:"); } /* * Convert a string like "12k" to a number like 12000. Return zero on error. */ u_int64_t rate2i(char *s) { u_int64_t r; /* Result. */ char *p; int l; int suffix = 0; /* First, set the multiple. */ l = strlen(s); switch (s[l-1]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': r = 1; break; case 'k': case 'K': r = 1000; suffix = 1; break; case 'm': case 'M': r = 1000000; suffix = 1; break; case 'g': case 'G': r = 1000000000ULL; suffix = 1; break; case 't': case 'T': r = 1000000000000ULL; suffix = 1; break; default: r = 0; } if (suffix) s[l-1] = '\0'; r *= strtoll(s, &p, 10); if (!*s || *p) /* Invalid character found. */ r = 0; return r; } /* * Get an integer in range (min, max) from stdin. Allow default value by * simply hit Enter. */ int get_int(int min, int max) { char buffer[MAXLINE] = {0}; int number; char *p; while (1) { fgets(buffer, MAXLINE, stdin); p = strchr(buffer, '\n'); if (p == NULL) { fprintf(stderr, "Your choice is too long!\n"); exit(0); } if (p == buffer) return 0; *p = '\0'; number = atoi(buffer); if ((number > max) || (number < min)) { fprintf(stderr, "Invalid number, do it one more time\n"); continue; } return number; } } /* * Get a string from stdin. If empty is allowed, returns when Enter is hit. */ void get_str(char *buffer, int allow_empty) { char *p; while (1) { fgets(buffer, MAXLINE, stdin); p = strchr(buffer, '\n'); if (p == NULL) { fprintf(stderr, "Your choice is too long!\n"); exit(0); } if ((!allow_empty) && (p == buffer)) { fprintf(stderr, "Empty string, do it one more time\n"); } else { *p = '\0'; return; } } } /* * Read setting of a thrulay TCP test. */ void read_tcp_setting(thrulay_setting_tcp_t *setting_tcp) { int rc; char host[MAXLINE] = {0}; fprintf(stderr, "Server name:"); get_str(host, 0); setting_tcp->server_name = strdup(host); fprintf(stderr, "Server port [5003]:"); rc = get_int(5003, 9999); setting_tcp->server_port = rc ? rc : 5003; fprintf(stderr, "Test duration [60s]:"); rc = get_int(1, 24 * 60 * 60); setting_tcp->test_duration = rc ? rc : 60; fprintf(stderr, "Report_interval [1s]:"); rc = get_int(1, setting_tcp->test_duration); setting_tcp->report_interval = rc ? rc : 1; fprintf(stderr, "Window size [4194304B]:"); rc = get_int(1500, INT_MAX); setting_tcp->window_size = rc ? rc : 4194304; fprintf(stderr, "Block size [8192B]:"); rc = get_int(16, 1048576); setting_tcp->block_size = rc ? rc : 8192; fprintf(stderr, "Number of parallel streams [1]:"); rc = get_int(1, 64); setting_tcp->nstream = rc ? rc : 1; /* We do not check TOS byte here. If you want to do so, see thrulay.c. */ fprintf(stderr, "TOS byte [0]:"); rc = get_int(1, 255); setting_tcp->tos = rc ? rc : 0; fprintf(stderr, "\n"); } /* * Read setting of a thrulay UDP test. */ void read_udp_setting(thrulay_setting_udp_t *setting_udp) { int rc; char buffer[MAXLINE] = {0}; fprintf(stderr, "Server name:"); get_str(buffer, 0); setting_udp->server_name = strdup(buffer); fprintf(stderr, "Server port [5003]:"); rc = get_int(5003, 9999); setting_udp->server_port = rc ? rc : 5003; fprintf(stderr, "Test duration [60s]:"); rc = get_int(1, 24 * 60 * 60); setting_udp->test_duration = rc ? rc : 60; fprintf(stderr, "UDP buffer size [4194304B]:"); rc = get_int(1500, INT_MAX); setting_udp->udp_buffer_size = rc ? rc : 4194304; fprintf(stderr, "Packet size [1500B]:"); rc = get_int(20+8, 1048576); setting_udp->packet_size = rc ? rc : 1500; fprintf(stderr, "Number of parallel streams [1]:"); rc = get_int(1, 64); setting_udp->nstream = rc ? rc : 1; fprintf(stderr, "TOS byte [0]:"); rc = get_int(1, 255); setting_udp->tos = rc ? rc : 0; setting_udp->rate = 0; while (!setting_udp->rate) { fprintf(stderr, "Sending rate (KMGT/s):"); get_str(buffer, 0); setting_udp->rate = rate2i(buffer); } fprintf(stderr, "Busy wait (yes/no) [yes]:"); get_str(buffer, 1); if ((buffer[0] = 'n') || (buffer[0] = 'N')) { setting_udp->wt = THRULAY_NONBUSYWAIT; } else { setting_udp->wt = THRULAY_BUSYWAIT; } fprintf(stderr, "\n"); } /* * Show how to get a thrulay report. You can further print individual * report fields as in thrulay.c. */ void print_report(int tid, int nstream, int from, int to) { int i, j; thrulay_report_tcp_t report; for (i=0; i<nstream; i++) { for (j=from; j<to; j++) { if (0 != thrulay_get_report(tid, i, j+1, &report)) { fprintf(stderr, "cannot get the %dth report " "of the %d-th stream\n", j+1, i+1); } else { fprintf(stderr, "get report[%d] of stream[%d]\n", j+1, i+1); } /* if */ } /* for j */ } /* for i */ return; } /* * Do a progressive TCP test. If half_stop is set, the test will be * terminated in the middle. Note that you do not have to close the * test before you call thrulay_exit(). thrulay_exit() will do this * for you. */ void perform_prog_test(thrulay_setting_tcp_t *setting_tcp, int half_stop) { int rc; int tid; int status; int already_got = 0; int elapsed = 0; rc = thrulay_init(); /* Initialize the thrulay library. */ if (rc < 0) { thrulay_err_msg(rc); fprintf(stderr, "could not initialize thrulay lib\n"); return; } else { fprintf(stderr, "initialize thrulay library successfully\n"); } tid = thrulay_open(THRULAY_TCP, setting_tcp); /* Setup the test. */ if (tid < 1) { thrulay_err_msg(tid); fprintf(stderr, "open a TCP test failed\n"); thrulay_exit(); return; } else { fprintf(stderr, "open a test successfully, tid = %d\n", tid); } rc = thrulay_start(tid); /* Start the test. */ if (tid != rc) { thrulay_err_msg(rc); fprintf(stderr, "start a test %d failed\n", tid); if (0 != (rc=thrulay_close(tid))) { thrulay_err_msg(rc); fprintf(stderr, "cannot close a test %d\n", tid); } thrulay_exit(); return; } sleep(setting_tcp->report_interval); do { rc = thrulay_wait(tid, &status, THRULAY_POLL); if (rc < 0) { thrulay_err_msg(rc); fprintf(stderr, "poll test status failed\n"); thrulay_exit(); return; } else if (rc == 0) { if (status == 0) { usleep(1000); continue; } else { print_report(tid, setting_tcp->nstream, already_got, status); already_got = status; } elapsed += setting_tcp->report_interval; if (half_stop && (elapsed >= setting_tcp->test_duration/2)) break; sleep(setting_tcp->report_interval); } else { if (status > 0) { print_report(tid, setting_tcp->nstream, already_got, status); } else if (status < 0) { thrulay_err_msg(status); fprintf(stderr, "test %d exit with error\n", tid); } } } while (rc != tid); if (half_stop) { rc = thrulay_wait(tid, &status, THRULAY_STOP); if (tid != rc) { thrulay_err_msg(rc); fprintf(stderr, "stop test %d failed\n", tid); if (0 != thrulay_close(tid)) { fprintf(stderr, "cannot close a test %d\n", tid); } thrulay_exit(); return; } else { fprintf(stderr, "test %d stopped\n", tid); print_report(tid, setting_tcp->nstream, already_got, status); } } thrulay_exit(); /* exit() should call close() */ fprintf(stderr, "cleanup thrulay libray successfully\n"); } void perform_lazy_test(thrulay_traffic_type_t type, void *setting, int half_stop) { int tid; /* unique test id */ int rc; int status; int nstream; int i, j; void *report; thrulay_report_tcp_t rpt_tcp; thrulay_report_udp_t rpt_udp; thrulay_setting_tcp_t *setting_tcp; thrulay_setting_udp_t *setting_udp; if (type == THRULAY_TCP) { setting_tcp = (thrulay_setting_tcp_t *)setting; nstream = setting_tcp->nstream; } else { setting_udp = (thrulay_setting_udp_t *)setting; nstream = setting_udp->nstream; } rc = thrulay_init(); /* Initialize the thrulay library. */ if (rc < 0) { thrulay_err_msg(rc); fprintf(stderr, "could not initialize thrulay lib\n"); return; } else { fprintf(stderr, "initialize thrulay library successfully\n"); } tid = thrulay_open(type, setting); /* Setup the test. */ if (tid < 1) { thrulay_err_msg(tid); fprintf(stderr, "open a test failed\n"); thrulay_exit(); return; } else { fprintf(stderr, "open a test successfully, tid = %d\n", tid); } rc = thrulay_start(tid); /* Start the test. */ if (tid != rc) { thrulay_err_msg(rc); fprintf(stderr, "start a test %d failed\n", tid); if (0 != thrulay_close(tid)) { fprintf(stderr, "cannot close a test %d\n", tid); } thrulay_exit(); return; } if (half_stop) { if (type == THRULAY_TCP) { sleep(setting_tcp->test_duration/2); } else { sleep(setting_udp->test_duration/2); } rc = thrulay_wait(tid, &status, THRULAY_STOP); if (tid != rc) { fprintf(stderr, "stop test %d failed\n", tid); if ((rc=thrulay_close(tid)) != 0) { thrulay_err_msg(rc); fprintf(stderr, "cannot close a test %d\n", tid); } thrulay_exit(); return; } else { fprintf(stderr, "test %d stopped, # of reports=%d\n", tid, status); } } else { rc = thrulay_wait(tid, &status, THRULAY_WAIT); if (tid != rc) { thrulay_err_msg(rc); fprintf(stderr, "wait for test %d failed\n", tid); if ((rc=thrulay_close(tid)) != 0) { thrulay_err_msg(rc); fprintf(stderr, "cannot close a test %d\n", tid); } thrulay_exit(); return; } else { fprintf(stderr, "test %d finished, # of reports=%d\n", tid, status); } } for (i=0; i<nstream; i++) { for (j=1; j<=status; j++) { if (type == THRULAY_TCP) { report = &rpt_tcp; } else { report = &rpt_udp; } if (0 != (rc=thrulay_get_report(tid, i, j, report))) { thrulay_err_msg(rc); fprintf(stderr, "cannot get the %dth report of the %d-th" "stream\n", j, i+1); } else { fprintf(stderr, "get report[%d] of stream[%d]\n", j, i+1); } } } thrulay_exit(); /* exit() should call close() */ fprintf(stderr, "cleanup thrulay libray successfully\n"); } int main(int argc, char *argv[]) { thrulay_setting_tcp_t setting_tcp; /* settings for TCP test */ thrulay_setting_udp_t setting_udp; /* settings for UDP test */ test_type_t nextstep = TEST_INIT; while (nextstep != TEST_EXIT) { switch (nextstep) { case TEST_INIT: print_menu(); nextstep = get_int(TEST_TCP_PROG_NORMAL, TEST_EXIT); break; case TEST_TCP_PROG_NORMAL: read_tcp_setting(&setting_tcp); perform_prog_test(&setting_tcp, 0); nextstep = TEST_INIT; break; case TEST_TCP_PROG_STOP: read_tcp_setting(&setting_tcp); perform_prog_test(&setting_tcp, 1); nextstep = TEST_INIT; break; case TEST_TCP_LAZY_NORMAL: read_tcp_setting(&setting_tcp); perform_lazy_test(THRULAY_TCP, &setting_tcp, 0); nextstep = TEST_INIT; break; case TEST_TCP_LAZY_STOP: read_tcp_setting(&setting_tcp); perform_lazy_test(THRULAY_TCP, &setting_tcp, 1); nextstep = TEST_INIT; break; case TEST_UDP_LAZY_NORMAL: read_udp_setting(&setting_udp); perform_lazy_test(THRULAY_UDP, &setting_udp, 0); nextstep = TEST_INIT; break; case TEST_UDP_LAZY_STOP: read_udp_setting(&setting_udp); perform_lazy_test(THRULAY_UDP, &setting_udp, 1); nextstep = TEST_INIT; break; default: break; } } exit(0); }