diff --git a/DatasetIOPlugin/Kitti/data/vtkLidarKITTIDataSetReader.h b/DatasetIOPlugin/Kitti/data/vtkLidarKITTIDataSetReader.h index 2cea4e1bf305b3114ef344df8df8cc9fc7af342b..165ca36d5ebf4f0469c96edf0b2a0f308405db18 100644 --- a/DatasetIOPlugin/Kitti/data/vtkLidarKITTIDataSetReader.h +++ b/DatasetIOPlugin/Kitti/data/vtkLidarKITTIDataSetReader.h @@ -37,7 +37,7 @@ public: void SetCalibrationFileName(const std::string& vtkNotUsed(filename)) override {notImpementedBody} //! Not implemented - void Open() override {notImpementedBody} + void Open(bool vtkNotUsed(reassemble)) override {notImpementedBody} //! Not implemented void Close() override {notImpementedBody} diff --git a/LidarPlugin/Common/Network/vtkPacketFileReader.cxx b/LidarPlugin/Common/Network/vtkPacketFileReader.cxx index 869c5800601ee15145c70b10a475297a30d13ddf..d42611a04c2ffb071d20fd70fd9085005dd95954 100644 --- a/LidarPlugin/Common/Network/vtkPacketFileReader.cxx +++ b/LidarPlugin/Common/Network/vtkPacketFileReader.cxx @@ -1,6 +1,8 @@ #include "vtkPacketFileReader.h" -//------------------------------------------------------------------------------ +#include <iostream> +#include <boost/endian/arithmetic.hpp> + bool IPHeaderFunctions::getFragmentInfo(unsigned char const * data, FragmentInfo & fragmentInfo) { fragmentInfo.Reset(); @@ -130,6 +132,243 @@ unsigned int IPHeaderFunctions::getIPHeaderLength(unsigned char const* data) } return (header - data); } + std::cerr << "IP header not recognised" << std::endl; return 0; } +//------------------------------------------------------------------------------ +bool IPHeaderFunctions::buildReassembledIPHeader(unsigned char* ipheader, const unsigned int ipHeaderLength, const unsigned int payloadSize) +{ + unsigned char const ipVersion = ipheader[0] >> 4; + if (ipVersion == 0x4) + { + //Set Total Length + boost::endian::big_uint16_t total_length = ipHeaderLength + payloadSize ; + std::copy( + total_length.data(), + total_length.data() + 2, + ipheader + 2 + ); + //Reset fragment flag + ipheader[6] =0x40; + ipheader[7] =0x00; + return true; + } + if (ipVersion == 0x6) + { + // WIP Removing Fragment Extension Header is a tedious process. + // WIP This feature is not needed at the time, if ever needed + // WIP will likely be superseded by a more robust solution like Pcap++. + std::cerr << "IPv6 Reassembly not supported" << std::endl; + return false; + } + + std::cerr << "IP header not recognised" << std::endl; + return false; +} + +//------------------------------------------------------------------------------ +bool vtkPacketFileReader::Open(const std::string& filename, std::string filter_arg, bool reassemble) +{ + //Open savefile in tcpdump/libcap format + char errbuff[PCAP_ERRBUF_SIZE]; + pcap_t* pcapFile = pcap_open_offline(filename.c_str(), errbuff); + if (!pcapFile) + { + this->LastError = errbuff; + return false; + } + + //Compute filter for the kernel-level filtering engine + bpf_program filter; + if (pcap_compile(pcapFile, &filter, filter_arg.c_str(), 0, PCAP_NETMASK_UNKNOWN) == -1) + { + this->LastError = pcap_geterr(pcapFile); + return false; + } + //Associate filter to pcap + if (pcap_setfilter(pcapFile, &filter) == -1) + { + this->LastError = pcap_geterr(pcapFile); + return false; + } + + //Determine Datalink header size + const unsigned int loopback_header_size = 4; + const unsigned int ethernet_header_size = 14; + auto linktype = pcap_datalink(pcapFile); + switch (linktype) + { + case DLT_EN10MB: + this->FrameHeaderLength = ethernet_header_size; + break; + case DLT_NULL: + this->FrameHeaderLength = loopback_header_size; + break; + default: + this->LastError = "Unknown link type in pcap file. Cannot tell where the payload is."; + return false; + } + + this->FileName = filename; + this->PCAPFile = pcapFile; + this->StartTime.tv_sec = this->StartTime.tv_usec = 0; + this->Reassemble = reassemble; + return true; +} + +void vtkPacketFileReader::Close() +{ + if (this->PCAPFile) + { + pcap_close(this->PCAPFile); + this->PCAPFile = 0; + this->FileName.clear(); + } +} +void vtkPacketFileReader::GetFilePosition(fpos_t* position) +{ +#ifdef _MSC_VER + pcap_fgetpos(this->PCAPFile, position); +#else + FILE* f = pcap_file(this->PCAPFile); + fgetpos(f, position); +#endif +} + +void vtkPacketFileReader::SetFilePosition(fpos_t* position) +{ +#ifdef _MSC_VER + pcap_fsetpos(this->PCAPFile, position); +#else + FILE* f = pcap_file(this->PCAPFile); + fsetpos(f, position); +#endif +} + +bool vtkPacketFileReader::NextPacket(const unsigned char*& data, unsigned int& dataLength, double& timeSinceStart, + pcap_pkthdr** headerReference, unsigned int* dataHeaderLength ) +{ + if (!this->PCAPFile) + { + return false; + } + + //Clear Previous Reassembly Data if needed + if (this->RemoveAssembled) + { + auto it = this->Fragments.find(this->AssembledId); + this->Fragments.erase(it); + this->AssembledId = 0; + this->RemoveAssembled = false; + } + + dataLength = 0; + pcap_pkthdr* header; + FragmentInfo fragmentInfo; + fragmentInfo.MoreFragments = true; + + while (fragmentInfo.MoreFragments) + { + unsigned char const * tmpData = nullptr; + int returnValue = pcap_next_ex(this->PCAPFile, &header, &tmpData); + if (returnValue < 0) + { + this->Close(); + return false; + } + + // Collect header values before they are removed. + IPHeaderFunctions::getFragmentInfo(tmpData + this->FrameHeaderLength, fragmentInfo); + timeSinceStart = GetElapsedTime(header->ts, this->StartTime); + + //Consts + const unsigned int ipHeaderLength = IPHeaderFunctions::getIPHeaderLength(tmpData + this->FrameHeaderLength); + if (ipHeaderLength == 0) + { + continue; + } + const unsigned int ethHeaderLength = this->FrameHeaderLength; + const unsigned int udpHeaderLength = 8; + + //CaptureLen cropping + const unsigned int frameLength = (std::min)(header->len,header->caplen); //windows.h conflict bypass + const unsigned int ipPayloadLength = frameLength - (ethHeaderLength + ipHeaderLength); + + unsigned char const * ipPayloadPtr = tmpData + ethHeaderLength + ipHeaderLength; + + //Provide Header Info if requested + if (headerReference != NULL && dataHeaderLength != NULL) + { + *headerReference = header; + *dataHeaderLength = ethHeaderLength + ipHeaderLength + udpHeaderLength; + } + + //IP Reassembly + if ( (fragmentInfo.MoreFragments || fragmentInfo.Offset > 0) && this->Reassemble ) + { + const unsigned int offset_frag = fragmentInfo.Offset * FRAGMENT_OFFSET_STEP; + const unsigned int offset = ethHeaderLength + ipHeaderLength + offset_frag; + const unsigned int requiredSize = offset + ipPayloadLength; + + auto & fragmentTracker = this->Fragments[fragmentInfo.Identification]; + auto & reassembledData = fragmentTracker.Data; + if (requiredSize > reassembledData.size()) + { + reassembledData.resize(requiredSize); + } + std::copy(ipPayloadPtr, ipPayloadPtr + ipPayloadLength, reassembledData.begin() + offset); + + // Update current collected payload size. + fragmentTracker.CurrentSize += ipPayloadLength; + + // There may be gaps of size FRAGMENT_OFFSET_STEP between fragments. + // Add this to the current size, assumes that <number of fragments - 1> * + // Any given fragment is always larger than FRAGMENT_OFFSET_STEP, + // so that it cannot be omitted accidentally. + if (fragmentInfo.MoreFragments) + { + // WIP I doubt this increment has any use, gap mentioned above is included within offset_frag + // WIP commenting this line and replacing >= with == has no effects + fragmentTracker.CurrentSize += FRAGMENT_OFFSET_STEP; + }else{ + // Set the expected size if this is the final fragment. + fragmentTracker.ExpectedSize = offset_frag + ipPayloadLength; + } + + // Return Reassembled Packet if complete. + if (fragmentTracker.ExpectedSize > 0 && fragmentTracker.CurrentSize >= fragmentTracker.ExpectedSize) + { + //Build Reassembled Packet Header off the last one received + std::copy( + tmpData, + ipPayloadPtr, + reassembledData.begin() + ); + //Frame Header + header->len = ethHeaderLength + ipHeaderLength + fragmentTracker.ExpectedSize ; + header->caplen = header->len; + //IP Header + IPHeaderFunctions::buildReassembledIPHeader(reassembledData.data() + ethHeaderLength, ipHeaderLength, fragmentTracker.ExpectedSize); + + // Delete the associated data on the next iteration. + this->AssembledId = fragmentInfo.Identification; + this->RemoveAssembled = true; + + //Point to dataPayload + data = reassembledData.data() + ethHeaderLength + ipHeaderLength + udpHeaderLength; + dataLength = fragmentTracker.ExpectedSize - udpHeaderLength; + return true; + } + } + //Self Standing IP packet or Reassembly is not desired + else + { + //Point to dataPayload + data = ipPayloadPtr + udpHeaderLength; + dataLength = ipPayloadLength - udpHeaderLength; + return true; + } + } + return true; +} diff --git a/LidarPlugin/Common/Network/vtkPacketFileReader.h b/LidarPlugin/Common/Network/vtkPacketFileReader.h index f7a15f91214baaa20bf3aa485de8a32a2afc199f..2d2f25695418e1d5552ae9bddf4fc6d4db71bb18 100644 --- a/LidarPlugin/Common/Network/vtkPacketFileReader.h +++ b/LidarPlugin/Common/Network/vtkPacketFileReader.h @@ -32,14 +32,18 @@ #ifndef __vtkPacketFileReader_h #define __vtkPacketFileReader_h +#include "lidarplugin_export.h" +//Compliance with vtk's fpos_t policy, needs to be included before any libc header +#include <vtkSystemIncludes.h> +#include "LVTime.h" + #include <pcap.h> #include <string> #include <cstdlib> #include <cstring> #include <vector> #include <unordered_map> -#include "lidarplugin_export.h" -#include "LVTime.h" + /* * Useful links to get started with IPv4 and IPv6 headers: * - https://en.wikipedia.org/wiki/IPv4#Packet_structure @@ -56,7 +60,7 @@ typedef uint32_t FragmentIdentificationT; //------------------------------------------------------------------------------ -// Packet fragment offsets are given in steps of 8 bytes. +// Packet fragment offsets are measured in blocks/steps of 8 bytes. constexpr unsigned int FRAGMENT_OFFSET_STEP = 8; //------------------------------------------------------------------------------ @@ -92,7 +96,6 @@ struct FragmentInfo } }; - namespace IPHeaderFunctions { //---------------------------------------------------------------------------- @@ -102,7 +105,7 @@ namespace IPHeaderFunctions * @param[out] fragmentInfo The collected fragment info. * @return True if the information could be retrieved, false otherwise. */ - LIDARPLUGIN_EXPORT bool LIDARPLUGIN_EXPORT getFragmentInfo(unsigned char const * data, FragmentInfo & fragmentInfo); + LIDARPLUGIN_EXPORT bool getFragmentInfo(unsigned char const * data, FragmentInfo & fragmentInfo); //---------------------------------------------------------------------------- /*! @@ -111,13 +114,13 @@ namespace IPHeaderFunctions * @return The number of bytes in the IP header, or 0 if this could not be * determined. */ - LIDARPLUGIN_EXPORT unsigned int LIDARPLUGIN_EXPORT getIPHeaderLength(unsigned char const* data); + LIDARPLUGIN_EXPORT unsigned int getIPHeaderLength(unsigned char const* data); + + bool buildReassembledIPHeader(unsigned char* iphdrdata, const unsigned int ipHeaderLength, const unsigned int payloadSize); } - - //------------------------------------------------------------------------------ -class vtkPacketFileReader +class LIDARPLUGIN_EXPORT vtkPacketFileReader { public: vtkPacketFileReader() @@ -129,212 +132,38 @@ public: { this->Close(); } - - // This function is called to read a savefile .pcap - // 1-Open a savefile in the tcpdump/libcap format to read packet - // 2-A packet filter is then compile to convert an high level filtering - // expression in a program that can be interpreted by the kernel-level filtering engine - // 3- The compiled filter is then associate to the capture - bool Open(const std::string& filename, std::string filter_arg="udp") - { - char errbuff[PCAP_ERRBUF_SIZE]; - pcap_t* pcapFile = pcap_open_offline(filename.c_str(), errbuff); - if (!pcapFile) - { - this->LastError = errbuff; - return false; - } - - bpf_program filter; - - if (pcap_compile(pcapFile, &filter, filter_arg.c_str(), 0, PCAP_NETMASK_UNKNOWN) == -1) - { - this->LastError = pcap_geterr(pcapFile); - return false; - } - - if (pcap_setfilter(pcapFile, &filter) == -1) - { - this->LastError = pcap_geterr(pcapFile); - return false; - } - - const unsigned int loopback_header_size = 4; - const unsigned int ethernet_header_size = 14; - auto linktype = pcap_datalink(pcapFile); - switch (linktype) - { - case DLT_EN10MB: - this->FrameHeaderLength = ethernet_header_size; - break; - case DLT_NULL: - this->FrameHeaderLength = loopback_header_size; - break; - default: - this->LastError = "Unknown link type in pcap file. Cannot tell where the payload is."; - return false; - } - - this->FileName = filename; - this->PCAPFile = pcapFile; - this->StartTime.tv_sec = this->StartTime.tv_usec = 0; - return true; - } + + /** + * @brief Open Pcap capture + * @param[in] filename pcap file name. + * @param[in] filter_arg kernel-level packet filter parameter. + * @param[in] reassemble if disabled, data will be unusable as is. + * This is solely used when saving a Pcap to file and original fragmentation is sought. + * Returns true is successful. + */ + bool Open(const std::string& filename, std::string filter_arg="udp", bool reassemble = true); bool IsOpen() { return (this->PCAPFile != 0); } - - void Close() - { - if (this->PCAPFile) - { - pcap_close(this->PCAPFile); - this->PCAPFile = 0; - this->FileName.clear(); - } - } + void Close(); const std::string& GetLastError() { return this->LastError; } - const std::string& GetFileName() { return this->FileName; } - void GetFilePosition(fpos_t* position) - { -#ifdef _MSC_VER - pcap_fgetpos(this->PCAPFile, position); -#else - FILE* f = pcap_file(this->PCAPFile); - fgetpos(f, position); -#endif - } - - void SetFilePosition(fpos_t* position) -{ -#ifdef _MSC_VER - pcap_fsetpos(this->PCAPFile, position); -#else - FILE* f = pcap_file(this->PCAPFile); - fsetpos(f, position); -#endif - } - + void GetFilePosition(fpos_t* position); + void SetFilePosition(fpos_t* position); + + /** + * @brief Read next UDP payload of the capture. + * @param[in] data A pointer to the first byte of UDP Payload. + * @param[in] dataLength Size in bytes of the UDP Payload. + * @param[out] timeSinceStart Network timestamp relative to the capture start time. + * @param[out] headerReference A pointer to pointer to the Frame header (Optional). + * @param[out] dataHeaderLength A pointer to the size of the Frame header (Optional). + * Returns 'data' pointer to payload data of size 'dataLength' + * Full Frame of size 'headerReference' is available, + * header data is located at 'data - dataHeaderLength' + */ bool NextPacket(const unsigned char*& data, unsigned int& dataLength, double& timeSinceStart, - pcap_pkthdr** headerReference = NULL, unsigned int* dataHeaderLength = NULL) - { - if (!this->PCAPFile) - { - return false; - } - - // Delete reassembled fragment data from the previous call, if any. This - // cannot be done earlier because it would invalidate the data before it is - // returned. - if (this->RemoveAssembled) - { - auto it = this->Fragments.find(this->AssembledId); - this->Fragments.erase(it); - this->AssembledId = 0; - this->RemoveAssembled = false; - } - - dataLength = 0; - pcap_pkthdr* header; - FragmentInfo fragmentInfo; - fragmentInfo.MoreFragments = true; - - while (fragmentInfo.MoreFragments) - { - unsigned char const * tmpData = nullptr; - unsigned int tmpDataLength; - - int returnValue = pcap_next_ex(this->PCAPFile, &header, &tmpData); - if (returnValue < 0) - { - this->Close(); - return false; - } - - // Collect header values before they are removed. - IPHeaderFunctions::getFragmentInfo(tmpData + this->FrameHeaderLength, fragmentInfo); - - // Only return the payload. - // We read the actual IP header length (v4 & v6) + assume UDP - const unsigned int ipHeaderLength = IPHeaderFunctions::getIPHeaderLength(tmpData + this->FrameHeaderLength); - if (ipHeaderLength == 0) - { - continue; - } - const unsigned int udpHeaderLength = 8; - const unsigned int bytesToSkip = this->FrameHeaderLength + ipHeaderLength + udpHeaderLength; - - tmpDataLength = header->len - bytesToSkip; - if (header->len > header->caplen) - tmpDataLength = header->caplen - bytesToSkip; - tmpData = tmpData + bytesToSkip; - timeSinceStart = GetElapsedTime(header->ts, this->StartTime); - - if (headerReference != NULL && dataHeaderLength != NULL) - { - *headerReference = header; - *dataHeaderLength = bytesToSkip; - } - - // pcap_next_ex may reallocate the buffers it returns so the data must be - // copied between each call. - if (dataLength > 0 || fragmentInfo.MoreFragments || fragmentInfo.Offset > 0) - { - decltype(tmpDataLength) offset = fragmentInfo.Offset * FRAGMENT_OFFSET_STEP; - decltype(tmpDataLength) requiredSize = offset + tmpDataLength; - - auto & fragmentTracker = this->Fragments[fragmentInfo.Identification]; - auto & reassembledData = fragmentTracker.Data; - - if (requiredSize > reassembledData.size()) - { - reassembledData.resize(requiredSize); - } - std::copy(tmpData, tmpData + tmpDataLength, reassembledData.begin() + offset); - - // Update current size, which represents the total number of bytes - // collected in the reassembled packet. - fragmentTracker.CurrentSize += tmpDataLength; - - // There may be gaps of size FRAGMENT_OFFSET_STEP between fragments. Add - // this to the current size. - // - // Note that this assumes that <number of fragments - 1> * - // FRAGMENT_OFFSET_STEP is never larger than any given fragment so that - // it will not be omitted accidentally. - if (fragmentInfo.MoreFragments) - { - fragmentTracker.CurrentSize += FRAGMENT_OFFSET_STEP; - } - // Set the expected size if this is the final fragment. - else - { - fragmentTracker.ExpectedSize = requiredSize; - } - - - // Return the packet if it's complete. - if (fragmentTracker.ExpectedSize > 0 && fragmentTracker.CurrentSize >= fragmentTracker.ExpectedSize) - { - data = reassembledData.data(); - dataLength = reassembledData.size(); - // Delete the associated data on the next iteration. - this->AssembledId = fragmentInfo.Identification; - this->RemoveAssembled = true; - return true; - } - } - else - { - data = tmpData; - dataLength = tmpDataLength; - return true; - } - } - - return true; - } + pcap_pkthdr** headerReference = NULL, unsigned int* dataHeaderLength = NULL); protected: pcap_t* PCAPFile; @@ -342,7 +171,7 @@ protected: std::string LastError; timeval StartTime; unsigned int FrameHeaderLength; - + bool Reassemble; private: //! @brief A map of fragmented packet IDs to the collected array of fragments. diff --git a/LidarPlugin/Common/Network/vtkPacketFileWriter.h b/LidarPlugin/Common/Network/vtkPacketFileWriter.h index a9394b80a7cae7c88b1905bf6cef065200f2b44a..bf25bf41658dae0d4fd83737fff884e81549e4b0 100644 --- a/LidarPlugin/Common/Network/vtkPacketFileWriter.h +++ b/LidarPlugin/Common/Network/vtkPacketFileWriter.h @@ -32,13 +32,13 @@ #ifndef __vtkPacketFileWriter_h #define __vtkPacketFileWriter_h +#include "lidarplugin_export.h" +#include "NetworkPacket.h" + #include <pcap.h> #include <string> #include <vector> -#include "lidarplugin_export.h" -#include "NetworkPacket.h" - class LIDARPLUGIN_EXPORT vtkPacketFileWriter { public: diff --git a/LidarPlugin/Common/Network/vvPacketSender.cxx b/LidarPlugin/Common/Network/vvPacketSender.cxx index d4a8b6efe944e7d96c8110a0f44f9acc0a936dcc..cf03c618fc924280db1a0985d7f3fbf74fda3e46 100644 --- a/LidarPlugin/Common/Network/vvPacketSender.cxx +++ b/LidarPlugin/Common/Network/vvPacketSender.cxx @@ -13,6 +13,7 @@ // limitations under the License. #include "vvPacketSender.h" +#include "vtkPacketFileReader.h" #include <chrono> #include <thread> diff --git a/LidarPlugin/Common/Network/vvPacketSender.h b/LidarPlugin/Common/Network/vvPacketSender.h index 841ab68e936ff04fa177fe4cf07f51b3cb96b822..bb03d88060f9fbe855cd0141f384006921590f6b 100644 --- a/LidarPlugin/Common/Network/vvPacketSender.h +++ b/LidarPlugin/Common/Network/vvPacketSender.h @@ -13,9 +13,8 @@ // limitations under the License. #include <string> -#include <vtkSystemIncludes.h> -#include "vtkPacketFileReader.h" +#include "lidarplugin_export.h" #include <boost/asio.hpp> #include <boost/thread/thread.hpp> @@ -30,7 +29,7 @@ class vtkPacketFileReader; * To send a pcap file multiples times, a new vvPacketSender should be created each time. */ -class VTK_EXPORT vvPacketSender +class LIDARPLUGIN_EXPORT vvPacketSender { public: vvPacketSender(std::string pcapfile, std::string destinationio = "127.0.0.1", diff --git a/LidarPlugin/IO/Lidar/Common/vtkLidarReader.cxx b/LidarPlugin/IO/Lidar/Common/vtkLidarReader.cxx index 9b86b3b353f1acd8a65d351a7fc001081ed4b02c..6b8dd6eb7d454cad080e4c6ea60c963164886d7b 100644 --- a/LidarPlugin/IO/Lidar/Common/vtkLidarReader.cxx +++ b/LidarPlugin/IO/Lidar/Common/vtkLidarReader.cxx @@ -285,7 +285,7 @@ int vtkLidarReader::GetFrameIndexForDataTime(double dataTime) } //----------------------------------------------------------------------------- -void vtkLidarReader::Open() +void vtkLidarReader::Open(bool reassemble) { this->Close(); this->Reader = new vtkPacketFileReader; @@ -295,7 +295,7 @@ void vtkLidarReader::Open() { filterPCAP += " port " + std::to_string(this->LidarPort); } - if (!this->Reader->Open(this->FileName, filterPCAP.c_str())) + if (!this->Reader->Open(this->FileName, filterPCAP.c_str(), reassemble)) { vtkErrorMacro(<< "Failed to open packet file: " << this->FileName << "!\n" << this->Reader->GetLastError()) diff --git a/LidarPlugin/IO/Lidar/Common/vtkLidarReader.h b/LidarPlugin/IO/Lidar/Common/vtkLidarReader.h index c545b54708477dea390de9230ed47417fe228732..3abcc563d529ef047855911382f4b4fb39a3a9ba 100644 --- a/LidarPlugin/IO/Lidar/Common/vtkLidarReader.h +++ b/LidarPlugin/IO/Lidar/Common/vtkLidarReader.h @@ -107,8 +107,9 @@ public: * @brief Open open the pcap file * @todo a decition should be made if the opening/closing of the pcap should be handle by * the class itself of the class user. Currently this is not clear + * @param reassemble Controls vtkPacketFileReader IP Reassembly */ - virtual void Open(); + virtual void Open(bool reassemble = true); /** * @brief Close close the pcap file diff --git a/LidarPlugin/StandAloneTools/PCAPSeparator.cxx b/LidarPlugin/StandAloneTools/PCAPSeparator.cxx index 0bdef64b3e873cd59c26f20b6981a94f8f632b01..2a5f06edab1f1bcaa37db2007aa348c16d981768 100644 --- a/LidarPlugin/StandAloneTools/PCAPSeparator.cxx +++ b/LidarPlugin/StandAloneTools/PCAPSeparator.cxx @@ -27,7 +27,6 @@ #include <vtkSmartPointer.h> -#include "lidarplugin_export.h" #include "vtkPacketFileReader.h" #include "vtkPacketFileWriter.h" #include "NetworkPacket.h"