/* PIP - Platform Independent Primitives Packets extractor Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pipacketextractor.h" /** \class PIPacketExtractor * \brief Packets extractor * \details * \section PIPacketExtractor_sec0 Synopsis * This class implements packet recognition by header and custom validating * algorithm from data stream. Stream is formed from child %PIIODevice * passed from contructor or with function \a setDevice(). * * \section PIPacketExtractor_sec1 Principle of work * %PIPacketExtractor works with child %PIIODevice. \a read and \a write * functions directly call child device functions. You should start threaded * read of \b extractor to proper work. Extractor read data from child device, * form continuous buffer and analyze it. * * \subsection PIPacketExtractor_sec1_0 Analysis * There is three parameters: * * header content * * header size * * payload size * * Extractor can detect packet with compare your header with readed data. * It is default implementation of function \a packetHeaderValidate(). * If header validating passed, function \a packetValidate() will be called. * If either of this function return \b false extractor shifts by one byte * and takes next header. If both functions returns \b true extractor shifts * by whole packet size. * \image html packet_detection.png * * \subsection PIPacketExtractor_sec1_1 Variants * If header size = 0 and payload size = 0 there is no analysis will be done, * and function \a packetValidate() anyway will be called immediately after * successfully read from child device. \n * If header size = 0 but payload size != 0 extractor will be call function * \a packetValidate() each payload size bytes. * * */ PIPacketExtractor::PIPacketExtractor(PIIODevice * device_, void * recHeaderPtr, int recHeaderSize, int recDataSize) { ret_func_header = 0; setPacketData(recHeaderPtr, recHeaderSize, recDataSize); setThreadedReadBufferSize(65536); setBufferSize(65536); setDevice(device_); allReaded = addSize = curInd = missed = 0; } void PIPacketExtractor::setDevice(PIIODevice * device_) { dev = device_; if (dev == 0) return; } bool PIPacketExtractor::threadedRead(uchar * readed, int size_) { memcpy(buffer.data(allReaded), readed, size_); allReaded += size_; while (allReaded >= packetSize + addSize && allReaded > 0) { if (headerSize > 0) { if (allReaded + curInd >= buffer_size) { memcpy(sbuffer.data(), buffer.data(), buffer_size); memcpy(buffer.data(), sbuffer.data(buffer_size - packetSize), allReaded); allReaded = packetSize; addSize = curInd = 0; } bool brk = false; while (!packetHeaderValidate((uchar * )headerPtr, buffer.data(curInd), headerSize)) { curInd++; missed++; if (packetSize > 0) missed_packets = missed / packetSize; if (curInd > addSize) { addSize += packetSize; brk = true; break; } } if (brk) continue; memcpy(mheader.data(), buffer.data(curInd), headerSize); if (headerPtr != 0) memcpy(headerPtr, buffer.data(curInd), headerSize); if (!packetValidate(buffer.data(curInd + headerSize), dataSize)) { curInd++; missed++; if (packetSize > 0) missed_packets = missed / packetSize; continue; } packetReceived(buffer.data(curInd), packetSize); memcpy(sbuffer.data(), buffer.data(), allReaded); memcpy(buffer.data(), sbuffer.data(packetSize + curInd), allReaded); allReaded -= packetSize + curInd; curInd = addSize = 0; } else { if (dataSize == 0) { if (packetValidate(buffer.data(), size_)) packetReceived(buffer.data(), size_); memcpy(sbuffer.data(), buffer.data(), allReaded); memcpy(buffer.data(), sbuffer.data(size_), allReaded); allReaded -= size_; } else { if (packetValidate(buffer.data(), dataSize)) packetReceived(buffer.data(), dataSize); memcpy(sbuffer.data(), buffer.data(), allReaded); memcpy(buffer.data(), sbuffer.data(packetSize), allReaded); allReaded -= packetSize; } } } return true; }