Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt

WinAPI, Qt, ICMP, PING

Immediately I want to upset you, dear readers. Qt does not have the functionality to work with the ICMP protocol and therefore have to use for this purpose API target operating system. However, this is not surprising. The ICMP protocol is a low-level protocol, and to work with it requires the use of raw sockets, which are not implemented in Qt.

But this is not a particular problem, because the main target platform has the necessary API to implement ping packages. For example Microsoft provides the simple use of ICMP protocol based IcmpSendEcho function.

IcmpSendEcho

The IcmpSendEcho function sends an IPv4 ICMP echo request and returns any echo response replies. The call returns when the time-out has expired or the reply buffer is filled.

DWORD IcmpSendEcho(
  _In_     HANDLE                 IcmpHandle,
  _In_     IPAddr                 DestinationAddress,
  _In_     LPVOID                 RequestData,
  _In_     WORD                   RequestSize,
  _In_opt_ PIP_OPTION_INFORMATION RequestOptions,
  _Out_    LPVOID                 ReplyBuffer,
  _In_     DWORD                  ReplySize,
  _In_     DWORD                  Timeout
);

Parameters

IcmpHandle [in]
The open handle returned by the IcmpCreateFile function.

DestinationAddress [in]
The IPv4 destination address of the echo request, in the form of an IPAddr structure.

RequestData [in]
A pointer to a buffer that contains data to send in the request.

RequestSize [in]
The size, in bytes, of the request data buffer pointed to by the RequestData parameter.

RequestOptions [in, optional]
A pointer to the IP header options for the request, in the form of an IP_OPTION_INFORMATION structure. On a 64-bit platform, this parameter is in the form for an IP_OPTION_INFORMATION32 structure.

This parameter may be NULL if no IP header options need to be specified.

ReplyBuffer [out]
A buffer to hold any replies to the echo request. Upon return, the buffer contains an array of ICMP_ECHO_REPLY structures followed by the options and data for the replies. The buffer should be large enough to hold at least one ICMP_ECHO_REPLY structure plus RequestSize bytes of data.

On a 64-bit platform, upon return the buffer contains an array of ICMP_ECHO_REPLY32 structures followed by the options and data for the replies.

ReplySize [in]
The allocated size, in bytes, of the reply buffer. The buffer should be large enough to hold at least one ICMP_ECHO_REPLY structure plus RequestSize bytes of data. On a 64-bit platform, The buffer should be large enough to hold at least one ICMP_ECHO_REPLY32 structure plus RequestSize bytes of data.

This buffer should also be large enough to also hold 8 more bytes of data (the size of an ICMP error message).

Timeout [in]
The time, in milliseconds, to wait for replies.

Return value

The IcmpSendEcho function returns the number of ICMP_ECHO_REPLY or ICMP_ECHO_REPLY32 structures stored in the ReplyBuffer . The status of each reply is contained in the structure. If the return value is zero, call GetLastError for additional error information.

If the function fails, the extended error code returned by GetLastError can be one of the following values.

  • ERROR_INSUFFICIENT_BUFFER - The data area passed to a system call is too small. This error is returned if the ReplySize parameter indicates that the buffer pointed to by the ReplyBuffer parameter is too small.
  • ERROR_INVALID_PARAMETER - An invalid parameter was passed to the function. This error is returned if the IcmpHandle parameter contains an invalid handle. This error can also be returned if the ReplySize parameter specifies a value less than the size of an ICMP_ECHO_REPLY or ICMP_ECHO_REPLY32 structure.
  • ERROR_NOT_ENOUGH_MEMORY - Not enough memory is available to complete the operation.
  • ERROR_NOT_SUPPORT - The request is not supported. This error is returned if no IPv4 stack is on the local computer.
  • IP_BUF_TOO_SMALL - The size of the ReplyBuffer specified in the ReplySize parameter was too small.
  • Other - Use FormatMessage to obtain the message string for the returned error.

Work with ICMP

IcmpSendEcho function sends an ICMP echo request to the specified address and returns the number of received and saved responses ReplyBuffer . IcmpSendEcho function is a synchronous function and returns the value after the end of the waiting time for an answer. If zero is returned, to obtain extended information call the GetLastError function.

In order to use this part of WinAPI, you must register the following two lines to the .Pro project file:

LIBS     += -lws2_32
LIBS     += -liphlpapi

And also connect the following libraries:

#include "winsock2.h"
#include "iphlpapi.h"
#include "icmpapi.h"

The main application window

In order to become familiar with the ICMP protocol will create a window with the following interface will be displayed where a response to requests, the IP-address and the start button.

widget.h

Apart from the key slot ads you are not able to see anything interesting, but nevertheless bring a header file.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

widget.cpp

And here the most interesting. At the touch of a button We will ping the selected contact IP-address. For beauty solutions I introduced validation of IP-addresses in lineEdit field.

#include "widget.h"
#include "ui_widget.h"
#include "winsock2.h"
#include "iphlpapi.h"
#include "icmpapi.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    // We validate the input data IP-addresses
    QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";

    QRegExp ipRegex ("^" + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange + "$");

    QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
    ui->lineEdit->setValidator(ipValidator);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // We declare variables
    HANDLE hIcmpFile;                       // Handler
    unsigned long ipaddr = INADDR_NONE;     // Destination address
    DWORD dwRetVal = 0;                     // Number of replies
    char SendData[32] = "Data Buffer";      // The buffer data being sent
    LPVOID ReplyBuffer = NULL;              // buffer replies
    DWORD ReplySize = 0;                    // Buffer Size responses

    // Set the IP-address of the field qlineEdit
    ipaddr = inet_addr(ui->lineEdit->text().toStdString().c_str());
    hIcmpFile = IcmpCreateFile();   // create a handler

    // Select the buffer memory responses
    ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
    ReplyBuffer = (VOID*) malloc(ReplySize);

    // Call the ICMP echo request function
    dwRetVal = IcmpSendEcho(hIcmpFile, ipaddr, SendData, sizeof(SendData),
                NULL, ReplyBuffer, ReplySize, 1000);

    // We create a row in which we write the response message
    QString strMessage = "";

    if (dwRetVal != 0) {
        // The structure of the echo response
        PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
        struct in_addr ReplyAddr;
        ReplyAddr.S_un.S_addr = pEchoReply->Address;

        strMessage += "Sent icmp message to " + ui->lineEdit->text() + "\n";
        if (dwRetVal > 1) {
            strMessage += "Received " + QString::number(dwRetVal) + " icmp message responses \n";
            strMessage += "Information from the first response: ";
        }
        else {
            strMessage += "Received " + QString::number(dwRetVal) + " icmp message response \n";
            strMessage += "Information from the first response: ";
        }
            strMessage += "Received from ";
            strMessage += inet_ntoa( ReplyAddr );
            strMessage += "\n";
            strMessage += "Status = " + pEchoReply->Status;
            strMessage += "Roundtrip time = " + QString::number(pEchoReply->RoundTripTime) + " milliseconds \n";
    } else {
        strMessage += "Call to IcmpSendEcho failed.\n";
        strMessage += "IcmpSendEcho returned error: ";
        strMessage += QString::number(GetLastError());
    }

    ui->textEdit->setText(strMessage); // Display information about the received data
    free(ReplyBuffer); // frees memory
}

Conclusion

As a result, you should have an application that will ping the selected IP-address.

Video

Virtual hosting with 10 percent discount
Virtual hosting with 10 percent discount
EVILEG offers reliable hosting with a 10% discount for virtual hosting and 5% for VPS
Support the author Donate

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Looking for a Job?
14,000.00 руб. - 40,000.00 руб.
Разработчик Qt
Annino, Moscow Oblast, Russia
5,000.00 руб. - 15,000.00 руб.
Дизайнер
Moskovskiy, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

A
Aug. 22, 2019, 11:24 p.m.
Aleksandr73

Qt - Test 001. Signals and slots

  • Result:47points,
  • Rating points-6
Aug. 21, 2019, 10:23 a.m.
Andrej Ermoshin

C++ - Test 002. Constants

  • Result:58points,
  • Rating points-2
Aug. 21, 2019, 10:15 a.m.
Andrej Ermoshin

C++ - Test 001. The first program and data types

  • Result:86points,
  • Rating points6
Last comments
Aug. 19, 2019, 7:41 a.m.
Andrej Jankovich

это проблема дистрибутива, попробуйте установить через пакетный менеджер snap Суть проблемы: libQt5Core которая лежит в дистрибутиве требует версию glibc >= 2.25 у вас видимо …
b
Aug. 18, 2019, 6:09 a.m.
bbb116

cqtdeployer /home/aleks/CQtDeployer/bin/cqtdeployer: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by /home/aleks/CQtDeployer/lib/libQt5Core.so.5) linux mint …
D
Aug. 17, 2019, 9:04 a.m.
Damir

github ChekableTView Правой групповая смена значения при перетаскивании левой как обычно.
Aug. 16, 2019, 1:03 p.m.
Evgenij Legotskoj

Потому, что в минуте 60 секунд
Aug. 16, 2019, 12:16 p.m.
Dmitrij

а почему делитель 60000, а не 1000?
Now discuss on the forum
Aug. 24, 2019, 7:21 a.m.
Evgenij Legotskoj

Не помню, давно уже с QML не работал, по-моему, обычно пишет в консоль, что не находит файл. В любом случае какую-то ошибку в консоль выкидывает. Но если честно, если у вас проект будет ак…
BG
Aug. 24, 2019, 4:27 a.m.
Brjus Gliff

Спасибо, вначале в документации было не понятно что к чему, теперь разобрался
I
Aug. 21, 2019, 8:36 a.m.
Intruder

Александр, мне не нужно перебирать. Вы говорите правильно, сначала я написал избыточный код просто не подумав. Задача такая, мне нужно просто переложить из QMap в атрибуты xml тега все, что там …
Aug. 21, 2019, 3:16 a.m.
nayk1982

Если Вы разрабатываете какую-то универсальную утилиту, которая вообще не привязана к логике, тогда как вариант: 1. Получить список таблиц через QSqlDatabase::tables 2. Для каждой табли…
EVILEG
About
Services
© EVILEG 2015-2019
Recommend hosting TIMEWEB