⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pinger.cpp

📁 电驴的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*---------------------------------------------------------------------
*
*  Some code in this file has been copied from a ping demo that was
*  created by Bob Quinn, 1997          http://www.sockets.com
*
* As some general documenation about how the ping is implemented,
* here is the description Bob Quinn wrote about the ping demo.
*
* <--- Cut --->
*
* Description:
*  This is a ping program that uses Microsoft's ICMP.DLL functions 
*  for access to Internet Control Message Protocol.  This is capable
*  of doing "ping or "traceroute", although beware that Microsoft 
*  discourages the use of these APIs.
*
*  Tested with MSVC 5 compile with "cl ms_icmp.c /link ws2_32.lib"
*  from the console (if you've run VCVARS32.BAT batch file that
*  ships with MSVC to set the proper environment variables)
*
* NOTES:
* - With both "Don't Fragment" and "Router Alert" set, the 
*    IP don't fragment bit is set, but not the router alert option.
* - The ICMP.DLL calls are not redirected to the TCP/IP service
*    provider (what's interesting about this is that the setsockopt()
*    IP_OPTION flag can't do Router Alert, but this API can ...hmmm.
* - Although the IcmpSendEcho() docs say it can return multiple
*    responses, if I receive multiple responses (e.g. sending to
*    a limited or subnet broadcast address) IcmpSendEcho() only
*    returns one.  Interesting that NT4 and Win98 don't respond
*    to broadcast pings.
* - using winsock.h  WSOCK32.LIB and version 1.1 works as well as 
*    using winsock2.h WS2_32.LIB  and version 2.2
*
* Some Background:
*
* The standard Berkeley Sockets SOCK_RAW socket type, is normally used
* to create ping (echo request/reply), and sometimes traceroute applications
* (the original traceroute application from Van Jacobson used UDP, rather
* than ICMP). Microsoft's WinSock version 2 implementations for NT4 and 
* Windows 95 support raw sockets, but none of their WinSock version 1.1
* implementations (WFWG, NT3.x or standard Windows 95) did.
*
* Microsoft has their own API for an ICMP.DLL that their ping and tracert
* applications use (by the way, they are both non-GUI text-based console
* applications. This is a proprietary API, and all function calls that 
* involve network functions operate in blocking mode. They still include 
* it with WinSock 2 implementations.
*
* There is little documentation available (I first found it in the Win32
* SDK in \MSTOOLS\ICMP, and it exists on the MS Developers' Network
* CD-ROM now, also). Microsoft disclaims this API about as strongly as 
* possible.  The README.TXT that accompanies it says:
*
* [DISCLAIMER]
* 
* We have had requests in the past to expose the functions exported from
* icmp.dll. The files in this directory are provided for your convenience
* in building applications which make use of ICMPSendEcho(). Notice that
* the functions in icmp.dll are not considered part of the Win32 API and
* will not be supported in future releases. Once we have a more complete
* solution in the operating system, this DLL, and the functions it exports,
* will be dropped.    
*      
* [DOCUMENTATION]     
*
* The ICMPSendEcho() function sends an ICMP echo request to the specified
* destination IP address and returns any replies received within the timeout
* specified. The API is synchronous, requiring the process to spawn a thread
* before calling the API to avoid blocking. An open IcmpHandle is required
* for the request to complete. IcmpCreateFile() and IcmpCloseHandle() 
* functions are used to create and destroy the context handle.
*
* <--- End cut --->
*/

/*---------------------------------------------------------------------
* Reworked (tag UDPing) to use UDP packets and ICMP_TTL_EXPIRE responses
* to avoid problems with some ISPs disallowing or limiting ICMP_ECHO
* (ping) requests. This has downside on NT based systems - raw sockets
* can be used only by administrative users; thereby current code has to
* implement both approaches.
*
* Example code and ideas used from (credits go to articles authors):
* http://tangentsoft.net/wskfaq/examples/rawping.html
* http://www.cs.concordia.ca/~teaching/comp445/labs/webpage/ch16.htm
* http://www.networksorcery.com/enp/protocol/icmp.htm
*
* NB! Take care about winsock libraries - look below for IP_TTL!
*
* Partial copyright (c) 2003 by DonQ
*/

#include "stdafx.h"
#include <Ws2tcpip.h>       // UDPing - raw socket and TTL setting support
#include "emule.h"
#include "TimeTick.h"
#include "Pinger.h"
#include "emuledlg.h"
#include "OtherFunctions.h"

extern CString GetErrorMessage(DWORD dwError, DWORD dwFlags);

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#define BUFSIZE     8192
#define DEFAULT_LEN 0
#define TIMEOUT     3000

/*---------------------------------------------------------
 * IcmpSendEcho() Error Strings
 * 
 * The values in the status word returned in the ICMP Echo 
 *  Reply buffer after calling IcmpSendEcho() all have a
 *  base value of 11000 (IP_STATUS_BASE).  At times,
 *  when IcmpSendEcho() fails outright, GetLastError() will 
 *  subsequently return these error values also.
 *
 * Two Errors value defined in ms_icmp.h are missing from 
 *  this string table (just to simplify use of the table):
 *    "IP_GENERAL_FAILURE (11050)"
 *    "IP_PENDING (11255)"
 */
#define MAX_ICMP_ERR_STRING  IP_STATUS_BASE + 22
static const LPCTSTR aszSendEchoErr[] = {
    _T("IP_STATUS_BASE (11000)"),
    _T("IP_BUF_TOO_SMALL (11001)"),
    _T("IP_DEST_NET_UNREACHABLE (11002)"),
    _T("IP_DEST_HOST_UNREACHABLE (11003)"),
    _T("IP_DEST_PROT_UNREACHABLE (11004)"),
    _T("IP_DEST_PORT_UNREACHABLE (11005)"),
    _T("IP_NO_RESOURCES (11006)"),
    _T("IP_BAD_OPTION (11007)"),
    _T("IP_HW_ERROR (11008)"),
    _T("IP_PACKET_TOO_BIG (11009)"),
    _T("IP_REQ_TIMED_OUT (11010)"),
    _T("IP_BAD_REQ (11011)"),
    _T("IP_BAD_ROUTE (11012)"),
    _T("IP_TTL_EXPIRED_TRANSIT (11013)"),
    _T("IP_TTL_EXPIRED_REASSEM (11014)"),
    _T("IP_PARAM_PROBLEM (11015)"),
    _T("IP_SOURCE_QUENCH (11016)"),
    _T("IP_OPTION_TOO_BIG (11017)"),
    _T("IP_BAD_DESTINATION (11018)"),
    _T("IP_ADDR_DELETED (11019)"),
    _T("IP_SPEC_MTU_CHANGE (11020)"),
    _T("IP_MTU_CHANGE (11021)"),
    _T("IP_UNLOAD (11022)")
};

Pinger::Pinger() {
    // udp start
    sockaddr_in sa;     // for UDP and raw sockets

    // ICMP must accept all responses
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = INADDR_ANY;	
    sa.sin_port = 0;

    udpStarted = false;
    // attempt to initialize raw ICMP socket
    is = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (is != INVALID_SOCKET) {
        int nRet = bind(is, (sockaddr *)&sa, sizeof(sa));
        if (nRet==SOCKET_ERROR) { 
            nRet = WSAGetLastError();
            closesocket(is);        // ignore return value - error close anyway
        } else {
            // attempt to initialize ordinal UDP socket - why should this fail???
            // NB! no need to bind this at a moment - will be bound later, implicitly at sendto
            us = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if (us == INVALID_SOCKET) {
                closesocket(is);            // ignore return value - we need to close it anyway!
            } else {
                udpStarted = true;
            }
        }
    }
    // udp end
 
    // Open ICMP.DLL
    hICMP_DLL = LoadLibrary(_T("ICMP.DLL"));
    if (hICMP_DLL == 0) {
        theApp.QueueDebugLogLine(false,_T("Pinger: LoadLibrary() failed: Unable to locate ICMP.DLL!"));
        return;
    }

    // Get pointers to ICMP.DLL functions
    lpfnIcmpCreateFile  = (IcmpCreateFile*)GetProcAddress(hICMP_DLL,"IcmpCreateFile");
    lpfnIcmpCloseHandle = (IcmpCloseHandle*)GetProcAddress(hICMP_DLL,"IcmpCloseHandle");
    lpfnIcmpSendEcho    = (IcmpSendEcho*)GetProcAddress(hICMP_DLL,"IcmpSendEcho");
    if ((!lpfnIcmpCreateFile) || 
        (!lpfnIcmpCloseHandle) || 
        (!lpfnIcmpSendEcho)) {

        theApp.QueueDebugLogLine(false,_T("Pinger: GetProcAddr() failed for at least one function."));
        return;
    }

    // Open the ping service
    hICMP = (HANDLE) lpfnIcmpCreateFile();
    if (hICMP == INVALID_HANDLE_VALUE) {
        int nErr = GetLastError();
        theApp.QueueDebugLogLine(false, _T("Pinger: IcmpCreateFile() failed, err: %u"), nErr);
        PIcmpErr(nErr);
        return;
    }

    // Init IPInfo structure
    stIPInfo.Tos      = 0;
    stIPInfo.Flags    = 0;
    stIPInfo.OptionsSize = 0;
    stIPInfo.OptionsData = NULL;
}

Pinger::~Pinger() {
    // UDPing reworked cleanup -->
    if (udpStarted) {
        closesocket(is);                // close UDP socket
        closesocket(us);                // close raw ICMP socket
    }
    // UDPing reworked cleanup end <--

    // Close the ICMP handle
    BOOL fRet = lpfnIcmpCloseHandle(hICMP);
    if (fRet == FALSE) {
        int nErr = GetLastError();
        theApp.QueueDebugLogLine(false,_T("Error closing ICMP handle, err: %u"), nErr);
        PIcmpErr(nErr);
    }

    // Shut down...
    FreeLibrary(hICMP_DLL);
}

PingStatus Pinger::Ping(uint32 lAddr, uint32 ttl, bool doLog, bool useUdp) {
    if(useUdp && udpStarted) {
        return PingUDP(lAddr, ttl, doLog);
    } else {
        return PingICMP(lAddr, ttl, doLog);
    }
}

PingStatus Pinger::PingUDP(uint32 lAddr, uint32 ttl, bool doLog) {
	// UDPing reworked ping sequence -->
	int nTTL = ttl;
	int nRet;
	sockaddr_in sa;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -