Privacy policyContactsAbout siteOpinionsGitHubDonate
© EVILEG 2015-2018
Recommend hosting
TIMEWEB

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

10% refund of hotel reservation amount on Booking
10% refund of hotel reservation amount on Booking
We offer a link with a 10% return on the amount of the order when booking a hotel through Booking

Comments

Only authorized users can post comments.
Please, Log in or Sign up
МБ
April 21, 2019, 9:40 a.m.
Моисей Бушуев

Qt - Test 001. Signals and slots

  • Result:0points,
  • Rating points-10
AA
April 17, 2019, 7:40 p.m.
Anton Ablin

Qt - Test 001. Signals and slots

  • Result:73points,
  • Rating points1
E
April 17, 2019, 6:16 p.m.
Evgeny

Qt - Test 001. Signals and slots

  • Result:100points,
  • Rating points10
Last comments
April 21, 2019, 4:22 p.m.
Евгений Легоцкой

Через метод setIcon table.horizontalHeaderItem(0).setIcon("qrc://path/to/icon.png")
April 21, 2019, 3:48 p.m.
Евгений Легоцкой

Добрый день! Спасибо за комментарий. Там действительно лучше будет сделать с инициализацией по умолчанию.
U
April 18, 2019, 3:37 p.m.
Unreal_man

А как иконку в хедер задать?
u
April 18, 2019, 2:15 a.m.
uaa

доброго времени,большое спасибо за пример для начинающего)при адаптации к своему проекту столкнулся с таким ньансом:в vepolyline.h в 47 строке нужна инициализация по умолчанию: int m_pointF...
E
April 11, 2019, 12:49 p.m.
Evgeny

Спасибо за ответ) У меня компоновщик на нее ругался просто. Оказалось, просто забыл Q_OBJECT в начале класса указать.
Now discuss on the forum
April 24, 2019, 11:22 a.m.
Ruslan Polupan

Согласен. но ситуация не поменялась. Такое чуство что данные не записываются в модель.
April 24, 2019, 6:20 a.m.
Ruslan Polupan

я так понимаю надо инфорация об устройствах.Я бы пробовал так rust@suse:~> lsblk -PNAME="sda" MAJ:MIN="8:0" RM="0" SIZE="111,8G" RO="0" TYPE="disk" MOUNTPOINT=""NAME="sda1" MAJ:MIN="8...
April 21, 2019, 4:16 p.m.
Евгений Легоцкой

Приветствую Нужно сохранять где-то выбранное значение, а потом восстанавливать его. Или использовать QSettings или добавить метод open(), в который передавать начальные значения для того...
R
April 19, 2019, 9:55 a.m.
RED_Spider

мені важко це зараз навіть перевірити, тому що знайшов коміт, це ще було в 2016 році, і цей код не буде працювати коректно зараз, єдине скажу що це були QThread
Join us in social networks

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