| /*--------------------------------------------------------------- |
| * Copyright (c) 1999,2000,2001,2002,2003 |
| * The Board of Trustees of the University of Illinois |
| * All Rights Reserved. |
| *--------------------------------------------------------------- |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software (Iperf) and associated |
| * documentation files (the "Software"), to deal in the Software |
| * without restriction, including without limitation the |
| * rights to use, copy, modify, merge, publish, distribute, |
| * sublicense, and/or sell copies of the Software, and to permit |
| * persons to whom the Software is furnished to do |
| * so, subject to the following conditions: |
| * |
| * |
| * Redistributions of source code must retain the above |
| * copyright notice, this list of conditions and |
| * the following disclaimers. |
| * |
| * |
| * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimers in the documentation and/or other materials |
| * provided with the distribution. |
| * |
| * |
| * Neither the names of the University of Illinois, NCSA, |
| * nor the names of its contributors may be used to endorse |
| * or promote products derived from this Software without |
| * specific prior written permission. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT |
| * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * ________________________________________________________________ |
| * National Laboratory for Applied Network Research |
| * National Center for Supercomputing Applications |
| * University of Illinois at Urbana-Champaign |
| * http://www.ncsa.uiuc.edu |
| * ________________________________________________________________ |
| * |
| * Settings.cpp |
| * by Mark Gates <mgates@nlanr.net> |
| * & Ajay Tirumala <tirumala@ncsa.uiuc.edu> |
| * ------------------------------------------------------------------- |
| * Stores and parses the initial values for all the global variables. |
| * ------------------------------------------------------------------- |
| * headers |
| * uses |
| * <stdlib.h> |
| * <stdio.h> |
| * <string.h> |
| * |
| * <unistd.h> |
| * ------------------------------------------------------------------- */ |
| |
| #define HEADERS() |
| |
| #include "headers.h" |
| |
| #include "Settings.hpp" |
| #include "Locale.h" |
| #include "SocketAddr.h" |
| |
| #include "util.h" |
| |
| #include "gnu_getopt.h" |
| |
| void Settings_Interpret( char option, const char *optarg, thread_Settings *mExtSettings ); |
| |
| /* ------------------------------------------------------------------- |
| * command line options |
| * |
| * The option struct essentially maps a long option name (--foobar) |
| * or environment variable ($FOOBAR) to its short option char (f). |
| * ------------------------------------------------------------------- */ |
| #define LONG_OPTIONS() |
| |
| const struct option long_options[] = |
| { |
| {"singleclient", no_argument, NULL, '1'}, |
| {"bandwidth", required_argument, NULL, 'b'}, |
| {"client", required_argument, NULL, 'c'}, |
| {"dualtest", no_argument, NULL, 'd'}, |
| {"format", required_argument, NULL, 'f'}, |
| {"help", no_argument, NULL, 'h'}, |
| {"interval", required_argument, NULL, 'i'}, |
| {"len", required_argument, NULL, 'l'}, |
| {"print_mss", no_argument, NULL, 'm'}, |
| {"num", required_argument, NULL, 'n'}, |
| {"output", required_argument, NULL, 'o'}, |
| {"port", required_argument, NULL, 'p'}, |
| {"tradeoff", no_argument, NULL, 'r'}, |
| {"server", no_argument, NULL, 's'}, |
| {"time", required_argument, NULL, 't'}, |
| {"udp", no_argument, NULL, 'u'}, |
| {"version", no_argument, NULL, 'v'}, |
| {"window", required_argument, NULL, 'w'}, |
| {"reportexclude", required_argument, NULL, 'x'}, |
| {"reportstyle",required_argument, NULL, 'y'}, |
| |
| // more esoteric options |
| {"bind", required_argument, NULL, 'B'}, |
| {"compatibility", no_argument, NULL, 'C'}, |
| {"daemon", no_argument, NULL, 'D'}, |
| {"file_input", required_argument, NULL, 'F'}, |
| {"stdin_input", no_argument, NULL, 'I'}, |
| {"mss", required_argument, NULL, 'M'}, |
| {"nodelay", no_argument, NULL, 'N'}, |
| {"listenport", required_argument, NULL, 'L'}, |
| {"parallel", required_argument, NULL, 'P'}, |
| {"remove", no_argument, NULL, 'R'}, |
| {"tos", required_argument, NULL, 'S'}, |
| {"ttl", required_argument, NULL, 'T'}, |
| {"single_udp", no_argument, NULL, 'U'}, |
| {"ipv6_domain", no_argument, NULL, 'V'}, |
| {"suggest_win_size", no_argument, NULL, 'W'}, |
| {"linux-congestion", required_argument, NULL, 'Z'}, |
| {0, 0, 0, 0} |
| }; |
| |
| #define ENV_OPTIONS() |
| |
| const struct option env_options[] = |
| { |
| {"IPERF_SINGLECLIENT", no_argument, NULL, '1'}, |
| {"IPERF_BANDWIDTH", required_argument, NULL, 'b'}, |
| {"IPERF_CLIENT", required_argument, NULL, 'c'}, |
| {"IPERF_DUALTEST", no_argument, NULL, 'd'}, |
| {"IPERF_FORMAT", required_argument, NULL, 'f'}, |
| // skip help |
| {"IPERF_INTERVAL", required_argument, NULL, 'i'}, |
| {"IPERF_LEN", required_argument, NULL, 'l'}, |
| {"IPERF_PRINT_MSS", no_argument, NULL, 'm'}, |
| {"IPERF_NUM", required_argument, NULL, 'n'}, |
| {"IPERF_PORT", required_argument, NULL, 'p'}, |
| {"IPERF_TRADEOFF", no_argument, NULL, 'r'}, |
| {"IPERF_SERVER", no_argument, NULL, 's'}, |
| {"IPERF_TIME", required_argument, NULL, 't'}, |
| {"IPERF_UDP", no_argument, NULL, 'u'}, |
| // skip version |
| {"TCP_WINDOW_SIZE", required_argument, NULL, 'w'}, |
| {"IPERF_REPORTEXCLUDE", required_argument, NULL, 'x'}, |
| {"IPERF_REPORTSTYLE",required_argument, NULL, 'y'}, |
| |
| // more esoteric options |
| {"IPERF_BIND", required_argument, NULL, 'B'}, |
| {"IPERF_COMPAT", no_argument, NULL, 'C'}, |
| {"IPERF_DAEMON", no_argument, NULL, 'D'}, |
| {"IPERF_FILE_INPUT", required_argument, NULL, 'F'}, |
| {"IPERF_STDIN_INPUT", no_argument, NULL, 'I'}, |
| {"IPERF_MSS", required_argument, NULL, 'M'}, |
| {"IPERF_NODELAY", no_argument, NULL, 'N'}, |
| {"IPERF_LISTENPORT", required_argument, NULL, 'L'}, |
| {"IPERF_PARALLEL", required_argument, NULL, 'P'}, |
| {"IPERF_TOS", required_argument, NULL, 'S'}, |
| {"IPERF_TTL", required_argument, NULL, 'T'}, |
| {"IPERF_SINGLE_UDP", no_argument, NULL, 'U'}, |
| {"IPERF_IPV6_DOMAIN", no_argument, NULL, 'V'}, |
| {"IPERF_SUGGEST_WIN_SIZE", required_argument, NULL, 'W'}, |
| {"IPERF_CONGESTION_CONTROL", required_argument, NULL, 'Z'}, |
| {0, 0, 0, 0} |
| }; |
| |
| #define SHORT_OPTIONS() |
| |
| const char short_options[] = "1b:c:df:hi:l:mn:o:p:rst:uvw:x:y:B:CDF:IL:M:NP:RS:T:UVWZ:"; |
| |
| /* ------------------------------------------------------------------- |
| * defaults |
| * ------------------------------------------------------------------- */ |
| #define DEFAULTS() |
| |
| const long kDefault_UDPRate = 1024 * 1024; // -u if set, 1 Mbit/sec |
| const int kDefault_UDPBufLen = 1470; // -u if set, read/write 1470 bytes |
| // 1470 bytes is small enough to be sending one packet per datagram on ethernet |
| |
| // 1450 bytes is small enough to be sending one packet per datagram on ethernet |
| // **** with IPv6 **** |
| |
| /* ------------------------------------------------------------------- |
| * Initialize all settings to defaults. |
| * ------------------------------------------------------------------- */ |
| |
| void Settings_Initialize( thread_Settings *main ) { |
| // Everything defaults to zero or NULL with |
| // this memset. Only need to set non-zero values |
| // below. |
| memset( main, 0, sizeof(thread_Settings) ); |
| main->mSock = INVALID_SOCKET; |
| main->mReportMode = kReport_Default; |
| // option, defaults |
| main->flags = FLAG_MODETIME | FLAG_STDOUT; // Default time and stdout |
| //main->mUDPRate = 0; // -b, ie. TCP mode |
| //main->mHost = NULL; // -c, none, required for client |
| main->mMode = kTest_Normal; // -d, mMode == kTest_DualTest |
| main->mFormat = 'a'; // -f, adaptive bits |
| // skip help // -h, |
| //main->mBufLenSet = false; // -l, |
| main->mBufLen = 128 * 1024; // -l, 8 Kbyte |
| //main->mInterval = 0; // -i, ie. no periodic bw reports |
| //main->mPrintMSS = false; // -m, don't print MSS |
| // mAmount is time also // -n, N/A |
| //main->mOutputFileName = NULL; // -o, filename |
| main->mPort = 5001; // -p, ttcp port |
| // mMode = kTest_Normal; // -r, mMode == kTest_TradeOff |
| main->mThreadMode = kMode_Unknown; // -s, or -c, none |
| main->mAmount = 1000; // -t, 10 seconds |
| // mUDPRate > 0 means UDP // -u, N/A, see kDefault_UDPRate |
| // skip version // -v, |
| //main->mTCPWin = 0; // -w, ie. don't set window |
| |
| // more esoteric options |
| //main->mLocalhost = NULL; // -B, none |
| //main->mCompat = false; // -C, run in Compatibility mode |
| //main->mDaemon = false; // -D, run as a daemon |
| //main->mFileInput = false; // -F, |
| //main->mFileName = NULL; // -F, filename |
| //main->mStdin = false; // -I, default not stdin |
| //main->mListenPort = 0; // -L, listen port |
| //main->mMSS = 0; // -M, ie. don't set MSS |
| //main->mNodelay = false; // -N, don't set nodelay |
| //main->mThreads = 0; // -P, |
| //main->mRemoveService = false; // -R, |
| //main->mTOS = 0; // -S, ie. don't set type of service |
| main->mTTL = 1; // -T, link-local TTL |
| //main->mDomain = kMode_IPv4; // -V, |
| //main->mSuggestWin = false; // -W, Suggest the window size. |
| |
| } // end Settings |
| |
| void Settings_Copy( thread_Settings *from, thread_Settings **into ) { |
| *into = new thread_Settings; |
| memcpy( *into, from, sizeof(thread_Settings) ); |
| if ( from->mHost != NULL ) { |
| (*into)->mHost = new char[ strlen(from->mHost) + 1]; |
| strcpy( (*into)->mHost, from->mHost ); |
| } |
| if ( from->mOutputFileName != NULL ) { |
| (*into)->mOutputFileName = new char[ strlen(from->mOutputFileName) + 1]; |
| strcpy( (*into)->mOutputFileName, from->mOutputFileName ); |
| } |
| if ( from->mLocalhost != NULL ) { |
| (*into)->mLocalhost = new char[ strlen(from->mLocalhost) + 1]; |
| strcpy( (*into)->mLocalhost, from->mLocalhost ); |
| } |
| if ( from->mFileName != NULL ) { |
| (*into)->mFileName = new char[ strlen(from->mFileName) + 1]; |
| strcpy( (*into)->mFileName, from->mFileName ); |
| } |
| // Zero out certain entries |
| (*into)->mTID = thread_zeroid(); |
| (*into)->runNext = NULL; |
| (*into)->runNow = NULL; |
| } |
| |
| /* ------------------------------------------------------------------- |
| * Delete memory: Does not clean up open file pointers or ptr_parents |
| * ------------------------------------------------------------------- */ |
| |
| void Settings_Destroy( thread_Settings *mSettings) { |
| DELETE_ARRAY( mSettings->mHost ); |
| DELETE_ARRAY( mSettings->mLocalhost ); |
| DELETE_ARRAY( mSettings->mFileName ); |
| DELETE_ARRAY( mSettings->mOutputFileName ); |
| DELETE_PTR( mSettings ); |
| } // end ~Settings |
| |
| /* ------------------------------------------------------------------- |
| * Parses settings from user's environment variables. |
| * ------------------------------------------------------------------- */ |
| void Settings_ParseEnvironment( thread_Settings *mSettings ) { |
| char *theVariable; |
| |
| int i = 0; |
| while ( env_options[i].name != NULL ) { |
| theVariable = getenv( env_options[i].name ); |
| if ( theVariable != NULL ) { |
| Settings_Interpret( env_options[i].val, theVariable, mSettings ); |
| } |
| i++; |
| } |
| } // end ParseEnvironment |
| |
| /* ------------------------------------------------------------------- |
| * Parse settings from app's command line. |
| * ------------------------------------------------------------------- */ |
| |
| void Settings_ParseCommandLine( int argc, char **argv, thread_Settings *mSettings ) { |
| int option; |
| while ( (option = |
| gnu_getopt_long( argc, argv, short_options, |
| long_options, NULL )) != EOF ) { |
| Settings_Interpret( option, gnu_optarg, mSettings ); |
| } |
| |
| for ( int i = gnu_optind; i < argc; i++ ) { |
| fprintf( stderr, "%s: ignoring extra argument -- %s\n", argv[0], argv[i] ); |
| } |
| } // end ParseCommandLine |
| |
| /* ------------------------------------------------------------------- |
| * Interpret individual options, either from the command line |
| * or from environment variables. |
| * ------------------------------------------------------------------- */ |
| |
| void Settings_Interpret( char option, const char *optarg, thread_Settings *mExtSettings ) { |
| char outarg[100]; |
| |
| switch ( option ) { |
| case '1': // Single Client |
| setSingleClient( mExtSettings ); |
| break; |
| case 'b': // UDP bandwidth |
| if ( !isUDP( mExtSettings ) ) { |
| fprintf( stderr, warn_implied_udp, option ); |
| } |
| |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| |
| Settings_GetLowerCaseArg(optarg,outarg); |
| mExtSettings->mUDPRate = byte_atoi(outarg); |
| setUDP( mExtSettings ); |
| |
| // if -l has already been processed, mBufLenSet is true |
| // so don't overwrite that value. |
| if ( !isBuflenSet( mExtSettings ) ) { |
| mExtSettings->mBufLen = kDefault_UDPBufLen; |
| } |
| break; |
| |
| case 'c': // client mode w/ server host to connect to |
| mExtSettings->mHost = new char[ strlen( optarg ) + 1 ]; |
| strcpy( mExtSettings->mHost, optarg ); |
| |
| if ( mExtSettings->mThreadMode == kMode_Unknown ) { |
| // Test for Multicast |
| iperf_sockaddr temp; |
| SockAddr_setHostname( mExtSettings->mHost, &temp, |
| (isIPV6( mExtSettings ) ? 1 : 0 )); |
| if ( SockAddr_isMulticast( &temp ) ) { |
| setMulticast( mExtSettings ); |
| } |
| mExtSettings->mThreadMode = kMode_Client; |
| mExtSettings->mThreads = 1; |
| } |
| break; |
| |
| case 'd': // Dual-test Mode |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| if ( isCompat( mExtSettings ) ) { |
| fprintf( stderr, warn_invalid_compatibility_option, option ); |
| } |
| #ifdef HAVE_THREAD |
| mExtSettings->mMode = kTest_DualTest; |
| #else |
| fprintf( stderr, warn_invalid_single_threaded, option ); |
| mExtSettings->mMode = kTest_TradeOff; |
| #endif |
| break; |
| |
| case 'f': // format to print in |
| mExtSettings->mFormat = (*optarg); |
| break; |
| |
| case 'h': // print help and exit |
| fprintf(stderr, usage_long1); |
| fprintf(stderr, usage_long2); |
| exit(1); |
| break; |
| |
| case 'i': // specify interval between periodic bw reports |
| mExtSettings->mInterval = atof( optarg ); |
| if ( mExtSettings->mInterval < 0.5 ) { |
| fprintf (stderr, report_interval_small, mExtSettings->mInterval); |
| mExtSettings->mInterval = 0.5; |
| } |
| break; |
| |
| case 'l': // length of each buffer |
| Settings_GetUpperCaseArg(optarg,outarg); |
| mExtSettings->mBufLen = byte_atoi( outarg ); |
| setBuflenSet( mExtSettings ); |
| if ( !isUDP( mExtSettings ) ) { |
| if ( mExtSettings->mBufLen < (int) sizeof( client_hdr ) && |
| !isCompat( mExtSettings ) ) { |
| setCompat( mExtSettings ); |
| fprintf( stderr, warn_implied_compatibility, option ); |
| } |
| } else { |
| if ( mExtSettings->mBufLen < (int) sizeof( UDP_datagram ) ) { |
| mExtSettings->mBufLen = sizeof( UDP_datagram ); |
| fprintf( stderr, warn_buffer_too_small, mExtSettings->mBufLen ); |
| } |
| if ( !isCompat( mExtSettings ) && |
| mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram ) |
| + sizeof( client_hdr ) ) ) { |
| setCompat( mExtSettings ); |
| fprintf( stderr, warn_implied_compatibility, option ); |
| } |
| } |
| |
| break; |
| |
| case 'm': // print TCP MSS |
| setPrintMSS( mExtSettings ); |
| break; |
| |
| case 'n': // bytes of data |
| // amount mode (instead of time mode) |
| unsetModeTime( mExtSettings ); |
| Settings_GetUpperCaseArg(optarg,outarg); |
| mExtSettings->mAmount = byte_atoi( outarg ); |
| break; |
| |
| case 'o' : // output the report and other messages into the file |
| unsetSTDOUT( mExtSettings ); |
| mExtSettings->mOutputFileName = new char[strlen(optarg)+1]; |
| strcpy( mExtSettings->mOutputFileName, optarg); |
| break; |
| |
| case 'p': // server port |
| mExtSettings->mPort = atoi( optarg ); |
| break; |
| |
| case 'r': // test mode tradeoff |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| if ( isCompat( mExtSettings ) ) { |
| fprintf( stderr, warn_invalid_compatibility_option, option ); |
| } |
| |
| mExtSettings->mMode = kTest_TradeOff; |
| break; |
| |
| case 's': // server mode |
| if ( mExtSettings->mThreadMode != kMode_Unknown ) { |
| fprintf( stderr, warn_invalid_client_option, option ); |
| break; |
| } |
| |
| mExtSettings->mThreadMode = kMode_Listener; |
| break; |
| |
| case 't': // seconds to write for |
| // time mode (instead of amount mode) |
| setModeTime( mExtSettings ); |
| mExtSettings->mAmount = (int) (atof( optarg ) * 100.0); |
| break; |
| |
| case 'u': // UDP instead of TCP |
| // if -b has already been processed, UDP rate will |
| // already be non-zero, so don't overwrite that value |
| if ( !isUDP( mExtSettings ) ) { |
| setUDP( mExtSettings ); |
| mExtSettings->mUDPRate = kDefault_UDPRate; |
| } |
| |
| // if -l has already been processed, mBufLenSet is true |
| // so don't overwrite that value. |
| if ( !isBuflenSet( mExtSettings ) ) { |
| mExtSettings->mBufLen = kDefault_UDPBufLen; |
| } else if ( mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram ) |
| + sizeof( client_hdr ) ) && |
| !isCompat( mExtSettings ) ) { |
| setCompat( mExtSettings ); |
| fprintf( stderr, warn_implied_compatibility, option ); |
| } |
| break; |
| |
| case 'v': // print version and exit |
| fprintf( stderr, version ); |
| exit(1); |
| break; |
| |
| case 'w': // TCP window size (socket buffer size) |
| Settings_GetUpperCaseArg(optarg,outarg); |
| mExtSettings->mTCPWin = byte_atoi(outarg); |
| |
| if ( mExtSettings->mTCPWin < 2048 ) { |
| fprintf( stderr, warn_window_small, mExtSettings->mTCPWin ); |
| } |
| break; |
| |
| case 'x': // Limit Reports |
| while ( *optarg != '\0' ) { |
| switch ( *optarg ) { |
| case 's': |
| case 'S': |
| setNoSettReport( mExtSettings ); |
| break; |
| case 'c': |
| case 'C': |
| setNoConnReport( mExtSettings ); |
| break; |
| case 'd': |
| case 'D': |
| setNoDataReport( mExtSettings ); |
| break; |
| case 'v': |
| case 'V': |
| setNoServReport( mExtSettings ); |
| break; |
| case 'm': |
| case 'M': |
| setNoMultReport( mExtSettings ); |
| break; |
| default: |
| fprintf(stderr, warn_invalid_report, *optarg); |
| } |
| optarg++; |
| } |
| break; |
| |
| case 'y': // Reporting Style |
| switch ( *optarg ) { |
| case 'c': |
| case 'C': |
| mExtSettings->mReportMode = kReport_CSV; |
| break; |
| default: |
| fprintf( stderr, warn_invalid_report_style, optarg ); |
| } |
| break; |
| |
| |
| // more esoteric options |
| case 'B': // specify bind address |
| mExtSettings->mLocalhost = new char[ strlen( optarg ) + 1 ]; |
| strcpy( mExtSettings->mLocalhost, optarg ); |
| // Test for Multicast |
| iperf_sockaddr temp; |
| SockAddr_setHostname( mExtSettings->mLocalhost, &temp, |
| (isIPV6( mExtSettings ) ? 1 : 0 )); |
| if ( SockAddr_isMulticast( &temp ) ) { |
| setMulticast( mExtSettings ); |
| } |
| break; |
| |
| case 'C': // Run in Compatibility Mode |
| setCompat( mExtSettings ); |
| if ( mExtSettings->mMode != kTest_Normal ) { |
| fprintf( stderr, warn_invalid_compatibility_option, |
| ( mExtSettings->mMode == kTest_DualTest ? |
| 'd' : 'r' ) ); |
| mExtSettings->mMode = kTest_Normal; |
| } |
| break; |
| |
| case 'D': // Run as a daemon |
| setDaemon( mExtSettings ); |
| break; |
| |
| case 'F' : // Get the input for the data stream from a file |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| |
| setFileInput( mExtSettings ); |
| mExtSettings->mFileName = new char[strlen(optarg)+1]; |
| strcpy( mExtSettings->mFileName, optarg); |
| break; |
| |
| case 'I' : // Set the stdin as the input source |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| |
| setFileInput( mExtSettings ); |
| setSTDIN( mExtSettings ); |
| mExtSettings->mFileName = new char[strlen("<stdin>")+1]; |
| strcpy( mExtSettings->mFileName,"<stdin>"); |
| break; |
| |
| case 'L': // Listen Port (bidirectional testing client-side) |
| if ( mExtSettings->mThreadMode != kMode_Client ) { |
| fprintf( stderr, warn_invalid_server_option, option ); |
| break; |
| } |
| |
| mExtSettings->mListenPort = atoi( optarg ); |
| break; |
| |
| case 'M': // specify TCP MSS (maximum segment size) |
| Settings_GetUpperCaseArg(optarg,outarg); |
| |
| mExtSettings->mMSS = byte_atoi( outarg ); |
| break; |
| |
| case 'N': // specify TCP nodelay option (disable Jacobson's Algorithm) |
| setNoDelay( mExtSettings ); |
| break; |
| |
| case 'P': // number of client threads |
| #ifdef HAVE_THREAD |
| mExtSettings->mThreads = atoi( optarg ); |
| #else |
| if ( mExtSettings->mThreadMode != kMode_Server ) { |
| fprintf( stderr, warn_invalid_single_threaded, option ); |
| } else { |
| mExtSettings->mThreads = atoi( optarg ); |
| } |
| #endif |
| break; |
| |
| case 'R': |
| setRemoveService( mExtSettings ); |
| break; |
| |
| case 'S': // IP type-of-service |
| // TODO use a function that understands base-2 |
| // the zero base here allows the user to specify |
| // "0x#" hex, "0#" octal, and "#" decimal numbers |
| mExtSettings->mTOS = strtol( optarg, NULL, 0 ); |
| break; |
| |
| case 'T': // time-to-live for multicast |
| mExtSettings->mTTL = atoi( optarg ); |
| break; |
| |
| case 'U': // single threaded UDP server |
| setSingleUDP( mExtSettings ); |
| break; |
| |
| case 'V': // IPv6 Domain |
| setIPV6( mExtSettings ); |
| if ( mExtSettings->mThreadMode == kMode_Server |
| && mExtSettings->mLocalhost != NULL ) { |
| // Test for Multicast |
| iperf_sockaddr temp; |
| SockAddr_setHostname( mExtSettings->mLocalhost, &temp, 1); |
| if ( SockAddr_isMulticast( &temp ) ) { |
| setMulticast( mExtSettings ); |
| } |
| } else if ( mExtSettings->mThreadMode == kMode_Client ) { |
| // Test for Multicast |
| iperf_sockaddr temp; |
| SockAddr_setHostname( mExtSettings->mHost, &temp, 1 ); |
| if ( SockAddr_isMulticast( &temp ) ) { |
| setMulticast( mExtSettings ); |
| } |
| } |
| break; |
| |
| case 'W' : |
| setSuggestWin( mExtSettings ); |
| fprintf( stderr, "The -W option is not available in this release\n"); |
| break; |
| |
| case 'Z': |
| #ifdef TCP_CONGESTION |
| setCongestionControl( mExtSettings ); |
| mExtSettings->mCongestion = new char[strlen(optarg)+1]; |
| strcpy( mExtSettings->mCongestion, optarg); |
| #else |
| fprintf( stderr, "The -Z option is not available on this operating system\n"); |
| #endif |
| break; |
| |
| default: // ignore unknown |
| break; |
| } |
| } // end Interpret |
| |
| void Settings_GetUpperCaseArg(const char *inarg, char *outarg) { |
| |
| int len = strlen(inarg); |
| strcpy(outarg,inarg); |
| |
| if ( (len > 0) && (inarg[len-1] >='a') |
| && (inarg[len-1] <= 'z') ) |
| outarg[len-1]= outarg[len-1]+'A'-'a'; |
| } |
| |
| void Settings_GetLowerCaseArg(const char *inarg, char *outarg) { |
| |
| int len = strlen(inarg); |
| strcpy(outarg,inarg); |
| |
| if ( (len > 0) && (inarg[len-1] >='A') |
| && (inarg[len-1] <= 'Z') ) |
| outarg[len-1]= outarg[len-1]-'A'+'a'; |
| } |
| |
| /* |
| * Settings_GenerateListenerSettings |
| * Called to generate the settings to be passed to the Listener |
| * instance that will handle dual testings from the client side |
| * this should only return an instance if it was called on |
| * the thread_Settings instance generated from the command line |
| * for client side execution |
| */ |
| void Settings_GenerateListenerSettings( thread_Settings *client, thread_Settings **listener ) { |
| if ( !isCompat( client ) && |
| (client->mMode == kTest_DualTest || client->mMode == kTest_TradeOff) ) { |
| *listener = new thread_Settings; |
| memcpy(*listener, client, sizeof( thread_Settings )); |
| setCompat( (*listener) ); |
| unsetDaemon( (*listener) ); |
| if ( client->mListenPort != 0 ) { |
| (*listener)->mPort = client->mListenPort; |
| } else { |
| (*listener)->mPort = client->mPort; |
| } |
| (*listener)->mFileName = NULL; |
| (*listener)->mHost = NULL; |
| (*listener)->mLocalhost = NULL; |
| (*listener)->mOutputFileName = NULL; |
| (*listener)->mMode = kTest_Normal; |
| (*listener)->mThreadMode = kMode_Listener; |
| if ( client->mHost != NULL ) { |
| (*listener)->mHost = new char[strlen( client->mHost ) + 1]; |
| strcpy( (*listener)->mHost, client->mHost ); |
| } |
| if ( client->mLocalhost != NULL ) { |
| (*listener)->mLocalhost = new char[strlen( client->mLocalhost ) + 1]; |
| strcpy( (*listener)->mLocalhost, client->mLocalhost ); |
| } |
| } else { |
| *listener = NULL; |
| } |
| } |
| |
| /* |
| * Settings_GenerateSpeakerSettings |
| * Called to generate the settings to be passed to the Speaker |
| * instance that will handle dual testings from the server side |
| * this should only return an instance if it was called on |
| * the thread_Settings instance generated from the command line |
| * for server side execution. This should be an inverse operation |
| * of GenerateClientHdr. |
| */ |
| void Settings_GenerateClientSettings( thread_Settings *server, |
| thread_Settings **client, |
| client_hdr *hdr ) { |
| int flags = ntohl(hdr->flags); |
| if ( (flags & HEADER_VERSION1) != 0 ) { |
| *client = new thread_Settings; |
| memcpy(*client, server, sizeof( thread_Settings )); |
| setCompat( (*client) ); |
| (*client)->mTID = thread_zeroid(); |
| (*client)->mPort = (unsigned short) ntohl(hdr->mPort); |
| (*client)->mThreads = ntohl(hdr->numThreads); |
| if ( hdr->bufferlen != 0 ) { |
| (*client)->mBufLen = ntohl(hdr->bufferlen); |
| } |
| if ( hdr->mWinBand != 0 ) { |
| if ( isUDP( server ) ) { |
| (*client)->mUDPRate = ntohl(hdr->mWinBand); |
| } else { |
| (*client)->mTCPWin = ntohl(hdr->mWinBand); |
| } |
| } |
| (*client)->mAmount = ntohl(hdr->mAmount); |
| if ( ((*client)->mAmount & 0x80000000) > 0 ) { |
| setModeTime( (*client) ); |
| #ifndef WIN32 |
| (*client)->mAmount |= 0xFFFFFFFF00000000LL; |
| #else |
| (*client)->mAmount |= 0xFFFFFFFF00000000; |
| #endif |
| (*client)->mAmount = -(*client)->mAmount; |
| } |
| (*client)->mFileName = NULL; |
| (*client)->mHost = NULL; |
| (*client)->mLocalhost = NULL; |
| (*client)->mOutputFileName = NULL; |
| (*client)->mMode = ((flags & RUN_NOW) == 0 ? |
| kTest_TradeOff : kTest_DualTest); |
| (*client)->mThreadMode = kMode_Client; |
| if ( server->mLocalhost != NULL ) { |
| (*client)->mLocalhost = new char[strlen( server->mLocalhost ) + 1]; |
| strcpy( (*client)->mLocalhost, server->mLocalhost ); |
| } |
| (*client)->mHost = new char[REPORT_ADDRLEN]; |
| if ( ((sockaddr*)&server->peer)->sa_family == AF_INET ) { |
| inet_ntop( AF_INET, &((sockaddr_in*)&server->peer)->sin_addr, |
| (*client)->mHost, REPORT_ADDRLEN); |
| } |
| #ifdef HAVE_IPV6 |
| else { |
| inet_ntop( AF_INET6, &((sockaddr_in6*)&server->peer)->sin6_addr, |
| (*client)->mHost, REPORT_ADDRLEN); |
| } |
| #endif |
| } else { |
| *client = NULL; |
| } |
| } |
| |
| /* |
| * Settings_GenerateClientHdr |
| * Called to generate the client header to be passed to the |
| * server that will handle dual testings from the server side |
| * This should be an inverse operation of GenerateSpeakerSettings |
| */ |
| void Settings_GenerateClientHdr( thread_Settings *client, client_hdr *hdr ) { |
| if ( client->mMode != kTest_Normal ) { |
| hdr->flags = htonl(HEADER_VERSION1); |
| } else { |
| hdr->flags = 0; |
| } |
| if ( isBuflenSet( client ) ) { |
| hdr->bufferlen = htonl(client->mBufLen); |
| } else { |
| hdr->bufferlen = 0; |
| } |
| if ( isUDP( client ) ) { |
| hdr->mWinBand = htonl(client->mUDPRate); |
| } else { |
| hdr->mWinBand = htonl(client->mTCPWin); |
| } |
| if ( client->mListenPort != 0 ) { |
| hdr->mPort = htonl(client->mListenPort); |
| } else { |
| hdr->mPort = htonl(client->mPort); |
| } |
| hdr->numThreads = htonl(client->mThreads); |
| if ( isModeTime( client ) ) { |
| hdr->mAmount = htonl(-(long)client->mAmount); |
| } else { |
| hdr->mAmount = htonl((long)client->mAmount); |
| hdr->mAmount &= htonl( 0x7FFFFFFF ); |
| } |
| if ( client->mMode == kTest_DualTest ) { |
| hdr->flags |= htonl(RUN_NOW); |
| } |
| } |