/*! \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 . */ #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 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 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 PacketExtractorFooterFunc; //! \ingroup IO-Utils //! \~\brief //! \~english Extracts packets from data produced by a child %PIIODevice. //! \~russian Выделяет пакеты из данных, поступающих от дочернего %PIIODevice. //! //! \~\details //! \~english //! The extractor forwards read and write operations to the assigned child //! device and applies one of several packet-splitting strategies to incoming //! bytes before emitting \a packetReceived(). //! \~russian //! Извлекатель перенаправляет операции чтения и записи назначенному дочернему //! устройству и применяет одну из стратегий разбиения к входящему потоку байтов //! перед генерацией \a packetReceived(). 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 = f; } //! \~english Sets custom payload validation callback. //! \~russian Устанавливает пользовательский callback проверки полезной нагрузки. void setPayloadCheckSlot(PacketExtractorPayloadFunc f) { func_payload = f; } //! \~english Sets custom footer validation callback. //! \~russian Устанавливает пользовательский callback проверки окончания пакета. void setFooterCheckSlot(PacketExtractorFooterFunc f) { func_footer = 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()); } EVENT2(packetReceived, const uchar *, data, int, size); //! \events //! \{ //! \fn void packetReceived(const uchar * data, int size) //! \~english Emitted when the current input chunk passes the configured extraction rules. //! \~russian Генерируется, когда текущие входные данные проходят настроенные правила выделения. //! \} 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