Files
pip/libs/main/io_utils/pipacketextractor.h
2026-03-20 16:31:30 +03:00

236 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\file pipacketextractor.h
//! \~\ingroup IO-Utils
//! \~\brief
//! \~english Packet extraction helper for byte-stream devices
//! \~russian Вспомогательный класс выделения пакетов для потоковых устройств
/*
PIP - Platform Independent Primitives
Packets extractor
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIPACKETEXTRACTOR_H
#define PIPACKETEXTRACTOR_H
#include "piiodevice.h"
//! \~english Callback for header validation and payload size detection. Receives source header, received header and header size. Returns
//! payload size or -1 when the header does not match.
//! \~russian Callback для проверки заголовка и определения размера полезной нагрузки. Принимает ожидаемый заголовок, полученный заголовок и
//! размер заголовка. Возвращает размер полезной нагрузки или -1, если заголовок не совпал.
typedef std::function<int(const uchar *, const uchar *, int)> PacketExtractorHeaderFunc;
//! \~english Callback for payload validation. Receives payload pointer and payload size. Returns \b true when the payload should be
//! accepted.
//! \~russian Callback для проверки полезной нагрузки. Принимает указатель на полезную нагрузку и ее размер. Возвращает \b true, если
//! нагрузка должна быть принята.
typedef std::function<bool(const uchar *, int)> PacketExtractorPayloadFunc;
//! \~english Callback for footer validation. Receives source footer, received footer and footer size. Returns \b true when the footer
//! matches.
//! \~russian Callback для проверки конца пакета. Принимает ожидаемое окончание пакета, полученное окончание и размер окончания. Возвращает
//! \b true, если окончание совпало.
typedef std::function<bool(const uchar *, const uchar *, int)> PacketExtractorFooterFunc;
//! \~\ingroup IO-Utils
//! \~\brief
//! \~english Extracts packets from data produced by a child %PIIODevice.
//! \~russian Выделяет пакеты из данных, поступающих от дочернего %PIIODevice.
//! \details
//! \~english The PIPacketExtractor class provides packet recognition from data stream using various algorithms.
//! \~russian Класс PIPacketExtractor предоставляет распознавание пакетов из потока данных с использованием различных алгоритмов.
class PIP_EXPORT PIPacketExtractor: public PIIODevice {
PIIODEVICE(PIPacketExtractor, "pckext");
friend class PIConnection;
public:
//! \~english Packet splitting modes.
//! \~russian Режимы выделения пакетов.
enum SplitMode {
None /** \~english Accept every read chunk as a packet \~russian Считать каждый прочитанный блок отдельным пакетом */,
Header /** \~english Search for \a header() and use configured payload size or callback result \~russian Искать \a header() и
использовать настроенный размер полезной нагрузки или результат callback */
,
Footer /** \~english Use fixed payload size and validate trailing \a footer() \~russian Использовать фиксированный размер полезной
нагрузки и проверять завершающий \a footer() */
,
HeaderAndFooter /** \~english Search for packets bounded by \a header() and \a footer() \~russian Искать пакеты, ограниченные \a
header() и \a footer() */
,
Size /** \~english Treat \a payloadSize() as full packet size \~russian Использовать \a payloadSize() как полный размер пакета */,
Timeout /** \~english Collect bytes until \a timeout() expires after the first read \~russian Накопить байты до истечения \a
timeout() после первого чтения */
};
//! \~english Constructs extractor bound to "device_" and configured with split mode "mode".
//! \~russian Создает извлекатель, привязанный к "device_", и настраивает режим выделения "mode".
explicit PIPacketExtractor(PIIODevice * device_ = nullptr, SplitMode mode = None);
//! \~english Stops extractor background activity and destroys the object.
//! \~russian Останавливает фоновую работу извлекателя и уничтожает объект.
virtual ~PIPacketExtractor() { stop(); }
//! \~english Returns the current child device.
//! \~russian Возвращает текущее дочернее устройство.
PIIODevice * device() { return dev; }
//! \~english Replaces the child device with "device_".
//! \~russian Заменяет дочернее устройство на "device_".
void setDevice(PIIODevice * device_);
//! \~english Returns unread bytes currently available from the child device.
//! \~russian Возвращает число непрочитанных байтов, доступных в дочернем устройстве.
ssize_t bytesAvailable() const override;
//! \~english Sets custom header validation callback.
//! \~russian Устанавливает пользовательский callback проверки заголовка.
void setHeaderCheckSlot(PacketExtractorHeaderFunc f) { func_header = std::move(f); }
//! \~english Sets custom payload validation callback.
//! \~russian Устанавливает пользовательский callback проверки полезной нагрузки.
void setPayloadCheckSlot(PacketExtractorPayloadFunc f) { func_payload = std::move(f); }
//! \~english Sets custom footer validation callback.
//! \~russian Устанавливает пользовательский callback проверки окончания пакета.
void setFooterCheckSlot(PacketExtractorFooterFunc f) { func_footer = std::move(f); }
//! \~english Switches packet extraction to mode "mode".
//! \~russian Переключает выделение пакетов в режим "mode".
void setSplitMode(SplitMode mode) { setProperty("splitMode", int(mode)); }
//! \~english Sets fixed payload size used by the size-based extraction modes.
//! \~russian Устанавливает фиксированный размер полезной нагрузки для режимов с известным размером.
void setPayloadSize(int size);
//! \~english Sets reference header bytes.
//! \~russian Устанавливает эталонные байты заголовка.
void setHeader(const PIByteArray & data);
//! \~english Sets reference footer bytes.
//! \~russian Устанавливает эталонные байты окончания пакета.
void setFooter(const PIByteArray & data);
//! \~english Sets accumulation timeout for \a Timeout mode.
//! \~russian Устанавливает тайм-аут накопления для режима \a Timeout.
void setTimeout(PISystemTime tm) { setProperty("timeout", tm); }
//! \~english Returns current packet splitting mode.
//! \~russian Возвращает текущий режим выделения пакетов.
SplitMode splitMode() const { return mode_; }
//! \~english Returns configured payload size.
//! \~russian Возвращает настроенный размер полезной нагрузки.
int payloadSize() const { return dataSize; }
//! \~english Returns configured reference header.
//! \~russian Возвращает настроенный эталонный заголовок.
PIByteArray header() const { return src_header; }
//! \~english Returns configured reference footer.
//! \~russian Возвращает настроенное эталонное окончание пакета.
PIByteArray footer() const { return src_footer; }
//! \~english Returns timeout used by \a Timeout mode.
//! \~russian Возвращает тайм-аут, используемый режимом \a Timeout.
PISystemTime timeout() const { return time_; }
//! \~english Returns number of bytes skipped during resynchronization.
//! \~russian Возвращает число байтов, пропущенных при ресинхронизации.
ullong missedBytes() const { return missed; }
//! \~english Feeds raw bytes into the extractor.
//! \~russian Передает сырые байты в извлекатель.
//! \~english Emits \a packetReceived() when a complete packet is recognized.
//! \~russian Генерирует \a packetReceived(), когда распознан полный пакет.
void appendData(const uchar * d, int s) { threadedRead(d, s); }
//! \~english Feeds byte-array data into the extractor.
//! \~russian Передает массив байтов в извлекатель.
//! \~english Emits \a packetReceived() when a complete packet is recognized.
//! \~russian Генерирует \a packetReceived(), когда распознан полный пакет.
void appendData(const PIByteArray & data) { threadedRead(data.data(), data.size_s()); }
//! \events
//! \{
//! \fn void packetReceived(const uchar * data, int size)
//! \~english Emitted when the current input chunk passes the configured extraction rules.
//! \~russian Генерируется, когда текущие входные данные проходят настроенные правила выделения.
EVENT2(packetReceived, const uchar *, data, int, size);
//! \}
protected:
//! \~english Validates packet header and optionally returns payload size.
//! \~russian Проверяет заголовок пакета и при необходимости возвращает размер полезной нагрузки.
//! \~\details
//! \~english
//! The default implementation compares "src" and "rec" byte by byte and
//! returns the configured \a payloadSize() on success.
//! \~russian
//! Реализация по умолчанию побайтно сравнивает "src" и "rec" и при успехе
//! возвращает настроенный \a payloadSize().
virtual int validateHeader(const uchar * src, const uchar * rec, int size);
//! \~english Validates packet footer.
//! \~russian Проверяет окончание пакета.
//! \~english The default implementation compares "src" and "rec" byte by byte.
//! \~russian Реализация по умолчанию побайтно сравнивает "src" и "rec".
virtual bool validateFooter(const uchar * src, const uchar * rec, int size);
//! \~english Validates packet payload.
//! \~russian Проверяет полезную нагрузку пакета.
//! \~english The default implementation accepts any payload.
//! \~russian Реализация по умолчанию принимает любую полезную нагрузку.
virtual bool validatePayload(const uchar * rec, int size);
private:
void construct();
void propertyChanged(const char *) override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t max_size) override;
bool threadedRead(const uchar * readed, ssize_t size) override;
PIString constructFullPathDevice() const override;
bool openDevice() override;
bool closeDevice() override;
DeviceInfoFlags deviceInfoFlags() const override;
PIIODevice * dev;
PIByteArray src_header, src_footer, tmpbuf;
PacketExtractorHeaderFunc func_header;
PacketExtractorPayloadFunc func_payload;
PacketExtractorFooterFunc func_footer;
SplitMode mode_;
int dataSize, packetSize_pending, footerInd;
PISystemTime time_;
bool header_found;
ullong missed;
};
#endif // PIPACKETEXTRACTOR_H