home *** CD-ROM | disk | FTP | other *** search
- /*
- * Xceed Winsock Library Sample: Ping
- * Copyright (c) 2000 Xceed Software Inc.
- *
- * This sample shows how to implement a "ping" application
- * using The Xceed Winsock Library.
- *
- * In particular, it demonstrate:
- * - Connectionless sockets
- * - Timeouts
- * - Using "#import" with the Xceed Winsock Library
- *
- * This file is part of the Xceed Winsock Library Samples.
- * The source code in this file is only intended as a supplement
- * to Xceed Winsock Library's documentation, and is provided "as is",
- * without warranty of any kind, either expressed or implied.
- *
- */
-
- #include "stdafx.h"
-
- /*
- * This is the easiest way to use the library in Visual C++
- */
-
- #pragma warning( disable : 4786 )
- #import "XceedWsl.dll" no_namespace named_guids
- #pragma warning( default : 4786 )
-
- #include "XcdPing.h"
-
- /*
- * Function prototypes
- */
-
- IXWSocketPtr GetRawICMPSocket( void );
- IXWAddressInfoPtr GetRemoteAddress( _bstr_t bstrHostName );
- u_short in_cksum(u_short *addr, int len);
-
- /*
- * main : This is the entry point of the application
- */
-
- int main(int argc, char* argv[])
- {
- printf( "Xceed Winsock Library Sample - Ping\n" );
- printf( "-----------------------------------\n" );
-
- if( argc < 2 )
- {
- printf( "Usage: %s hostname [count]\n\n", argv[ 0 ] );
- return 0;
- }
-
- CoInitializeEx( NULL, COINIT_MULTITHREADED );
-
- try
- {
- // Create the connectionless socket and the remote address we need.
- IXWAddressInfoPtr piRemoteAddress = GetRemoteAddress( argv[ 1 ] );
- IXWSocketPtr piSocket = GetRawICMPSocket();
-
- // Get a string representation of this address
- WCHAR* pwszRemoteAddress = NULL;
-
- piRemoteAddress->GetAddressString( &pwszRemoteAddress );
-
- printf( "Pinging %s [%S] with %d bytes of data:\n\n",
- argv[ 1 ], pwszRemoteAddress, REQ_DATASIZE );
-
- CoTaskMemFree( pwszRemoteAddress );
-
- // Set the receive timeout to prevent waiting too long for lost packets
- IXWTransferTimeOutPtr piTimeOut = piSocket;
- piTimeOut->SetReceiveTimeOut( 1000 );
- piTimeOut.Release();
-
- IXWAddressedByteTransferPtr piTransfer = piSocket;
-
- int nCount = ( argc >= 3 ) ? atoi( argv[ 2 ] ) : PING_COUNT;
-
- for( int i = 0; i < nCount; i++ )
- {
- // Build the packet that we send to the ping server
- SEchoRequest xRequest;
-
- xRequest.xIcmpHeader.cType = ICMP_ECHOREQ;
- xRequest.xIcmpHeader.cCode = 0;
- xRequest.xIcmpHeader.wChecksum = 0;
- xRequest.xIcmpHeader.wID = i + 1;
- xRequest.xIcmpHeader.wSeq = i + 1;
-
- for( int j = 0; j < REQ_DATASIZE; j++ )
- xRequest.cData[ j ] = ' ' + j;
-
- xRequest.dwTime = GetTickCount();
-
- xRequest.xIcmpHeader.wChecksum = in_cksum( reinterpret_cast< WORD* >( &xRequest ), sizeof( SEchoRequest ) );
-
- // Send this structure as an array of bytes
- piTransfer->SendBytesTo( piRemoteAddress, sizeof( SEchoRequest ),
- reinterpret_cast< BYTE* >( &xRequest ), wsoNone );
-
- // Try to receive answer
- IXWAddressInfoPtr piReceiveAddress;
- DWORD dwReceivedSize = 0;
- BYTE* pcReceivedData = NULL;
-
- try
- {
- piTransfer->ReceiveBytesFrom( &piReceiveAddress, &dwReceivedSize, &pcReceivedData, wroWaitForData );
- }
- catch( const _com_error& xErr )
- {
- if( xErr.Error() == WSL_E_RECEIVETIMEDOUT )
- {
- printf( "Request timed out.\n" );
- continue;
- }
-
- throw( xErr );
- }
-
- // Display information about he received answer
- DWORD dwReceiveTime = GetTickCount();
-
- if( !dwReceivedSize || !pcReceivedData )
- throw( _bstr_t( L"Got an invalid packet." ) );
-
- if( dwReceivedSize < sizeof( SEchoReply ) )
- {
- CoTaskMemFree( pcReceivedData );
- throw( _bstr_t( L"Got an invalid packet." ) );
- }
-
- SEchoReply xReply;
-
- CopyMemory( &xReply, pcReceivedData, sizeof( SEchoReply ) );
- CoTaskMemFree( pcReceivedData );
-
- WCHAR* pwszReceiveAddress = NULL;
-
- piReceiveAddress->GetAddressString( &pwszReceiveAddress );
-
- printf( "Reply from %S: bytes=%d time=%dms TTL=%d\n", pwszReceiveAddress,
- REQ_DATASIZE,
- dwReceiveTime - xReply.xEchoRequest.dwTime,
- static_cast< int >( xReply.xIpHeader.cTimeToLive ) );
-
- CoTaskMemFree( pwszReceiveAddress );
-
- // Wait one second between each ping
- Sleep( 1000 );
- }
- }
- catch( const _com_error& xErr )
- {
- printf( "*** COM Error %08X\n%s\n\n", xErr.Error(),
- static_cast< const char* >( xErr.Description() ) );
- }
- catch( const _bstr_t& bstrErr )
- {
- printf( "%s\n\n", static_cast< const char* >( bstrErr ) );
- }
- catch( ... )
- {
- printf( "*** Unhandled exception.\n\n" );
- }
-
- CoUninitialize();
- return 0;
- }
-
- /*
- * GetRawICMPSocket : Create a socket using the ICMP protocol, with raw data format.
- */
-
- IXWSocketPtr GetRawICMPSocket( void )
- {
- // Create the ICMP protocol
- IXWProtocolLookupPtr piProtocolLookup( CLSID_Protocols );
- IXWProtocolInfoPtr piProtocol;
-
- piProtocolLookup->GetProtocol( wafInet, wstRaw, wptIP_ICMP, &piProtocol );
-
- // Create the connectionless socket
- IXWSocketFactoryPtr piSocketFactory( CLSID_SocketFactory );
- IXWSocketPtr piSocket;
-
- piSocketFactory->CreateConnectionlessSocket( piProtocol, 0,
- const_cast< GUID* >( &__uuidof( piSocket ) ),
- reinterpret_cast< void** >( &piSocket ) );
-
- return piSocket;
- }
-
- /*
- * GetRemoteAddress : Create an inet address from a string either
- * representing a host name (like www.microsoft.com)
- * or dotted inet address (like 192.168.0.200)
- */
-
- IXWAddressInfoPtr GetRemoteAddress( _bstr_t bstrHostName )
- {
- IXWProvideAddressesPtr piProvideAddresses( CLSID_AddressManager );
- IXWAddressInfoPtr piAddress;
-
- // First, try to get the address out of a dotted address string format.
- piProvideAddresses->GetAddress( wafInet, const_cast< GUID* >( &__uuidof( piAddress ) ),
- reinterpret_cast< void** >( &piAddress ) );
-
- try
- {
- piAddress->SetAddressString( bstrHostName );
- }
- catch( const _com_error& xErr )
- {
- if( xErr.Error() != WSL_E_INVALIDADDRESSSTRING )
- throw( xErr );
-
- piAddress.Release();
- }
-
- if( !piAddress.GetInterfacePtr() )
- {
- IXWEnumAddressPtr piEnumAddress;
-
- // If SetAddressStrin failed, try to translate a host name to an address.
- piProvideAddresses->GetAddressesFromHostName( bstrHostName, wnsDNS, &piEnumAddress );
- piEnumAddress->RemoteNext( 1, &piAddress, NULL );
- }
-
- return piAddress;
- }
-
- //
- // Mike Muuss' in_cksum() function
- // and his comments from the original
- // ping program
- //
- // * Author -
- // * Mike Muuss
- // * U. S. Army Ballistic Research Laboratory
- // * December, 1983
-
- /*
- * I N _ C K S U M
- *
- * Checksum routine for Internet Protocol family headers (C Version)
- *
- */
- u_short in_cksum(u_short *addr, int len)
- {
- register int nleft = len;
- register u_short *w = addr;
- register u_short answer;
- register int sum = 0;
-
- /*
- * Our algorithm is simple, using a 32 bit accumulator (sum),
- * we add sequential 16 bit words to it, and at the end, fold
- * back all the carry bits from the top 16 bits into the lower
- * 16 bits.
- */
- while( nleft > 1 ) {
- sum += *w++;
- nleft -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
- u_short u = 0;
-
- *(u_char *)(&u) = *(u_char *)w ;
- sum += u;
- }
-
- /*
- * add back carry outs from top 16 bits to low 16 bits
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* truncate to 16 bits */
- return (answer);
- }
-