/* * Report the client or listener Settings in default style */ void reporter_reportsettings( ReporterData *data ) { int win, win_requested; win = getsock_tcp_windowsize( data->info.transferID, (data->mThreadMode == kMode_Listener ? 0 : 1) ); win_requested = data->mTCPWin; printf( seperator_line ); if ( data->mThreadMode == kMode_Listener ) { printf( server_port, (isUDP( data ) ? "UDP" : "TCP"), data->mPort ); } else { printf( client_port, data->mHost, (isUDP( data ) ? "UDP" : "TCP"), data->mPort ); } if ( data->mLocalhost != NULL ) { printf( bind_address, data->mLocalhost ); if ( SockAddr_isMulticast( &data->connection.local ) ) { printf( join_multicast, data->mLocalhost ); } } if ( isUDP( data ) ) { printf( (data->mThreadMode == kMode_Listener ? server_datagram_size : client_datagram_size), data->mBufLen ); if ( SockAddr_isMulticast( &data->connection.peer ) ) { printf( multicast_ttl, data->info.mTTL); } } byte_snprintf( buffer, sizeof(buffer), win, toupper( data->info.mFormat)); printf( "%s: %s", (isUDP( data ) ? udp_buffer_size : tcp_window_size), buffer ); if ( win_requested == 0 ) { printf( " %s", window_default ); } else if ( win != win_requested ) { byte_snprintf( buffer, sizeof(buffer), win_requested, toupper( data->info.mFormat)); printf( warn_window_requested, buffer ); } printf( "\n" ); printf( seperator_line ); }
bool OutPacket::fill(unsigned char *buf, int *len) { int headerLen = 0, bodyLen=0, encryptedLen = 0; unsigned char *bodyBuf; unsigned char *encrypted; bodyBuf = (unsigned char *)malloc(MAX_PACKET_SIZE* sizeof(unsigned char)); encrypted = (unsigned char *)malloc(MAX_PACKET_SIZE * sizeof(unsigned char)); headerLen = putHead(buf); bodyLen = putBody(bodyBuf); encryptedLen = bodyLen; encryptBody(bodyBuf, bodyLen, encrypted, &encryptedLen); memcpy(buf+headerLen, encrypted, encryptedLen); buf[ headerLen + encryptedLen ] = QQ_PACKET_TAIL; (*len) = headerLen + encryptedLen + 1; if(!isUDP()) { short tmp2 = htons(*len); memcpy(buf, &tmp2, 2); } free(bodyBuf); free(encrypted); return true; }
int OutPacket::putHead(unsigned char *buf) { int pos=0; if(!isUDP()){ buf[0]=buf[1]=0; pos+=2; } buf[pos++]=(unsigned char)QQ_PACKET_TAG; short tmp = htons(version); memcpy(buf+pos, &tmp, 2); pos+=2; tmp = htons(command); memcpy(buf+pos, &tmp, 2); pos+=2; tmp = htons(sequence); memcpy(buf+pos, &tmp, 2); pos+=2; int id = htonl(getQQ()); memcpy(buf+pos, &id, 4); pos+=4; return pos; }
/* ------------------------------------------------------------------- * Listens for connections and starts Servers to handle data. * For TCP, each accepted connection spawns a Server thread. * For UDP, handle all data in this thread for Win32 Only, otherwise * spawn a new Server thread. * ------------------------------------------------------------------- */ void Listener::Run( void ) { #ifdef WIN32 if ( isUDP( mSettings ) && !isSingleUDP( mSettings ) ) { UDPSingleServer(); } else #else #ifdef sun if ( ( isUDP( mSettings ) && isMulticast( mSettings ) && !isSingleUDP( mSettings ) ) || isSingleUDP( mSettings ) ) { UDPSingleServer(); } else #else if ( isSingleUDP( mSettings ) ) { UDPSingleServer(); } else
/* * 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); } }
/* * This function handles multiple format printing by sending to the * appropriate dispatch function */ int reporter_print( ReporterData *stats, int type, int end ) { switch ( type ) { case TRANSFER_REPORT: statistics_reports[stats->mode]( &stats->info ); if ( end != 0 && isPrintMSS( stats ) && !isUDP( stats ) ) { PrintMSS( stats ); } break; case SERVER_RELAY_REPORT: serverstatistics_reports[stats->mode]( &stats->connection, &stats->info ); break; case SETTINGS_REPORT: settings_reports[stats->mode]( stats ); break; case CONNECTION_REPORT: stats->info.reserved_delay = connection_reports[stats->mode]( &stats->connection, stats->info.transferID ); break; case MULTIPLE_REPORT: multiple_reports[stats->mode]( &stats->info ); break; default: fprintf( stderr, "Printing type not implemented! No Output\n" ); } fflush( stdout ); return end; }
/* * Prints reports conditionally */ int reporter_condprintstats( ReporterData *stats, MultiHeader *multireport, int force ) { if ( force != 0 ) { stats->info.cntOutofOrder = stats->cntOutofOrder; // assume most of the time out-of-order packets are not // duplicate packets, so conditionally subtract them from the lost packets. stats->info.cntError = stats->cntError; if ( stats->info.cntError > stats->info.cntOutofOrder ) { stats->info.cntError -= stats->info.cntOutofOrder; } stats->info.cntDatagrams = (isUDP(stats) ? stats->PacketID : stats->cntDatagrams); stats->info.TotalLen = stats->TotalLen; stats->info.startTime = 0; stats->info.endTime = TimeDifference( stats->packetTime, stats->startTime ); stats->info.free = 1; reporter_print( stats, TRANSFER_REPORT, force ); if ( isMultipleReport(stats) ) { reporter_handle_multiple_reports( multireport, &stats->info, force ); } } else while ((stats->intervalTime.tv_sec != 0 || stats->intervalTime.tv_usec != 0) && TimeDifference( stats->nextTime, stats->packetTime ) < 0 ) { stats->info.cntOutofOrder = stats->cntOutofOrder - stats->lastOutofOrder; stats->lastOutofOrder = stats->cntOutofOrder; // assume most of the time out-of-order packets are not // duplicate packets, so conditionally subtract them from the lost packets. stats->info.cntError = stats->cntError - stats->lastError; if ( stats->info.cntError > stats->info.cntOutofOrder ) { stats->info.cntError -= stats->info.cntOutofOrder; } stats->lastError = stats->cntError; stats->info.cntDatagrams = (isUDP( stats ) ? stats->PacketID - stats->lastDatagrams : stats->cntDatagrams - stats->lastDatagrams); stats->lastDatagrams = (isUDP( stats ) ? stats->PacketID : stats->cntDatagrams); stats->info.TotalLen = stats->TotalLen - stats->lastTotal; stats->lastTotal = stats->TotalLen; stats->info.startTime = stats->info.endTime; stats->info.endTime = TimeDifference( stats->nextTime, stats->startTime ); TimeAdd( stats->nextTime, stats->intervalTime ); stats->info.free = 0; reporter_print( stats, TRANSFER_REPORT, force ); if ( isMultipleReport(stats) ) { reporter_handle_multiple_reports( multireport, &stats->info, force ); } } return force; }
/* * 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; } }
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" ); } } } }
void Client::Connect( ) { int rc; SockAddr_remoteAddr( mSettings ); assert( mSettings->inHostname != NULL ); // create an internet socket int type = ( isUDP( mSettings ) ? SOCK_DGRAM : SOCK_STREAM); int domain = (SockAddr_isIPv6( &mSettings->peer ) ? #ifdef HAVE_IPV6 AF_INET6 #else AF_INET #endif : AF_INET); mSettings->mSock = socket( domain, type, 0 ); WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" ); SetSocketOptions( mSettings ); SockAddr_localAddr( mSettings ); if ( mSettings->mLocalhost != NULL ) { // bind socket to local address char temp[100] = "cbind:"; SockAddr_getHostAddress(&mSettings->local, &temp[6], 94); rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, SockAddr_get_sizeof_sockaddr( &mSettings->local ) ); WARN_errno( rc == SOCKET_ERROR, temp ); } // connect socket rc = connect( mSettings->mSock, (sockaddr*) &mSettings->peer, SockAddr_get_sizeof_sockaddr( &mSettings->peer )); FAIL_errno( rc == SOCKET_ERROR, "connect", mSettings ); getsockname( mSettings->mSock, (sockaddr*) &mSettings->local, &mSettings->size_local ); getpeername( mSettings->mSock, (sockaddr*) &mSettings->peer, &mSettings->size_peer ); } // end Connect
/* * 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 ) { #ifdef SAME_TCP if ( (client->mMode == kTest_DualTest) || (client->mMode == kTest_TradeOff) || (client->mMode == kTest_SameTCP_TradeOff_ClientSide)) { #else if ( client->mMode != kTest_Normal ) { #endif 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); } #ifdef SAME_TCP if ( client->mMode == kTest_SameTCP_TradeOff_ClientSide ) { hdr->flags |= htonl(RUN_ON_SAME_TCP); } #endif }
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 ); }
/* ------------------------------------------------------------------- * Set socket options before the listen() or connect() calls. * These are optional performance tuning factors. * ------------------------------------------------------------------- */ void SetSocketOptions( thread_Settings *inSettings ) { // set the TCP window size (socket buffer sizes) // also the UDP buffer size // must occur before call to accept() for large window sizes setsock_tcp_windowsize( inSettings->mSock, inSettings->mTCPWin, (inSettings->mThreadMode == kMode_Client ? 1 : 0) ); if ( isCongestionControl( inSettings ) ) { #ifdef TCP_CONGESTION Socklen_t len = strlen( inSettings->mCongestion ) + 1; int rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION, inSettings->mCongestion, len); FAIL( rc == SOCKET_ERROR, ( "Attempt to set '%s' congestion control failed: %s\r\n", inSettings->mCongestion, strerror(errno) ), NULL ); #else fprintf( stderr, "The -Z option is not available on this operating system\r\n"); #endif /* TCP_CONGESTION */ } // check if we're sending multicast, and set TTL if ( isMulticast( inSettings ) && ( inSettings->mTTL > 0 ) ) { #ifdef HAVE_MULTICAST int val = inSettings->mTTL; if ( !SockAddr_isIPv6( &inSettings->local ) ) { int rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*) &val, (Socklen_t) sizeof(val)); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set multicast TTL.\r\n" ) ); } #ifdef HAVE_IPV6_MULTICAST else { int rc = setsockopt( inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*) &val, (Socklen_t) sizeof(val)); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set multicast TTL.\r\n" ) ); } #endif /* HAVE_IPV6_MULTICAST */ #endif /* HAVE_MULTICAST */ } #ifdef IP_TOS // set IP TOS (type-of-service) field // if ( inSettings->mTOS > 0 ) { int tos, rc; tos = inSettings->mTOS; Socklen_t len = sizeof(tos); rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS,(char*) &tos, len ); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set IP_TOS.\r\n" ) ); // } #endif /* IP_TOS */ if ( !isUDP( inSettings ) ) { // set the TCP maximum segment size setsock_tcp_mss( inSettings->mSock, inSettings->mMSS ); #ifdef TCP_NODELAY // set TCP nodelay option if ( isNoDelay( inSettings ) ) { int nodelay = 1; Socklen_t len = sizeof(nodelay); int rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY, (char*) &nodelay, len ); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set TCP_NODELAY.\r\n" ) ); } #endif /* TCP_NODELAY */ } } // end SetSocketOptions
/* * Updates connection stats */ int reporter_handle_packet( ReportHeader *reporthdr ) { ReportStruct *packet = &reporthdr->data[reporthdr->reporterindex]; ReporterData *data = &reporthdr->report; Transfer_Info *stats = &reporthdr->report.info; int finished = 0; double usec_transit; data->packetTime = packet->packetTime; stats->socket = packet->socket; if ( packet->packetID < 0 ) { finished = 1; if ( reporthdr->report.mThreadMode != kMode_Client ) { data->TotalLen += packet->packetLen; } } else { if (!packet->emptyreport) { // update fields common to TCP and UDP, client and server data->TotalLen += packet->packetLen; // update fields common to UDP client and server if ( isUDP( data ) ) { data->cntDatagrams++; stats->IPGsum += TimeDifference(data->packetTime, data->IPGstart ); stats->IPGcnt++; data->IPGstart = data->packetTime; // Finally, update UDP server fields if (stats->mUDP == kMode_Server) { //subsequent packets double transit; double deltaTransit; transit = TimeDifference( packet->packetTime, packet->sentTime ); // packet loss occured if the datagram numbers aren't sequential if ( packet->packetID != data->PacketID + 1 ) { if (packet->packetID < data->PacketID + 1 ) { data->cntOutofOrder++; } else { data->cntError += packet->packetID - data->PacketID - 1; } } // never decrease datagramID (e.g. if we get an out-of-order packet) if ( packet->packetID > data->PacketID ) { data->PacketID = packet->packetID; } if (stats->transit.totcntTransit == 0) { // Very first packet stats->transit.minTransit = transit; stats->transit.maxTransit = transit; stats->transit.sumTransit = transit; stats->transit.cntTransit = 1; stats->transit.totminTransit = transit; stats->transit.totmaxTransit = transit; stats->transit.totsumTransit = transit; stats->transit.totcntTransit = 1; // For variance, working units is microseconds usec_transit = transit * 1e6; stats->transit.vdTransit = usec_transit; stats->transit.meanTransit = usec_transit; stats->transit.m2Transit = usec_transit * usec_transit; stats->transit.totvdTransit = usec_transit; stats->transit.totmeanTransit = usec_transit; stats->transit.totm2Transit = usec_transit * usec_transit; } else { // from RFC 1889, Real Time Protocol (RTP) // J = J + ( | D(i-1,i) | - J ) / // Compute jitter deltaTransit = transit - stats->transit.lastTransit; if ( deltaTransit < 0.0 ) { deltaTransit = -deltaTransit; } stats->jitter += (deltaTransit - stats->jitter) / (16.0); // Compute end/end delay stats stats->transit.sumTransit += transit; stats->transit.cntTransit++; stats->transit.totsumTransit += transit; stats->transit.totcntTransit++; // mean min max tests if (transit < stats->transit.minTransit) { stats->transit.minTransit=transit; } if (transit < stats->transit.totminTransit) { stats->transit.totminTransit=transit; } if (transit > stats->transit.maxTransit) { stats->transit.maxTransit=transit; } if (transit > stats->transit.totmaxTransit) { stats->transit.totmaxTransit=transit; } // For variance, working units is microseconds // variance interval usec_transit = transit * 1e6; stats->transit.vdTransit = usec_transit - stats->transit.meanTransit; stats->transit.meanTransit = stats->transit.meanTransit + (stats->transit.vdTransit / stats->transit.cntTransit); stats->transit.m2Transit = stats->transit.m2Transit + (stats->transit.vdTransit * (usec_transit - stats->transit.meanTransit)); // variance total stats->transit.totvdTransit = usec_transit - stats->transit.totmeanTransit; stats->transit.totmeanTransit = stats->transit.totmeanTransit + (stats->transit.totvdTransit / stats->transit.totcntTransit); stats->transit.totm2Transit = stats->transit.totm2Transit + (stats->transit.totvdTransit * (usec_transit - stats->transit.totmeanTransit)); } stats->transit.lastTransit = transit; } } else if (reporthdr->report.mThreadMode == kMode_Server && (packet->packetLen > 0)) { int bin; // mean min max tests stats->tcp.read.cntRead++; stats->tcp.read.totcntRead++; bin = (int)floor((packet->packetLen -1)/stats->tcp.read.binsize); stats->tcp.read.bins[bin]++; stats->tcp.read.totbins[bin]++; } else if (reporthdr->report.mThreadMode == kMode_Client) { if (packet->errwrite) { stats->tcp.write.WriteErr++; stats->tcp.write.totWriteErr++; } else { stats->tcp.write.WriteCnt++; stats->tcp.write.totWriteCnt++; } } } else if ((stats->mUDP == kMode_Server) && \ (stats->transit.cntTransit == 0)) { // This is the case when empty reports // cross the report interval boundary // Hence, set the per interval min to infinity // and the per interval max and sum to zero stats->transit.minTransit = FLT_MAX; stats->transit.maxTransit = FLT_MIN; stats->transit.sumTransit = 0; stats->transit.vdTransit = 0; stats->transit.meanTransit = 0; stats->transit.m2Transit = 0; } } // Print a report if appropriate return reporter_condprintstats( &reporthdr->report, reporthdr->multireport, finished ); }
/* * InitReport is called by a transfer agent (client or * server) to setup the needed structures to communicate * traffic. */ ReportHeader* InitReport( thread_Settings *agent ) { ReportHeader *reporthdr = NULL; ReporterData *data = NULL; if ( isDataReport( agent ) ) { /* * Create in one big chunk */ reporthdr = malloc( sizeof(ReportHeader) + NUM_REPORT_STRUCTS * sizeof(ReportStruct) ); if ( reporthdr != NULL ) { // Only need to make sure the headers are clean memset( reporthdr, 0, sizeof(ReportHeader)); reporthdr->data = (ReportStruct*)(reporthdr+1); reporthdr->multireport = agent->multihdr; data = &reporthdr->report; reporthdr->reporterindex = NUM_REPORT_STRUCTS - 1; data->info.transferID = agent->mSock; data->info.groupID = (agent->multihdr != NULL ? agent->multihdr->groupID : 128); data->type = TRANSFER_REPORT; if ( agent->mInterval != 0.0 ) { struct timeval *interval = &data->intervalTime; interval->tv_sec = (long) agent->mInterval; interval->tv_usec = (long) ((agent->mInterval - interval->tv_sec) * rMillion); } data->mHost = agent->mHost; data->mLocalhost = agent->mLocalhost; data->mBufLen = agent->mBufLen; data->mMSS = agent->mMSS; data->mTCPWin = agent->mTCPWin; data->flags = agent->flags; data->mThreadMode = agent->mThreadMode; data->mode = agent->mReportMode; data->info.mFormat = agent->mFormat; data->info.mTTL = agent->mTTL; if (data->mThreadMode == kMode_Server) data->info.tcp.read.binsize = data->mBufLen / 8; if ( isUDP( agent ) ) { gettimeofday(&data->IPGstart, NULL); reporthdr->report.info.mUDP = (char)agent->mThreadMode; } else { reporthdr->report.info.mTCP = (char)agent->mThreadMode; } if ( isEnhanced( agent ) ) { data->info.mEnhanced = 1; } else { data->info.mEnhanced = 0; } } else { FAIL(1, "Out of Memory!!\n", agent); } } if ( isConnectionReport( agent ) ) { if ( reporthdr == NULL ) { /* * Create in one big chunk */ reporthdr = malloc( sizeof(ReportHeader) ); if ( reporthdr != NULL ) { // Only need to make sure the headers are clean memset( reporthdr, 0, sizeof(ReportHeader)); data = &reporthdr->report; data->info.transferID = agent->mSock; data->info.groupID = 128; } else { FAIL(1, "Out of Memory!!\n", agent); } } if ( reporthdr != NULL ) { data->type |= CONNECTION_REPORT; data->connection.peer = agent->peer; data->connection.size_peer = agent->size_peer; data->connection.local = agent->local; data->connection.size_local = agent->size_local; } else { FAIL(1, "Out of Memory!!\n", agent); } } if ( isConnectionReport( agent ) || isDataReport( agent ) ) { #ifdef HAVE_THREAD /* * Update the ReportRoot to include this report. */ if ( reporthdr->report.mThreadMode == kMode_Client && reporthdr->multireport != NULL ) { // syncronize watches on my mark...... BarrierClient( reporthdr ); } else { if ( reporthdr->multireport != NULL && isMultipleReport( agent )) { reporthdr->multireport->threads++; if ( reporthdr->multireport->report->startTime.tv_sec == 0 ) { gettimeofday( &(reporthdr->multireport->report->startTime), NULL ); } reporthdr->report.startTime = reporthdr->multireport->report->startTime; } else { // set start time gettimeofday( &(reporthdr->report.startTime), NULL ); } reporthdr->report.nextTime = reporthdr->report.startTime; TimeAdd( reporthdr->report.nextTime, reporthdr->report.intervalTime ); } Condition_Lock( ReportCond ); reporthdr->next = ReportRoot; ReportRoot = reporthdr; Condition_Signal( &ReportCond ); Condition_Unlock( ReportCond ); #else // set start time gettimeofday( &(reporthdr->report.startTime), NULL ); /* * Process the report in this thread */ reporthdr->next = NULL; process_report ( reporthdr ); #endif } if ( !isDataReport( agent ) ) { reporthdr = NULL; } return reporthdr; }
MultiHeader* InitMulti( thread_Settings *agent, int inID ) { MultiHeader *multihdr = NULL; if ( agent->mThreads > 1 || agent->mThreadMode == kMode_Server ) { if ( isMultipleReport( agent ) ) { multihdr = malloc(sizeof(MultiHeader) + sizeof(ReporterData) + NUM_MULTI_SLOTS * sizeof(Transfer_Info)); } else { multihdr = malloc(sizeof(MultiHeader)); } if ( multihdr != NULL ) { memset( multihdr, 0, sizeof(MultiHeader) ); Condition_Initialize( &multihdr->barrier ); multihdr->groupID = inID; multihdr->threads = agent->mThreads; if ( isMultipleReport( agent ) ) { int i; ReporterData *data = NULL; multihdr->report = (ReporterData*)(multihdr + 1); memset(multihdr->report, 0, sizeof(ReporterData)); multihdr->data = (Transfer_Info*)(multihdr->report + 1); data = multihdr->report; for ( i = 0; i < NUM_MULTI_SLOTS; i++ ) { multihdr->data[i].startTime = -1; multihdr->data[i].transferID = inID; multihdr->data[i].groupID = -2; } data->type = TRANSFER_REPORT; if ( agent->mInterval != 0.0 ) { struct timeval *interval = &data->intervalTime; interval->tv_sec = (long) agent->mInterval; interval->tv_usec = (long) ((agent->mInterval - interval->tv_sec) * rMillion); } data->mHost = agent->mHost; data->mLocalhost = agent->mLocalhost; data->mBufLen = agent->mBufLen; data->mMSS = agent->mMSS; data->mTCPWin = agent->mTCPWin; data->flags = agent->flags; data->mThreadMode = agent->mThreadMode; data->mode = agent->mReportMode; data->info.mFormat = agent->mFormat; data->info.mTTL = agent->mTTL; if (data->mThreadMode == kMode_Server) data->info.tcp.read.binsize = data->mBufLen / 8; if ( isEnhanced( agent ) ) { data->info.mEnhanced = 1; } else { data->info.mEnhanced = 0; } if ( isUDP( agent ) ) { multihdr->report->info.mUDP = (char)agent->mThreadMode; multihdr->report->info.mUDP = 0; } else { multihdr->report->info.mTCP = (char)agent->mThreadMode; } if ( isConnectionReport( agent ) ) { data->type |= CONNECTION_REPORT; data->connection.peer = agent->peer; data->connection.size_peer = agent->size_peer; SockAddr_setPortAny( &data->connection.peer ); data->connection.local = agent->local; data->connection.size_local = agent->size_local; SockAddr_setPortAny( &data->connection.local ); } } } else { FAIL(1, "Out of Memory!!\n", agent); } } return multihdr; }
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); } }
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