📄 ttcpproxy.cpp
字号:
// TTCPProxy.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <io.h>
#include "getopt.h"
/*
* T T C P . C
*
* Test TCP connection. Makes a connection on port 5001
* and transfers fabricated buffers or data copied from stdin.
*
* Usable on 4.2, 4.3, and 4.1a systems by defining one of
* BSD42 BSD43 (BSD41a)
* Machines using System V with BSD sockets should define SYSV.
*
* Modified for operation under 4.2BSD, 18 Dec 84
* T.C. Slattery, USNA
* Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
* Modified in 1989 at Silicon Graphics, Inc.
* catch SIGPIPE to be able to print stats when receiver has died
* for tcp, don't look for sentinel during reads to allow small transfers
* increased default buffer size to 8K, g_nNumBuffersToSend to 2K to transfer 16MB
* moved default port to 5001, beyond IPPORT_USERRESERVED
* make sinkmode default because it is more popular,
* -s now means don't sink/source.
* in sink/source mode use pattern generator to fill send
* buffer (once at init time). received data is tossed.
* count number of read/write system calls to see effects of
* blocking from full socket buffers
* for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
* buffer alignment options, -A and -O
* print stats in a format that's a bit easier to use with grep & awk
* for SYSV, mimic BSD routines to use most of the existing timing code
* Modified by Steve Miller of the University of Maryland, College Park
* -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
* Modified Sept. 1989 at Silicon Graphics, Inc.
* restored -s sense at request of tcs@brl
* Modified Oct. 1991 at Silicon Graphics, Inc.
* use getopt(3) for option processing, add -f and -T options.
* SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
*
* PCAUSA Version 1.00.00.01 - Modified April, 1999 at Printing
* Communications Assoc., Inc. (PCAUSA) PCAUSA. Initial port to Winsock.
*
* PCAUSA Version 1.00.00.02 - Modified January, 2000 at Printing
* Communications Assoc., Inc. (PCAUSA) to fix setting of setsockopt call
* for TCP_NODELAY.
*
* PCAUSA Version 2.01.01.04 - Modified May, 2002 at Printing
* Communications Assoc., Inc. (PCAUSA). Incorporates substantial rework
* suit the author's style and purpose (as a sockets programming learning
* program and a TCP/IP exploration tool).
*
* Although the functionality has been extended, the application is
* backwards-compatible with previous PCAUSA releases.
*
* PCAUSA Version 2.01.01.05 - Modified May, 2002 at PCAUSA. Modification
* to allow SO_RVCBUF and SO_SNDBUF values of zero(0) to be handled.
*
* PCAUSA Version 2.01.01.06 - Modified April, 2003 at PCAUSA. Fixed minor
* bug in TTCP transmitter. PCAUSA PCATTCP preamble was not inserted
* correctly when building transmit buffer.
*
* PCAUSA Version 2.01.01.07 - Modified November, 2003 at PCAUSA.
* Incorporated fix identified by Clarkson University that reduces
* hangs when ending the UDP transmitter test. See additional comments
* in TTCP_TransmitUDP module.
*
* Distribution Status -
* Public Domain. Distribution Unlimited.
*/
#define PCATTCP_VERSION "2.02.06.15"
/////////////////////////////////////////////////////////////////////////////
//// GLOBAL VARIABLES
//
extern int errno;
BOOL g_bShutdown = FALSE; // Set by Ctrl-C Handler
WSADATA g_WsaData;
#ifndef IPPORT_TTCP
#define IPPORT_TTCP 5001
#endif
#define IPPORT_TTCP_PROXY 5002
typedef
struct _CMD_BLOCK
{
//
// Test Command/Configuration Data
//
BOOLEAN m_bTransmit;
USHORT m_Protocol;
SOCKADDR_IN m_RemoteAddr; // Host Byte Order
int m_nRemoteAddrLen;
SOCKADDR_IN m_LocalAddress; // Host Byte Order
USHORT m_Port; // Host Byte Order
BOOLEAN m_bOptContinuous;
int m_nOptWriteDelay; // milliseconds of delay before each write
BOOLEAN m_bOptMultiReceiver;
BOOLEAN m_bTouchRecvData;
BOOLEAN m_bSinkMode; // FALSE = normal I/O, TRUE = sink/source mode
int m_nNumBuffersToSend; // number of buffers to send in sinkmode
int m_nBufferSize; // length of buffer
int m_nBufOffset; // align buffer to this
int m_nBufAlign; //modulo this
BOOLEAN m_bUseSockOptBufSize;
int m_nSockOptBufSize; // socket buffer size to use
int m_nSockOptNoDelay; // set TCP_NODELAY socket option
BOOLEAN m_bSockOptDebug; // TRUE = set SO_DEBUG socket option
SOCKET m_ExtraSocket;
}
CMD_BLOCK, *PCMD_BLOCK;
typedef
struct _TEST_BLOCK
{
//
// Command/Configuration Data
//
CMD_BLOCK m_Cmd;
//
// Instance Data
//
PCHAR m_pBufBase; // ptr to dynamic buffer (base)
PCHAR m_pBuf; // ptr to dynamic buffer (aligned)
SOCKET m_Socket_fd; // fd of network send/receive socket
//
// Statistics
//
DWORD m_tStart;
DWORD m_tFinish;
unsigned long m_numCalls; // # of I/O system calls
double m_nbytes; // bytes on net
}
TEST_BLOCK, *PTEST_BLOCK;
int b_flag = 0; // use mread()
int one = 1; // for 4.3 BSD style setsockopt()
int zero = 0; // for 4.3 BSD style setsockopt()
int verbose = 0; // 0=print basic info, 1=print cpu rate, proc
// resource usage.
char fmt = 'K'; // output format:
// k = kilobits, K = kilobytes,
// m = megabits, M = megabytes,
// g = gigabits, G = gigabytes
#define UDP_GUARD_BUFFER_LENGTH 4
//
// Forward Procedure Prototypes
//
void TTCP_ExitTest( PTEST_BLOCK pTBlk, BOOLEAN bExitProcess );
void TTCP_ExitTestOnWSAError( PTEST_BLOCK pTBlk, PCHAR pFnc );
void TTCP_ExitTestOnCRTError( PTEST_BLOCK pTBlk, PCHAR pFnc );
int TTCP_Nread( PTEST_BLOCK pTBlk, int count );
int TTCP_Nwrite( PTEST_BLOCK pTBlk, int count );
int TTCP_mread( PTEST_BLOCK pTBlk, unsigned n );
char *outfmt(double b);
void delay( int us );
/////////////////////////////////////////////////////////////////////////////
//// Miscellaneous Support Routines
//
void DumpRuleBuffer( PTCP_REDIR_RULE_BUFFER pRuleBuffer )
{
ULONG i;
struct in_addr in_temp;
if( pRuleBuffer == NULL )
{
printf( "Rule Buffer is NULL\n" );
}
printf( "Dumping %d Rules\n\n", pRuleBuffer->RuleCount );
for( i = 0; i < pRuleBuffer->RuleCount; ++i )
{
if( pRuleBuffer->RuleArray[ i ].RemoteAddressRangeStart == 0 )
{
printf( "Any Remote Address" );
}
else
{
if( pRuleBuffer->RuleArray[ i ].RemoteAddressRangeStart
== pRuleBuffer->RuleArray[ i ].RemoteAddressRangeEnd
)
{
in_temp.S_un.S_addr = pRuleBuffer->RuleArray[ i ].RemoteAddressRangeStart;
printf( "%s", inet_ntoa( in_temp ) );
}
else
{
in_temp.S_un.S_addr = pRuleBuffer->RuleArray[ i ].RemoteAddressRangeStart;
printf( "%s - ", inet_ntoa( in_temp ) );
in_temp.S_un.S_addr = pRuleBuffer->RuleArray[ i ].RemoteAddressRangeEnd;
printf( "%s", inet_ntoa( in_temp ) );
}
}
printf( ":%d -> ", pRuleBuffer->RuleArray[ i ].RemotePort );
in_temp.S_un.S_addr = pRuleBuffer->RuleArray[ i ].RedirectToAddress;
printf( "%s:%d\n", inet_ntoa( in_temp ), pRuleBuffer->RuleArray[ i ].RedirectToPort );
if( *pRuleBuffer->RuleArray[ i ].ProcessNameToRedirect == 0 )
{
printf( " Redirect Any Process " );
}
else
{
printf( " Redirect Process \042%s\042 ", pRuleBuffer->RuleArray[ i ].ProcessNameToRedirect);
}
if( pRuleBuffer->RuleArray[ i ].ProcessIdToIgnore == 0 )
{
if( *pRuleBuffer->RuleArray[ i ].ProcessNameToIgnore == 0 )
{
printf( "\n" );
}
else
{
printf( "Except \042%s\042\n", pRuleBuffer->RuleArray[ i ].ProcessNameToIgnore);
}
}
else
{
printf( "Except Process %d\n", pRuleBuffer->RuleArray[ i ].ProcessIdToIgnore);
}
printf( "\n" );
}
printf( "\n" );
}
void TTCP_LogMsg( const char *format, ... )
{
// FILE *logfd = NULL;
FILE *logfd = stderr;
char szBuffer[ 256 ];
va_list marker;
if( !logfd )
{
// LogOpen();
}
if( !logfd )
{
return;
}
va_start( marker, format );
vsprintf( szBuffer, format, marker );
fprintf( logfd, szBuffer );
}
void TTCP_InitStatistics( PTEST_BLOCK pTBlk )
{
pTBlk->m_numCalls = 0; // # of I/O system calls
pTBlk->m_nbytes = 0; // bytes on net
pTBlk->m_tStart = GetTickCount();
}
void TTCP_LogStatistics( PTEST_BLOCK pTBlk )
{
double realt; // user, real time (seconds)
pTBlk->m_tFinish = GetTickCount();
realt = ((double )pTBlk->m_tFinish - (double )pTBlk->m_tStart)/1000;
if( pTBlk->m_Cmd.m_Protocol == IPPROTO_UDP )
{
if( pTBlk->m_Cmd.m_bTransmit )
{
TTCP_LogMsg( " Statistics : UDP -> %s:%d\n",
inet_ntoa( pTBlk->m_Cmd.m_RemoteAddr.sin_addr ),
pTBlk->m_Cmd.m_Port );
}
else
{
TTCP_LogMsg( " Statistics : UDP <- %s:%d\n",
inet_ntoa( pTBlk->m_Cmd.m_RemoteAddr.sin_addr ),
htons( pTBlk->m_Cmd.m_RemoteAddr.sin_port ) );
}
}
else
{
if( pTBlk->m_Cmd.m_bTransmit )
{
TTCP_LogMsg( " Statistics : TCP -> %s:%d\n",
inet_ntoa( pTBlk->m_Cmd.m_RemoteAddr.sin_addr ),
pTBlk->m_Cmd.m_Port
);
}
else
{
TTCP_LogMsg( " Statistics : TCP <- %s:%d\n",
inet_ntoa( pTBlk->m_Cmd.m_RemoteAddr.sin_addr ),
htons( pTBlk->m_Cmd.m_RemoteAddr.sin_port ) );
}
}
TTCP_LogMsg(
"%.0f bytes in %.2f real seconds = %s/sec +++\n",
pTBlk->m_nbytes,
realt,
outfmt(pTBlk->m_nbytes/realt)
);
TTCP_LogMsg( "numCalls: %d; msec/call: %.2f; calls/sec: %.2f\n",
pTBlk->m_numCalls,
1024.0 * realt/((double )pTBlk->m_numCalls),
((double )pTBlk->m_numCalls)/realt
);
}
/////////////////////////////////////////////////////////////////////////////
//// TEST_BLOCK Support Routines
//
// Remarks
// A TEST_BLOCK structure is allocated for each TTCP primary test routine:
//
// TTCP_TransmitTCP
// TTCP_TransmitUDP
// TTCP_ReceiveTCP
// TTCP_ListenTCP
// TTCP_ReceiveUDP
//
// The TEST_BLOCK is a private "instance data" structure that contains
// all of the information necessary to perform the function. It includes
// a copy of the CMD_BLOCK parameters that control the test's operation
// as well as other members to keep track of SOCKETs, buffers and
// statistics associated with the test function.
//
// Each TTCP primary test function allocates its own TEST_BLOCK and is
// responsible for eventually freeing it.
//
// In the blocking single-threaded PCATTCP version use of this mechanism
// is certainly overkill, and serves no truly useful purpose. Global
// data would have been just as effective.
//
// HOWEVER, this approach was taken in anticipation of eventually enhancing
// the test to be multi-threaded - which will actually be trivial.
//
PTEST_BLOCK
TTCP_AllocateTestBlock( PCMD_BLOCK pCmdBlk )
{
PTEST_BLOCK pTBlk = NULL;
pTBlk = (PTEST_BLOCK )malloc( sizeof( TEST_BLOCK ) );
if( !pTBlk )
{
TTCP_ExitTestOnCRTError( NULL, "malloc" );
return( NULL );
}
memset( pTBlk, 0x00, sizeof( TEST_BLOCK ) );
memcpy( &pTBlk->m_Cmd, pCmdBlk, sizeof( CMD_BLOCK ) );
pTBlk->m_Socket_fd = INVALID_SOCKET; // fd of network send/receive socket
return( pTBlk );
}
void TTCP_FreeTestBlock( PTEST_BLOCK pTBlk )
{
if( !pTBlk )
{
return;
}
if( pTBlk->m_pBufBase )
{
free( pTBlk->m_pBufBase );
}
pTBlk->m_pBufBase = NULL;
if( pTBlk->m_Socket_fd != INVALID_SOCKET )
{
closesocket( pTBlk->m_Socket_fd );
pTBlk->m_Socket_fd = INVALID_SOCKET;
}
pTBlk->m_Socket_fd = INVALID_SOCKET;
free( pTBlk );
}
/////////////////////////////////////////////////////////////////////////////
//// TTCP Exit Routines
//
// Remarks
// The TTCP tests exit by calling one of
//
// TTCP_ExitTest - Call for normal exit.
// TTCP_ExitTestOnWSAError - Call to exit when Winsock error is encountered.
// TTCP_ExitTestOnCRTError - Call to exit when OS/DOS error is encountered.
//
// The exit routines systematically free the TEST_BLOCK resources and the
// TEST_BLOCK structure itself.
//
// They exit by calling ExitThread or ExitProcess. Understand that in
// the single-threaded version a call to ExitThread simply exits the
// main program thread. That is: it is equivalent to calling ExitProcess.
//
void TTCP_ExitTest( PTEST_BLOCK pTBlk, BOOLEAN bExitProcess )
{
if( pTBlk )
{
TTCP_FreeTestBlock( pTBlk );
}
if( bExitProcess )
{
WSACleanup();
TcpRedirector_ClearRedirectRules();
TcpRedirector_Shutdown();
ExitProcess( 1 );
}
ExitThread( 1 );
}
void TTCP_ExitTestOnWSAError( PTEST_BLOCK pTBlk, PCHAR pFnc )
{
int nError = WSAGetLastError();
TTCP_LogMsg( "*** Winsock Error: %s Failed; Error: %d (0x%8.8X)\n",
pFnc, nError, nError );
TTCP_ExitTest( pTBlk, TRUE );
}
void TTCP_ExitTestOnCRTError( PTEST_BLOCK pTBlk, PCHAR pFnc )
{
TTCP_LogMsg( "*** CRT Error: %s Failed; Error: %d (0x%8.8X)\n",
pFnc, errno, errno );
TTCP_ExitTest( pTBlk, TRUE );
}
/////////////////////////////////////////////////////////////////////////////
//// CtrlHandler
//
// Purpose
// Console Ctrl-C handler.
//
// Parameters
//
// Return Value
//
// Remarks
//
BOOL WINAPI CtrlHandler( DWORD dwCtrlType )
{
//
// Sanity Checks
//
switch( dwCtrlType )
{
case CTRL_C_EVENT:
TTCP_LogMsg( "Ctrl+C Event\n" );
TTCP_LogMsg( "TTCP shutting down...\n" );
g_bShutdown = TRUE;
//
// Flush Logged Messages
// ---------------------
// This allows redirected console output to be saved OK.
//
fflush( stderr );
fflush( stdout );
ExitProcess(1);
return( TRUE );
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_SHUTDOWN_EVENT:
default:
return( FALSE );
}
return( FALSE );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -