IcmpSendEcho возвращает 183

0

Я приспособил этот пример кода из MSDN здесь. Он отлично работает, если я создаю его самостоятельно, но если я добавлю его в свое приложение, это не сработает. Для удобства я включаю точную адаптацию класса, который у меня есть.

Я только хочу сделать простой пинг каждую секунду. Raw Sockets не работают без прав администратора, и этот подход 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 %s\n", LogDebug, _address);
                if (_dwRetVal > 1) {
                    LogLog("\tReceived %ld icmp message responses\n", LogDebug, _dwRetVal);
                    LogLog("\tInformation from the first response:\n", LogDebug);
                }
                else {
                    LogLog("\tReceived %ld icmp message response\n", LogDebug, _dwRetVal);
                    LogLog("\tInformation from this response:\n", LogDebug);
                }
                LogLog("\t  Received from %s\n", LogDebug, inet_ntoa(ReplyAddr));
                LogLog("\t  Status = %ld\n", LogDebug,
                    pEchoReply->Status);
                LogLog("\t  Roundtrip time = %ld milliseconds\n", LogDebug,
                    pEchoReply->RoundTripTime);

                //needs synchronization here. Probably not very important
                _lastRTT = pEchoReply->RoundTripTime;
                LogLog("\t  Roundtrip time = %ld milliseconds\n", LogDebug, _lastRTT);
                IcmpCloseHandle(_hIcmpFile);
            }
            else {
                LogLog("\tCall to IcmpSendEcho failed.\n", LogError);
                LogLog("\tIcmpSendEcho returned error: %ld\n", 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: %ld\n", LogError, GetLastError());
            return;
        }

        _replySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
        _replyBuffer = (VOID*)malloc(_replySize);
        if (_replyBuffer == NULL) {
            LogLog("\tUnable to allocate memory\n", LogError);
            return;
        }

        //Spawn thread on AsyncPingHandler()
        CreateClassThread(AsyncPingHandler, this);

    }


    WinPing::~WinPing()
    {
    }
  • 1
    Ваш в while цикл в DoPing() бесполезно, так как все пути кода приводят к return так IcmpSendEcho() вызывается только один раз.
  • 0
    Да жаль. Я забыл удалить их в копии, которую я вставил сюда, но это не проблема. Я тоже обновил код здесь.
Показать ещё 1 комментарий
Теги:
winsock
ping
winsock2

2 ответа

1
Лучший ответ

Я узнал, что намного проще, гораздо более стабильный способ выполнения ping - использовать GetRTTandHopCount. Вот пример.

UINT ip = inet_addr(serverAddress);
ULONG hopCount = 0;
ULONG RTT = 0;

if (GetRTTAndHopCount(ip, &hopCount, 30, &RTT) == TRUE) {
    printf("Hops: %ld\n", hopCount);
    printf("RTT: %ld\n", RTT);
}
else {
    printf("Error: %ld\n", GetLastError());
}

return RTT;
1

Вы не вызываете GetLastError() сразу после IcmpSendEcho() (при вызове IcmpCreateFile()). LogLog() вы вызываете LogLog(), что, вероятно, изменяет код ошибки, возвращаемый GetLastError(), например, если он регистрируется в файле, который не может быть найден. ВСЕГДА вызывайте GetLastError() прежде чем делать что-либо, что может вызвать системную функцию.

else {
    DWORD dwErrCode = GetLastError(); // <-- call GetLastError() first
    LogLog("\tCall to IcmpSendEcho failed.\n", LogError);
    LogLog("\tIcmpSendEcho returned error: %u\n", LogError, dwErrCode); // <-- then use the value when needed
    return;
}
  • 0
    Это очень хороший момент. Так что ошибка может быть не 183, а что-то еще. Ошибка ICMP, поскольку возвращаемое значение равно 0, но код ошибки может быть другим. Стоит проверить. Спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню