Esempio n. 1
0
/*
 * 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;
    }
}
Esempio n. 2
0
/*
 * Settings_GenerateServerSettings
 * Called to generate the settings to be passed to the Server
 * instance that will handle dual testings from the client side
 * using the same TCP Connection
 * 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_GenerateServerSettings( thread_Settings *client, thread_Settings **server ) {
    if ( !isCompat( client ) && 
         (client->mMode == kTest_SameTCP_TradeOff_ClientSide ) ) {
        *server = new thread_Settings;
        memcpy(*server, client, sizeof( thread_Settings ));
        setCompat( (*server) );
        unsetDaemon( (*server) );
        (*server)->mFileName   = NULL;
        (*server)->mHost       = NULL;
        (*server)->mLocalhost  = NULL;
        (*server)->mOutputFileName = NULL;
        (*server)->mMode       = kTest_SameTCP_TradeOff_ClientSide; 
	(*server)->mThreadMode = kMode_Server;
	(*server)->mSock = client->mSock;
        if ( client->mHost != NULL ) {
            (*server)->mHost = new char[strlen( client->mHost ) + 1];
            strcpy( (*server)->mHost, client->mHost );
        }
        if ( client->mLocalhost != NULL ) {
            (*server)->mLocalhost = new char[strlen( client->mLocalhost ) + 1];
            strcpy( (*server)->mLocalhost, client->mLocalhost );
        }
    } else {
        *server = NULL;
    }
}
Esempio n. 3
0
void Client::InitiateServer() {
    if ( !isCompat( mSettings ) ) {
        int currLen;
        client_hdr* temp_hdr;
        if ( isUDP( mSettings ) ) {
            UDP_datagram *UDPhdr = (UDP_datagram *)mBuf;
            temp_hdr = (client_hdr*)(UDPhdr + 1);
        } else {
            temp_hdr = (client_hdr*)mBuf;
        }
        Settings_GenerateClientHdr( mSettings, temp_hdr );
        if ( !isUDP( mSettings ) ) {
            currLen = send( mSettings->mSock, mBuf, sizeof(client_hdr), 0 );
            if ( currLen < 0 ) {
                WARN_errno( currLen < 0, "write1" );
            }
        }
    }
}
Esempio n. 4
0
void Client::Run( void ) {
    struct UDP_datagram* mBuf_UDP = (struct UDP_datagram*) mBuf; 
    unsigned long currLen = 0; 

    int delay_target = 0; 
    int delay = 0; 
    int adjust = 0; 

    char* readAt = mBuf;

#if HAVE_THREAD
    if ( !isUDP( mSettings ) ) {
	RunTCP();
	return;
    }
#endif
    
    // Indicates if the stream is readable 
    bool canRead = true, mMode_Time = isModeTime( mSettings ); 

    // setup termination variables
    if ( mMode_Time ) {
        mEndTime.setnow();
        mEndTime.add( mSettings->mAmount / 100.0 );
    }

    if ( isUDP( mSettings ) ) {
        // Due to the UDP timestamps etc, included 
        // reduce the read size by an amount 
        // equal to the header size
    
        // compute delay for bandwidth restriction, constrained to [0,1] seconds 
        delay_target = (int) ( mSettings->mBufLen * ((kSecs_to_usecs * kBytes_to_Bits) 
                                                     / mSettings->mUDPRate) ); 
        if ( delay_target < 0  || 
             delay_target > (int) 1 * kSecs_to_usecs ) {
            fprintf( stderr, warn_delay_large, delay_target / kSecs_to_usecs ); 
            delay_target = (int) kSecs_to_usecs * 1; 
        }
        if ( isFileInput( mSettings ) ) {
            if ( isCompat( mSettings ) ) {
                Extractor_reduceReadSize( sizeof(struct UDP_datagram), mSettings );
                readAt += sizeof(struct UDP_datagram);
            } else {
                Extractor_reduceReadSize( sizeof(struct UDP_datagram) +
                                          sizeof(struct client_hdr), mSettings );
                readAt += sizeof(struct UDP_datagram) +
                          sizeof(struct client_hdr);
            }
        }
    }

    ReportStruct *reportstruct = NULL;

    // InitReport handles Barrier for multiple Streams
    mSettings->reporthdr = InitReport( mSettings );
    reportstruct = new ReportStruct;
    reportstruct->packetID = 0;

    lastPacketTime.setnow();
    
    do {

        // Test case: drop 17 packets and send 2 out-of-order: 
        // sequence 51, 52, 70, 53, 54, 71, 72 
        //switch( datagramID ) { 
        //  case 53: datagramID = 70; break; 
        //  case 71: datagramID = 53; break; 
        //  case 55: datagramID = 71; break; 
        //  default: break; 
        //} 
        gettimeofday( &(reportstruct->packetTime), NULL );

        if ( isUDP( mSettings ) ) {
            // store datagram ID into buffer 
            mBuf_UDP->id      = htonl( (reportstruct->packetID)++ ); 
            mBuf_UDP->tv_sec  = htonl( reportstruct->packetTime.tv_sec ); 
            mBuf_UDP->tv_usec = htonl( reportstruct->packetTime.tv_usec );

            // delay between writes 
            // make an adjustment for how long the last loop iteration took 
            // TODO this doesn't work well in certain cases, like 2 parallel streams 
            adjust = delay_target + lastPacketTime.subUsec( reportstruct->packetTime ); 
            lastPacketTime.set( reportstruct->packetTime.tv_sec, 
                                reportstruct->packetTime.tv_usec ); 

            if ( adjust > 0  ||  delay > 0 ) {
                delay += adjust; 
            }
        }

        // Read the next data block from 
        // the file if it's file input 
        if ( isFileInput( mSettings ) ) {
            Extractor_getNextDataBlock( readAt, mSettings ); 
            canRead = Extractor_canRead( mSettings ) != 0; 
        } else
            canRead = true; 

        // perform write 
        currLen = write( mSettings->mSock, mBuf, mSettings->mBufLen ); 
        if ( currLen < 0 && errno != ENOBUFS ) {
            WARN_errno( currLen < 0, "write2" ); 
            break; 
        }

        // report packets 
        reportstruct->packetLen = currLen;
        ReportPacket( mSettings->reporthdr, reportstruct );
        
        if ( delay > 0 ) {
            delay_loop( delay ); 
        }
        if ( !mMode_Time ) {
            /* mAmount may be unsigned, so don't let it underflow! */
            if( mSettings->mAmount >= currLen ) {
                mSettings->mAmount -= currLen;
            } else {
                mSettings->mAmount = 0;
            }
        }

    } while ( ! (sInterupted  || 
                 (mMode_Time   &&  mEndTime.before( reportstruct->packetTime ))  || 
                 (!mMode_Time  &&  0 >= mSettings->mAmount)) && canRead ); 

    // stop timing
    gettimeofday( &(reportstruct->packetTime), NULL );
    CloseReport( mSettings->reporthdr, reportstruct );

    if ( isUDP( mSettings ) ) {
        // send a final terminating datagram 
        // Don't count in the mTotalLen. The server counts this one, 
        // but didn't count our first datagram, so we're even now. 
        // The negative datagram ID signifies termination to the server. 
    
        // store datagram ID into buffer 
        mBuf_UDP->id      = htonl( -(reportstruct->packetID)  ); 
        mBuf_UDP->tv_sec  = htonl( reportstruct->packetTime.tv_sec ); 
        mBuf_UDP->tv_usec = htonl( reportstruct->packetTime.tv_usec ); 

        if ( isMulticast( mSettings ) ) {
            write( mSettings->mSock, mBuf, mSettings->mBufLen ); 
        } else {
            write_UDP_FIN( ); 
        }
    }
    DELETE_PTR( reportstruct );
    EndReport( mSettings->reporthdr );
} 
Esempio n. 5
0
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 'E': // specify the local port on this PC to connect with (only for client mode)
            mExtSettings->mLocalPort = atoi( optarg );
            break;
        
        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
Esempio n. 6
0
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
		#ifdef RINA
			if ( !isUDP( mExtSettings )  && !isRINA( mExtSettings ) ) {
		#else
			if ( !isUDP( mExtSettings ) ) {
		#endif
				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);
		#ifdef RINA
			if ( !isUDP( mExtSettings )  && !isRINA( mExtSettings ) ) 
		#endif
			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
		#ifdef RINA
			if ( isRINA( mExtSettings ) ) {
				fprintf( stderr, warn_invalid_rina_option, option );
				break;
			}
		#endif
			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 );
		#ifdef RINA
			if ( !isUDP( mExtSettings )  && !isRINA( mExtSettings ) ) {
		#else
			if ( !isUDP( mExtSettings ) ) {
		#endif
				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
		#ifdef RINA
			if ( mExtSettings->mThreadMode != kMode_Unknown && !isRINA( mExtSettings ) ) {
		#else
			if ( mExtSettings->mThreadMode != kMode_Unknown ) {
		#endif
				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 );
		#ifdef RINA
				unsetRINA( mExtSettings );
		#endif
				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

	#ifdef RINA
		case 'A': // RINA instead of UDP or TCP
			mExtSettings->mMode = kTest_Normal; // RINA don't work in dual mode
			setRINA( mExtSettings );
			// if -b has already been processed, UDP rate will
			// already be non-zero, so don't overwrite that value
			if ( isUDP( mExtSettings ) ) {
				unsetUDP( mExtSettings );
			} else {
				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 );
			}

			// if -s have not been used yet, consider the use of client mode
			if ( mExtSettings->mThreadMode == kMode_Unknown ) {
				mExtSettings->mThreadMode = kMode_Client;
			}
			rina::initialize("EMERG", "");
			break;
	#endif

		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 ) {
#ifdef RINA
            if ( isUDP( server ) || isRINA( server ) ) {
#else
            if ( isUDP( server ) ) {
#endif
                (*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;
    }
#ifdef RINA
    if ( isUDP( client ) || isRINA( client ) ) {
#else
    if ( isUDP( client ) ) {
#endif
        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);
    }
}