Exemple #1
0
void setsock_tcp_mss( int inSock, int inMSS ) {
#ifdef TCP_MAXSEG
    int rc;
    int newMSS;
    Socklen_t len;

    assert( inSock != INVALID_SOCKET );

    if ( inMSS > 0 ) {
        /* set */
        newMSS = inMSS;
        len = sizeof( newMSS );
        rc = setsockopt( inSock, IPPROTO_TCP, TCP_MAXSEG, (char*) &newMSS,  len );
        if ( rc == SOCKET_ERROR ) {
            fprintf( stderr, warn_mss_fail, newMSS );
            return;
        }

        /* verify results */
        rc = getsockopt( inSock, IPPROTO_TCP, TCP_MAXSEG, (char*) &newMSS, &len );
        WARN_errno( rc == SOCKET_ERROR, ( "Unable to get value of TCP_MAXSEG with getsockopt.\n" ) );
        if ( newMSS != inMSS ) {
            fprintf( stderr, warn_mss_notset, inMSS, newMSS );
        }
    }
#else
    IPERF_DEBUGF( SOCKET_DEBUG | IPERF_DBG_TRACE | IPERF_DBG_LEVEL_WARNING, ( "%s", warn_mss_no_attempt ) );
#endif /* TCP_MAXSEG */
} // end setsock_tcp_mss
Exemple #2
0
/* -------------------------------------------------------------------
 * Delete memory (buffer).
 * ------------------------------------------------------------------- */
Listener::~Listener() {
    if ( mSettings->mSock != INVALID_SOCKET ) {
        int rc = close( mSettings->mSock );
        WARN_errno( rc == SOCKET_ERROR, "close" );
        mSettings->mSock = INVALID_SOCKET;
    }
    DELETE_ARRAY( mBuf );
} // end ~Listener
Exemple #3
0
Client::~Client() {
    if ( mSettings->mSock != INVALID_SOCKET ) {
        int rc = close( mSettings->mSock );
        WARN_errno( rc == SOCKET_ERROR, "close" );
        mSettings->mSock = INVALID_SOCKET;
    }
    if(outFile!=NULL)
      fclose(outFile);
    DELETE_ARRAY( mBuf );
} // end ~Client
Exemple #4
0
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
Exemple #5
0
void Client::write_UDP_FIN( ) {
    int rc; 
    fd_set readSet; 
    struct timeval timeout; 

    int count = 0; 
    while ( count < 10 ) {
        count++; 

        // write data 
        rc=write( mSettings->mSock, mBuf, mSettings->mBufLen );
	WARN_errno( rc < 0, "write");

        // wait until the socket is readable, or our timeout expires 
        FD_ZERO( &readSet ); 
        FD_SET( mSettings->mSock, &readSet ); 
        timeout.tv_sec  = 0; 
        timeout.tv_usec = 250000; // quarter second, 250 ms 

        rc = select( mSettings->mSock+1, &readSet, NULL, NULL, &timeout ); 
        FAIL_errno( rc == SOCKET_ERROR, "select", mSettings ); 

        if ( rc == 0 ) {
            // select timed out 
            continue; 
        } else {
            // socket ready to read 
            rc = read( mSettings->mSock, mBuf, mSettings->mBufLen ); 
            WARN_errno( rc < 0, "read" );
    	    if ( rc < 0 ) {
                break;
            } else if ( rc >= (int) (sizeof(UDP_datagram) + sizeof(server_hdr)) ) {
                ReportServerUDP( mSettings, (server_hdr*) ((UDP_datagram*)mBuf + 1) );
            }

            return; 
        } 
    } 

    fprintf( stderr, warn_no_ack, mSettings->mSock, count ); 
} 
Exemple #6
0
void delay_ms(unsigned long msec)
{
    struct timespec requested, remaining;

    requested.tv_sec  = msec/1000;
    requested.tv_nsec = (msec%1000) * 1000L;

    while (nanosleep(&requested, &remaining) == -1)
        if (errno == EINTR)
            requested = remaining;
        else {
            WARN_errno(1, "nanosleep");
            break;
        }
}
Exemple #7
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" );
            }
        }
    }
}
Exemple #8
0
static void gettcpistats (ReporterData *stats) {
    struct tcp_info tcp_internal;
    socklen_t tcp_info_length = sizeof(struct tcp_info);
    int retry;
    if (stats->info.mEnhanced && stats->info.mTCP == kMode_Client) {
	// Read the TCP retry stats for a client.  Do this
	// on  a report interval period.
	if (getsockopt(stats->info.socket, IPPROTO_TCP, TCP_INFO, &tcp_internal, &tcp_info_length) < 0) {
	    WARN_errno( 1 , "getsockopt");
	    retry = 0;
	} else {
	    retry = tcp_internal.tcpi_total_retrans - stats->info.tcp.write.lastTCPretry;
	}
	stats->info.tcp.write.TCPretry = retry;
	stats->info.tcp.write.totTCPretry += retry;
	stats->info.tcp.write.lastTCPretry = tcp_internal.tcpi_total_retrans;
	stats->info.tcp.write.cwnd = tcp_internal.tcpi_snd_cwnd * tcp_internal.tcpi_snd_mss / 1024;
    } 
}
Exemple #9
0
/* -------------------------------------------------------------------
 * returns the TCP maximum segment size
 * ------------------------------------------------------------------- */
int getsock_tcp_mss( int inSock ) {
    int theMSS = 0;

#ifdef TCP_MAXSEG
    int rc;
    Socklen_t len;
    assert( inSock >= 0 );

    /* query for MSS */
    len = sizeof( theMSS );
#if defined(WICED) && defined(NETWORK_LwIP)
    /* We can't use `getsockopt' to query SO_SNDBUF on LwIP */
    rc = 0;
    theMSS = TCP_MSS;
#else
    rc = getsockopt( inSock, IPPROTO_TCP, TCP_MAXSEG, (char*) &theMSS, &len );
    WARN_errno( rc == SOCKET_ERROR, ( "Unable to get value of TCP_MAXSEG with getsockopt.\n" ) );
#endif /* defined(WICED) && defined(NETWORK_LwIP) */
#else
    IPERF_DEBUGF( SOCKET_DEBUG | IPERF_DBG_TRACE | IPERF_DBG_LEVEL_WARNING, ( "Unable get set socket TCP MSS - TCP_MAXSEG is undefined.\n" ) );
#endif /* TCP_MAXSEG */

    return theMSS;
} // end getsock_tcp_mss
Exemple #10
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 );
} 
Exemple #11
0
void Client::RunTCP( void ) {
    unsigned long currLen = 0; 
    struct itimerval it;
    max_size_t totLen = 0;

    int err;

    char* readAt = mBuf;

    // Indicates if the stream is readable 
    bool canRead = true, mMode_Time = isModeTime( mSettings ); 

    ReportStruct *reportstruct = NULL;

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

    lastPacketTime.setnow();
    if ( mMode_Time ) {
	memset (&it, 0, sizeof (it));
	it.it_value.tv_sec = (int) (mSettings->mAmount / 100.0);
	it.it_value.tv_usec = (int) 10000 * (mSettings->mAmount -
	    it.it_value.tv_sec * 100.0);
	err = setitimer( ITIMER_REAL, &it, NULL );
	if ( err != 0 ) {
	    perror("setitimer");
	    exit(1);
	}
    }
    do {
        // 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 );
#ifdef __linux
        OutTcpInfo(outFile, mSettings->mSock);
#endif
        if ( currLen < 0 ) {
            WARN_errno( currLen < 0, "write2" ); 
            break; 
        }
	totLen += currLen;

	if(mSettings->mInterval > 0) {
    	    gettimeofday( &(reportstruct->packetTime), NULL );
            reportstruct->packetLen = currLen;
            ReportPacket( mSettings->reporthdr, reportstruct );
        }	

        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  &&  0 >= mSettings->mAmount)) && canRead ); 

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

    // if we're not doing interval reporting, report the entire transfer as one big packet
    if(0.0 == mSettings->mInterval) {
        reportstruct->packetLen = totLen;
        ReportPacket( mSettings->reporthdr, reportstruct );
    }
    CloseReport( mSettings->reporthdr, reportstruct );

    DELETE_PTR( reportstruct );
    EndReport( mSettings->reporthdr );
}
Exemple #12
0
/* -------------------------------------------------------------------
 * main()
 *      Entry point into Iperf
 *
 * sets up signal handlers
 * initialize global locks and conditions
 * parses settings from environment and command line
 * starts up server or client thread
 * waits for all threads to complete
 * ------------------------------------------------------------------- */
int main( int argc, char **argv ) {
#ifdef WIN32
    // Start winsock
    WSADATA wsaData;
    int rc;
#endif

    // Set SIGTERM and SIGINT to call our user interrupt function
    my_signal( SIGTERM, Sig_Interupt );
    my_signal( SIGINT,  Sig_Interupt );
#ifndef WIN32 // SIGALRM=14, _NSIG=3...
    my_signal( SIGALRM,  Sig_Interupt );
#endif

#ifndef WIN32
	// Ignore broken pipes
    signal(SIGPIPE,SIG_IGN);
#endif

#ifdef WIN32 
    // Start winsock
    rc = WSAStartup( 0x202, &wsaData );
    WARN_errno( rc == SOCKET_ERROR, "WSAStartup" );
    if (rc == SOCKET_ERROR)
        return 0;

    // Tell windows we want to handle our own signals
    SetConsoleCtrlHandler( sig_dispatcher, true );
#endif

    // Initialize global mutexes and conditions
    Condition_Initialize ( &ReportCond );
    Condition_Initialize ( &ReportDoneCond );
    Mutex_Initialize( &groupCond );
    Mutex_Initialize( &clients_mutex );

    // Initialize the thread subsystem
    thread_init( );

    // Initialize the interrupt handling thread to 0
    sThread = thread_zeroid();

    // perform any cleanup when quitting Iperf
    atexit( cleanup );

    // Allocate the "global" settings
    thread_Settings* ext_gSettings = new thread_Settings;

    // Initialize settings to defaults
    Settings_Initialize( ext_gSettings );
    // read settings from environment variables
    Settings_ParseEnvironment( ext_gSettings );
    // read settings from command-line parameters
    Settings_ParseCommandLine( argc, argv, ext_gSettings );

    // Check for either having specified client or server
    if ( ext_gSettings->mThreadMode == kMode_Client
         || ext_gSettings->mThreadMode == kMode_Listener ) {
#ifdef WIN32
        // Start the server as a daemon
        // Daemon mode for non-windows in handled
        // in the listener_spawn function
        if ( isDaemon( ext_gSettings ) ) {
            CmdInstallService(argc, argv);
            return 0;
        }

        // Remove the Windows service if requested
        if ( isRemoveService( ext_gSettings ) ) {
            // remove the service
            if ( CmdRemoveService() ) {
                fprintf(stderr, "IPerf Service is removed.\n");

                return 0;
            }
        }
#endif
        // initialize client(s)
        if ( ext_gSettings->mThreadMode == kMode_Client ) {
            client_init( ext_gSettings );
        }

#ifdef HAVE_THREAD
        // start up the reporter and client(s) or listener
        {
            thread_Settings *into = NULL;
            // Create the settings structure for the reporter thread
            Settings_Copy( ext_gSettings, &into );
            into->mThreadMode = kMode_Reporter;

            // Have the reporter launch the client or listener
            into->runNow = ext_gSettings;

            // Start all the threads that are ready to go
            thread_start( into );
        }
#else
        // No need to make a reporter thread because we don't have threads
        thread_start( ext_gSettings );
#endif
    } else {
        // neither server nor client mode was specified
        // print usage and exit

#ifdef WIN32
        // In Win32 we also attempt to start a previously defined service
        // Starting in 2.0 to restart a previously defined service
        // you must call iperf with "iperf -D" or using the environment variable
        SERVICE_TABLE_ENTRY dispatchTable[] =
        {
            { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
            { NULL, NULL}
        };

        // Only attempt to start the service if "-D" was specified
        if ( !isDaemon(ext_gSettings) ||
             // starting the service by SCM, there is no arguments will be passed in.
             // the arguments will pass into Service_Main entry.
             !StartServiceCtrlDispatcher(dispatchTable) )
            // If the service failed to start then print usage
#endif
        fprintf( stderr, usage_short, argv[0], argv[0] );

        return 0;
    }

    // wait for other (client, server) threads to complete
    thread_joinall();

    // all done!
    return 0;
} // end main
Exemple #13
0
/* -------------------------------------------------------------------
 * 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
Exemple #14
0
/* -------------------------------------------------------------------
 * main()
 *      Entry point into Iperf
 *
 * sets up signal handlers
 * initialize global locks and conditions
 * parses settings from environment and command line
 * starts up server or client thread
 * waits for all threads to complete
 * ------------------------------------------------------------------- */
#ifdef __cplusplus
extern "C"
#endif /* __cplusplus */
int IPERF_MAIN( int argc, char **argv ) {
#ifdef NO_EXIT
    should_exit = 0;
#endif /* NO_EXIT */
#ifdef IPERF_DEBUG
    debug_init();
#endif /* IPERF_DEBUG */

#ifndef NO_INTERRUPTS
#ifdef WIN32
    setsigalrmfunc(call_sigalrm);
#endif /* WIN32 */

    // Set SIGTERM and SIGINT to call our user interrupt function
    my_signal( SIGTERM, Sig_Interupt );
    my_signal( SIGINT,  Sig_Interupt );
    my_signal( SIGALRM,  Sig_Interupt );

#ifndef WIN32
    // Ignore broken pipes
    signal(SIGPIPE,SIG_IGN);
#else
    // Start winsock
    WORD wVersionRequested;
    WSADATA wsaData;

    // Using MAKEWORD macro, Winsock version request 2.2
    wVersionRequested = MAKEWORD(2, 2);

    int rc = WSAStartup( wVersionRequested, &wsaData );
    WARN_errno( rc == SOCKET_ERROR, ( "WSAStartup failed.\n" ) );
	if (rc != 0) {
	    fprintf(stderr, "The Winsock DLL was not found!\n");
		return 1;
	}

    /*
     * Confirm that the WinSock DLL supports 2.2. Note that if the DLL supports
	 * versions greater than 2.2 in addition to 2.2, it will still return 2.2 in
	 * wVersion since that is the version we requested.
     */
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 ) {
        /* Tell the user that we could not find a usable WinSock DLL. */
        fprintf(stderr, "The DLL does not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
        WSACleanup();
        return 1;
    }

    // Tell windows we want to handle our own signals
    SetConsoleCtrlHandler( sig_dispatcher, true );
#endif /* WIN32 */
#endif /* NO_INTERRUPTS */

    // Initialize global mutexes and conditions
    IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Initializing report condition.\n" ) );
    Condition_Initialize ( &ReportCond );
    IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Initializing report done condition.\n" ) );
    Condition_Initialize ( &ReportDoneCond );
    IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Initializing group condition mutex.\n" ) );
    Mutex_Initialize( &groupCond );
    IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Initializing clients mutex.\n" ) );
    Mutex_Initialize( &clients_mutex );

    // Initialize the thread subsystem
    IPERF_DEBUGF( THREAD_DEBUG | IPERF_DBG_TRACE, ( "Initializing the thread subsystem.\n" ) );
    thread_init( );

    // Initialize the interrupt handling thread to 0
    sThread = thread_zeroid();

#ifndef NO_EXIT
    // perform any cleanup when quitting Iperf
    atexit( cleanup );
#endif /* NO_EXIT */

    // Allocate the "global" settings
    thread_Settings *ext_gSettings = (thread_Settings*) malloc( sizeof( thread_Settings ) );
    FAIL( ext_gSettings == NULL, ( "Unable to allocate memory for thread_Settings ext_gSettings.\n" ), NULL );
    IPERF_DEBUGF( MEMALLOC_DEBUG, IPERF_MEMALLOC_MSG( ext_gSettings, sizeof( thread_Settings ) ) );

    // Initialize settings to defaults
    Settings_Initialize( ext_gSettings );
#ifndef NO_ENVIRONMENT
    // read settings from environment variables
    Settings_ParseEnvironment( ext_gSettings );
#endif /* NO_ENVIORNMENT */
    // read settings from command-line parameters
    Settings_ParseCommandLine( argc, argv, ext_gSettings );

#ifdef NO_EXIT
    if (should_exit) {
        IPERF_DEBUGF( MEMFREE_DEBUG | IPERF_DBG_TRACE, IPERF_MEMFREE_MSG( ext_gSettings ) );
        FREE_PTR( ext_gSettings );

        IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Destroying report condition.\n" ) );
        Condition_Destroy( &ReportCond );
        IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Destroying report done condition.\n" ) );
        Condition_Destroy( &ReportDoneCond );
        IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Destroying group condition mutex.\n" ) );
        Mutex_Destroy( &groupCond );
        IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Destroying clients mutex.\n" ) );
        Mutex_Destroy( &clients_mutex );

        return 0;
    }
#endif /* NO_EXIT */

    // Check for either having specified client or server
    if ( ext_gSettings->mThreadMode == kMode_Client 
         || ext_gSettings->mThreadMode == kMode_Listener ) {
#ifdef WIN32
#ifndef NO_DAEMON
        // Start the server as a daemon
        // Daemon mode for non-windows in handled
        // in the listener_spawn function
        if ( isDaemon( ext_gSettings ) ) {
            CmdInstallService(argc, argv);
            return 0;
        }
#endif /* NO_DAEMON */

#ifndef NO_SERVICE
        // Remove the Windows service if requested
        if ( isRemoveService( ext_gSettings ) ) {
            // remove the service
            if ( CmdRemoveService() ) {
                fprintf(stderr, "IPerf Service is removed.\n");
                return 0;
            }
        }
#endif /* NO_SERVICE */
#endif /* WIN32 */
        // initialize client(s)
        if ( ext_gSettings->mThreadMode == kMode_Client ) {
            IPERF_DEBUGF( CLIENT_DEBUG | LISTENER_DEBUG | IPERF_DBG_TRACE, ( "Initializing client(s)...\n" ) );
            client_init( ext_gSettings );
        }

#ifdef HAVE_THREAD
        // start up the reporter and client(s) or listener
        thread_Settings *into = NULL;
        // Create the settings structure for the reporter thread
        IPERF_DEBUGF( CLIENT_DEBUG | LISTENER_DEBUG | REPORTER_DEBUG | IPERF_DBG_TRACE, ( "Creating the settings structure for the reporter thread.\n" ) );
        Settings_Copy( ext_gSettings, &into );
        into->mThreadMode = kMode_Reporter;

        // Have the reporter launch the client or listener
        IPERF_DEBUGF( CLIENT_DEBUG | LISTENER_DEBUG | IPERF_DBG_TRACE, ( "Setting the reporter to launch the client or listener before launching itself.\n" ) );
        into->runNow = ext_gSettings;
        
        // Start all the threads that are ready to go
        IPERF_DEBUGF( THREAD_DEBUG | IPERF_DBG_TRACE, ( "Starting all the threads...\n" ) );
        thread_start( into );
#else
        // No need to make a reporter thread because we don't have threads
        IPERF_DEBUGF( THREAD_DEBUG | IPERF_DBG_TRACE, ( "Starting iperf in a single thread...\n" ) );
        thread_start( ext_gSettings );
#endif /* HAVE_THREAD */
    } else {
        // neither server nor client mode was specified
        // print usage and exit

#ifdef WIN32
        // In Win32 we also attempt to start a previously defined service
        // Starting in 2.0 to restart a previously defined service
        // you must call iperf with "iperf -D" or using the environment variable
        SERVICE_TABLE_ENTRY dispatchTable[] =
        {
            { TEXT((char *) SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
            { NULL, NULL}
        };

#ifndef NO_DAEMON
        // Only attempt to start the service if "-D" was specified
        if ( !isDaemon(ext_gSettings) ||
             // starting the service by SCM, there is no arguments will be passed in.
             // the arguments will pass into Service_Main entry.
             !StartServiceCtrlDispatcher(dispatchTable) )
            // If the service failed to start then print usage
#endif /* NO_DAEMON */
#endif /* WIN32 */
        fprintf( stderr, usage_short, argv[0], argv[0] );

        return 0;
    }

    // wait for other (client, server) threads to complete
//    IPERF_DEBUGF( THREAD_DEBUG | IPERF_DBG_TRACE, ( "Waiting for other (client, server) threads to complete...\n" ) );
//    thread_joinall();
    
#ifdef NO_EXIT
	/* We can't run the atexit function */
#ifdef WIN32
    // Shutdown Winsock
    WSACleanup();
#endif /* WIN32 */
    // clean up the list of clients
    Iperf_destroy ( &clients );

    // shutdown the thread subsystem
    IPERF_DEBUGF( THREAD_DEBUG | IPERF_DBG_TRACE, ( "Deinitializing the thread subsystem.\n" ) );

    IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Destroying report condition.\n" ) );
    Condition_Destroy( &ReportCond );
    IPERF_DEBUGF( CONDITION_DEBUG | IPERF_DBG_TRACE, ( "Destroying report done condition.\n" ) );
    Condition_Destroy( &ReportDoneCond );
    IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Destroying group condition mutex.\n" ) );
    Mutex_Destroy( &groupCond );
    IPERF_DEBUGF( MUTEX_DEBUG | IPERF_DBG_TRACE, ( "Destroying clients mutex.\n" ) );
    Mutex_Destroy( &clients_mutex );

#ifdef IPERF_DEBUG
    debug_init();
#endif /* IPERF_DEBUG */
#endif /* NO_EXIT */
	
    // all done!
    IPERF_DEBUGF( IPERF_DBG_TRACE | IPERF_DBG_STATE, ( "Done!\n" ) );
    return 0;
} // end main
Exemple #15
0
void PerfSocket::Client_Recv_TCP(void) {
    // terminate loop nicely on user interupts

    sInterupted = false;
    //my_signal( SIGINT,  Sig_Interupt );
    //my_signal( SIGPIPE, Sig_Interupt );
#ifndef WIN32
    signal (SIGPIPE, SIG_IGN);
#endif

    int currLen;
    InitTransfer();
    double fract = 0.0;
    mStartTime.setnow();
    long  endSize = get_tcp_windowsize(mSock), startSize=endSize, loopLen =0, prevLen =0;
    Timestamp prevTime;
    prevTime.setnow();



    /* Periodic reporting is done here in the loop itself, if Suggest Window Size option is set*/
    mPReporting = false;

    /* Send the first packet indicating that the server has to send data */
    mBuf[0] = 'a';
    currLen = write( mSock, mBuf, mSettings->mBufLen );
    if ( currLen < 0 ) {
        WARN_errno( currLen < 0, "write" );
        return;
    }

    do {
        // perform read
        currLen = read( mSock, mBuf, mSettings->mBufLen );
        mPacketTime.setnow();
        if ( currLen < 0 ) {
            WARN_errno( currLen < 0, "read" );
            break;
        }

        mTotalLen += currLen;
        loopLen +=currLen;

        // periodically report bandwidths
        ReportPeriodicBW();

        double nFract = mStartTime.fraction(mPacketTime,mEndTime);
        if ( nFract > (fract + 0.1) ) {
            printf(seperator_line);
            ReportWindowSize();
            sReporting.Lock();
            ReportBW( loopLen, prevTime.subSec(mStartTime),  mPacketTime.subSec( mStartTime));
            sReporting.Unlock();
            fract +=0.1;
            if ( startSize != endSize ) {
                /* Change the window size only if the data transfer has changed at least by 5% */
                if ( loopLen < prevLen ) {

                    if ( ( ((double)(prevLen - loopLen)) /  
                           ((double)prevLen))  > 0.05         
                       ) {
                        endSize = startSize + (endSize - startSize)/2;
                    }

                } else {
                    if ( ( ((double)(loopLen - prevLen)) /       
                           ((double)prevLen) ) > 0.05          
                       ) {
                        startSize = endSize;
                        endSize = endSize*2;
                        prevLen = loopLen;

                    }
                }
            } else {
                endSize = endSize*2;
                prevLen = loopLen;
            }

            /** Reset the variables after setting new window size */
            prevTime.setnow();
            loopLen = 0 ;
            //shutdown(mSock,SHUT_RDWR);
            close(mSock);
            mSock = -1;
            Connect( mSettings->mHost, mSettings->mLocalhost );
            mBuf[0] = 'a';
            if ( set_tcp_windowsize(mSock,endSize) == -1 ) {
                printf(unable_to_change_win);
            }
            if ( get_tcp_windowsize(mSock) != endSize ) {
                printf(unable_to_change_win);
            }
            write( mSock, mBuf, mSettings->mBufLen );
        }
    } while ( ! (sInterupted  ||
                 (mMode_time   &&  mPacketTime.after( mEndTime ))  ||
                 (!mMode_time  &&  mTotalLen >= mAmount))
            );


    printf( seperator_line );
    ReportWindowSize();
    sReporting.Lock();
    ReportBW( loopLen, prevTime.subSec(mStartTime),  mPacketTime.subSec( mStartTime));
    sReporting.Unlock();

    printf( seperator_line);
    printf( opt_estimate);
    if ( loopLen > prevLen )
        set_tcp_windowsize(mSock,endSize);
    else
        set_tcp_windowsize(mSock,startSize);

    ReportWindowSize();
    printf( seperator_line );

    // stop timing
    mEndTime.setnow();

    sReporting.Lock();
    ReportBW( mTotalLen, 0.0, mEndTime.subSec( mStartTime ));
    sReporting.Unlock();

    if ( mSettings->mPrintMSS ) {
        // read the socket option for MSS (maximum segment size)
        ReportMSS( getsock_tcp_mss( mSock ));
    }
    //close(mSock);
    //mSock = -1;
}
Exemple #16
0
void PerfSocket::Send_TCP( void ) {
    if ( false ) {
        Client_Recv_TCP();
        return;
    }

    // terminate loop nicely on user interupts
    sInterupted = false;
    SigfuncPtr oldINT = my_signal( SIGINT,  Sig_Interupt );
    SigfuncPtr oldPIPE = my_signal( SIGPIPE, Sig_Interupt );

    int currLen;
    bool canRead;
    InitTransfer();

    do {

        // If the input is from a 
        // file, fill the buffer with
        // data from the file 
        if ( mSettings->mFileInput ) {
            extractor->getNextDataBlock(mBuf);

            // If the first character is 'a'
            // change if to '0' so that the
            // server does not mistake it for
            // a Window Suggest option
            if ( mBuf[0] == 'a' )
                mBuf[0] = '0';
            canRead = extractor->canRead();
        } else
            canRead = true;

        // perform write
        currLen = write( mSock, mBuf, mSettings->mBufLen );
        mPacketTime.setnow();
        if ( currLen < 0 ) {
            WARN_errno( currLen < 0, "write" );
            break;
        }

        // periodically report bandwidths
        ReportPeriodicBW();

        mTotalLen += currLen;

    } while ( ! (sInterupted  ||
                 (mMode_time   &&  mPacketTime.after( mEndTime ))  ||
                 (!mMode_time  &&  mTotalLen >= mAmount)) && canRead );

    if ( oldINT != Sig_Interupt ) {
        // Return signal handlers to previous handlers
        my_signal( SIGINT, oldINT );
        my_signal( SIGPIPE, oldPIPE );
    }

    // shutdown sending connection and wait (read)
    // for the other side to shutdown
    shutdown( mSock, SHUT_WR );
    currLen = read( mSock, mBuf, mSettings->mBufLen );
    WARN_errno( currLen == SOCKET_ERROR, "read on server close" );
    WARN( currLen > 0, "server sent unexpected data" );

    // stop timing
    mEndTime.setnow();
    sReporting.Lock();
    ReportBW( mTotalLen, 0.0, mEndTime.subSec( mStartTime ));
    sReporting.Unlock();

    if ( mSettings->mPrintMSS ) {
        // read the socket option for MSS (maximum segment size)
        ReportMSS( getsock_tcp_mss( mSock ));
    }

}