IcmpSendEcho returns 183

IcmpSendEcho returns 183

本文关键字:returns IcmpSendEcho      更新时间:2023-10-16

我在这里改编了MSDN中的这个代码示例。如果我单独构建它,它可以很好地工作,但如果我将它添加到应用程序中,它就会失败。为了方便起见,我包括了对我所学课程的精确改编。

我只想每秒钟做一次简单的ping。如果没有管理权限,原始套接字就无法工作,而且这种ICMP.dll方法在我的应用程序中也无法工作,我不明白为什么。错误183的行是"无法创建文件,因为它已经存在",这在上下文中毫无意义。

有人能发现问题吗?非常感谢你的帮助。

Ping.h

    #pragma once
    #include "Ping.h"
    #include "LogBase.h"
    class WinPing :
        public Ping
    {
    public:
        WinPing(char* address, int period);
        ~WinPing();
        unsigned long           GetRTT();
    private:
        HANDLE                  _hIcmpFile;
        unsigned long           _ipaddr;
        DWORD                   _dwRetVal;
        LPVOID                  _replyBuffer;
        DWORD                   _replySize;
        static HANDLE           _inputTimer;

        int                     _period;
        unsigned long           _lastRTT;

        static DWORD WINAPI     AsyncPingHandler(void* Param);
        void                    DoPing();   
    };

WinPing.h

    #pragma once
    #include "Ping.h"
    #include "LogBase.h"
    class WinPing :
        public Ping
    {
    public:
        WinPing(char* address, int period);
        ~WinPing();
        unsigned long           GetRTT();
    private:
        HANDLE                  _hIcmpFile;
        unsigned long           _ipaddr;
        DWORD                   _dwRetVal;
        LPVOID                  _replyBuffer;
        DWORD                   _replySize;
        static HANDLE           _inputTimer;

        int                     _period;
        unsigned long           _lastRTT;

        static DWORD WINAPI     AsyncPingHandler(void* Param);
        void                    DoPing();   
    };

WinPing.cpp

    #include "WinPing.h"
    #include <winsock2.h>
    #include <iphlpapi.h>
    #include <icmpapi.h>
    #include <stdio.h>
    #include "utils.h"
    #pragma comment(lib, "iphlpapi.lib")
    #pragma comment(lib, "ws2_32.lib")
    HANDLE WinPing::_inputTimer = NULL;
    char SendData[32] = "Data Buffer";
    unsigned long WinPing::GetRTT()
    {
        return _lastRTT;
    }

    void WinPing::DoPing()
    {
        LARGE_INTEGER t;
        t.HighPart = t.LowPart = 0;
        SetWaitableTimer(_inputTimer, &t, _period, NULL, NULL, TRUE);
        while (true)
        {
            int r = WaitForSingleObject(_inputTimer, _period * 2);
            if (r != WAIT_OBJECT_0)
            {
                LogLog("InputHandler: Bad Timer return", LogError);
            }
            _dwRetVal = IcmpSendEcho(_hIcmpFile, _ipaddr, SendData, sizeof(SendData),
                NULL, _replyBuffer, _replySize, 1000);
            if (_dwRetVal != 0) {
                PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)_replyBuffer;
                struct in_addr ReplyAddr;
                ReplyAddr.S_un.S_addr = pEchoReply->Address;
                LogLog("tSent icmp message to %sn", LogDebug, _address);
                if (_dwRetVal > 1) {
                    LogLog("tReceived %ld icmp message responsesn", LogDebug, _dwRetVal);
                    LogLog("tInformation from the first response:n", LogDebug);
                }
                else {
                    LogLog("tReceived %ld icmp message responsen", LogDebug, _dwRetVal);
                    LogLog("tInformation from this response:n", LogDebug);
                }
                LogLog("t  Received from %sn", LogDebug, inet_ntoa(ReplyAddr));
                LogLog("t  Status = %ldn", LogDebug,
                    pEchoReply->Status);
                LogLog("t  Roundtrip time = %ld millisecondsn", LogDebug,
                    pEchoReply->RoundTripTime);
                //needs synchronization here. Probably not very important
                _lastRTT = pEchoReply->RoundTripTime;
                LogLog("t  Roundtrip time = %ld millisecondsn", LogDebug, _lastRTT);
                IcmpCloseHandle(_hIcmpFile);
            }
            else {
                LogLog("tCall to IcmpSendEcho failed.n", LogError);
                LogLog("tIcmpSendEcho returned error: %ldn", LogError, GetLastError());
            }
        }
    }
    DWORD WINAPI WinPing::AsyncPingHandler(void* Param)
    {
        _inputTimer = CreateWaitableTimer(NULL, false, NULL);
        if (!_inputTimer)
        {
            LogLog("Unable to create input waitable timer", LogError);
            return 1;
        }
        LogLog("RTT Ping Thread started", LogDebug);
        WinPing* This = (WinPing*)Param;
        This->DoPing();
        return 0;
    }

    WinPing::WinPing(char* address, int period)
        :Ping(address),
        _period(period)
    {
        // Declare and initialize variables
        _ipaddr = INADDR_NONE;
        _dwRetVal = 0;
        _replyBuffer = NULL;
        _replySize = 0;

        _ipaddr = inet_addr(address);
        if (_ipaddr == INADDR_NONE) {
            LogLog("Not an IP Address:%s", LogError, address);
            return;
        }
        _hIcmpFile = IcmpCreateFile();
        if (_hIcmpFile == INVALID_HANDLE_VALUE) {
            LogLog("tUnable to open handle.n", LogError);
            LogLog("IcmpCreatefile returned error: %ldn", LogError, GetLastError());
            return;
        }
        _replySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
        _replyBuffer = (VOID*)malloc(_replySize);
        if (_replyBuffer == NULL) {
            LogLog("tUnable to allocate memoryn", LogError);
            return;
        }
        //Spawn thread on AsyncPingHandler()
        CreateClassThread(AsyncPingHandler, this);
    }

    WinPing::~WinPing()
    {
    }

IcmpSendEcho()失败后,您不会立即调用GetLastError()(与调用IcmpCreateFile()时相同)。您首先调用LogLog(),这可能会更改GetLastError()返回的错误代码,例如,如果它正在记录到找不到的文件ALWAYS在执行任何可能调用系统函数的操作之前调用GetLastError()

else {
    DWORD dwErrCode = GetLastError(); // <-- call GetLastError() first
    LogLog("tCall to IcmpSendEcho failed.n", LogError);
    LogLog("tIcmpSendEcho returned error: %un", LogError, dwErrCode); // <-- then use the value when needed
    return;
}

我发现一种更简单、更稳定的ping方法是使用GetRTTandHopCount。下面是一个例子。

UINT ip = inet_addr(serverAddress);
ULONG hopCount = 0;
ULONG RTT = 0;
if (GetRTTAndHopCount(ip, &hopCount, 30, &RTT) == TRUE) {
    printf("Hops: %ldn", hopCount);
    printf("RTT: %ldn", RTT);
}
else {
    printf("Error: %ldn", GetLastError());
}
return RTT;