Skip to content

Commit f2ba2a6

Browse files
authored
Fixes PcapFileWriter inconsistently writing nanosecond precision. (#1977)
* Changed PcapFileWriterDevice to throw an exception if requested with nanosecond precision, while the runtime doesn't support it. * Split the file precision tests into separate Micro and Nano test. * Added a check that the file reader should fail on a nanosecond precision file. * Reordered the precision tests so the static files are first read. The written new files are compared to the static files for binary match. * Simplified precision assert. * Added reading checks both against the written sample and the static sample. * Lint * Add static nanosecond and microsecond pcap files. * Update precision checks. * Changed cout to print verbose. * Remove include.
1 parent 948449c commit f2ba2a6

File tree

8 files changed

+97
-72
lines changed

8 files changed

+97
-72
lines changed

Pcap++/header/PcapFileDevice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ namespace pcpp
232232
/// Ethernet
233233
/// @param[in] nanosecondsPrecision A boolean indicating whether to write timestamps in nano-precision. If set
234234
/// to false, timestamps will be written in micro-precision
235+
/// @throws std::runtime_error if nanosecondsPrecision is set to `true` but the current platform and environment
236+
/// doesn't support it.
235237
PcapFileWriterDevice(const std::string& fileName, LinkLayerType linkLayerType = LINKTYPE_ETHERNET,
236238
bool nanosecondsPrecision = false);
237239

Pcap++/src/PcapFileDevice.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#define LOG_MODULE PcapLogModuleFileDevice
22

33
#include <cerrno>
4+
#include <stdexcept>
45
#include "PcapFileDevice.h"
56
#include "light_pcapng_ext.h"
67
#include "Logger.h"
@@ -273,9 +274,9 @@ namespace pcpp
273274
#else
274275
if (nanosecondsPrecision)
275276
{
276-
PCPP_LOG_ERROR(
277-
"PcapPlusPlus was compiled without nano precision support which requires libpcap > 1.5.1. Please "
278-
"recompile PcapPlusPlus with nano precision support to use this feature. Using default microsecond precision");
277+
throw std::runtime_error(
278+
"PcapPlusPlus was compiled without nano precision support which requires libpcap > 1.5.1. "
279+
"Please recompile PcapPlusPlus with nano precision support to use this feature.");
279280
}
280281
m_Precision = FileTimestampPrecision::Microseconds;
281282
#endif

Tests/Pcap++Test/Common/PcapFileNamesDef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
#define SLL2_PCAP_PATH "PcapExamples/sll2.pcap"
3131
#define SLL2_PCAP_WRITE_PATH "PcapExamples/sll2_copy.pcap"
3232
#define EXAMPLE_PCAP_MICRO_PATH "PcapExamples/microsecs.pcap"
33+
#define EXAMPLE_PCAP_MICRO_WRITE_PATH "PcapExamples/microsecs_copy.pcap"
3334
#define EXAMPLE_PCAP_DESTRUCTOR1_PATH "PcapExamples/destructor1.pcap"
3435
#define EXAMPLE_PCAP_DESTRUCTOR2_PATH "PcapExamples/destructor2.pcap"
3536
#define EXAMPLE_PCAP_NANO_PATH "PcapExamples/nanosecs.pcap"
37+
#define EXAMPLE_PCAP_NANO_WRITE_PATH "PcapExamples/nanosecs_copy.pcap"
3638
#define EXAMPLE_PCAPNG_NANO_PATH "PcapExamples/nanosecs.pcapng"
88 Bytes
Binary file not shown.
88 Bytes
Binary file not shown.

Tests/Pcap++Test/TestDefinition.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ PTF_TEST_CASE(TestLoggerMultiThread);
2121

2222
// Implemented in FileTests.cpp
2323
PTF_TEST_CASE(TestPcapFileReadWrite);
24-
PTF_TEST_CASE(TestPcapFilePrecision);
24+
PTF_TEST_CASE(TestPcapFileMicroPrecision);
25+
PTF_TEST_CASE(TestPcapFileNanoPrecision);
2526
PTF_TEST_CASE(TestPcapSllFileReadWrite);
2627
PTF_TEST_CASE(TestPcapSll2FileReadWrite);
2728
PTF_TEST_CASE(TestPcapRawIPFileReadWrite);

Tests/Pcap++Test/Tests/FileTests.cpp

Lines changed: 85 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -99,88 +99,106 @@ PTF_TEST_CASE(TestPcapFileReadWrite)
9999
PTF_ASSERT_FALSE(readerDev2.isOpened());
100100
} // TestPcapFileReadWrite
101101

102-
PTF_TEST_CASE(TestPcapFilePrecision)
102+
PTF_TEST_CASE(TestPcapFileMicroPrecision)
103103
{
104104
std::array<uint8_t, 16> testPayload = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
105105
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
106-
pcpp::RawPacket rawPacketNano(testPayload.data(), testPayload.size(), timespec({ 1, 1234 }), false); // 1.000001234
106+
107107
pcpp::RawPacket rawPacketMicro(testPayload.data(), testPayload.size(), timeval({ 1, 2 }), false); // 1.000002000
108+
pcpp::RawPacket rawPacketNano(testPayload.data(), testPayload.size(), timespec({ 1, 1234 }), false); // 1.000001234
109+
110+
// Write micro precision file
111+
pcpp::PcapFileWriterDevice writerDevMicro(EXAMPLE_PCAP_MICRO_WRITE_PATH, pcpp::LINKTYPE_ETHERNET, false);
112+
PTF_ASSERT_EQUAL(writerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Microseconds, enumclass);
113+
PTF_ASSERT_TRUE(writerDevMicro.open());
114+
PTF_ASSERT_EQUAL(writerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Microseconds, enumclass);
115+
116+
// File precision should remain Micro. Nano precision will be truncated to micro precision.
117+
PTF_ASSERT_TRUE(writerDevMicro.writePacket(rawPacketMicro));
118+
PTF_ASSERT_TRUE(writerDevMicro.writePacket(rawPacketNano));
119+
writerDevMicro.close();
120+
121+
pcpp::FileTimestampPrecision expectedPrecision = pcpp::PcapFileWriterDevice::isNanoSecondPrecisionSupported()
122+
? pcpp::FileTimestampPrecision::Nanoseconds
123+
: pcpp::FileTimestampPrecision::Microseconds;
124+
125+
// Read micro precision file, both original and written
126+
for (auto const path : { EXAMPLE_PCAP_MICRO_PATH, EXAMPLE_PCAP_MICRO_WRITE_PATH })
127+
{
128+
// Read micro precision file
129+
pcpp::PcapFileReaderDevice readerDevMicro(path);
130+
PTF_ASSERT_EQUAL(readerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Unknown, enumclass);
131+
PTF_ASSERT_TRUE(readerDevMicro.open());
132+
PTF_ASSERT_EQUAL(readerDevMicro.getTimestampPrecision(), expectedPrecision, enumclass);
133+
134+
pcpp::RawPacket readPacketNano2, readPacketMicro2;
135+
PTF_ASSERT_TRUE(readerDevMicro.getNextPacket(readPacketMicro2));
136+
PTF_ASSERT_EQUAL(readPacketMicro2.getPacketTimeStamp().tv_sec, 1);
137+
PTF_ASSERT_EQUAL(readPacketMicro2.getPacketTimeStamp().tv_nsec, 2000);
138+
139+
PTF_ASSERT_TRUE(readerDevMicro.getNextPacket(readPacketNano2));
140+
PTF_ASSERT_EQUAL(readPacketNano2.getPacketTimeStamp().tv_sec, 1);
141+
PTF_ASSERT_EQUAL(readPacketNano2.getPacketTimeStamp().tv_nsec, 1000);
142+
readerDevMicro.close();
143+
}
144+
} // TestPcapFileMicroPrecision
108145

146+
PTF_TEST_CASE(TestPcapFileNanoPrecision)
147+
{
109148
// Writer precision support should equal to reader precision support
110149
PTF_ASSERT_EQUAL(pcpp::PcapFileWriterDevice::isNanoSecondPrecisionSupported(),
111150
pcpp::PcapFileReaderDevice::isNanoSecondPrecisionSupported());
112151

152+
if (!pcpp::PcapFileWriterDevice::isNanoSecondPrecisionSupported())
153+
{
154+
PTF_PRINT_VERBOSE("Pcap nano precision is not supported on the current platform! "
155+
"The test will check for proper failure messages.\n");
156+
PTF_ASSERT_RAISES(pcpp::PcapFileWriterDevice(EXAMPLE_PCAP_NANO_WRITE_PATH, pcpp::LINKTYPE_ETHERNET, true),
157+
std::runtime_error,
158+
"PcapPlusPlus was compiled without nano precision support which requires libpcap > 1.5.1. "
159+
"Please recompile PcapPlusPlus with nano precision support to use this feature.");
160+
161+
pcpp::PcapFileReaderDevice readerDevNano(EXAMPLE_PCAP_NANO_PATH);
162+
PTF_ASSERT_FALSE(readerDevNano.open());
163+
return;
164+
}
165+
166+
std::array<uint8_t, 16> testPayload = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
167+
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
168+
169+
pcpp::RawPacket rawPacketMicro(testPayload.data(), testPayload.size(), timeval({ 1, 2 }), false); // 1.000002000
170+
pcpp::RawPacket rawPacketNano(testPayload.data(), testPayload.size(), timespec({ 1, 1234 }), false); // 1.000001234
171+
113172
// Write nano precision file
114-
pcpp::Logger::getInstance().suppressLogs();
115-
pcpp::PcapFileWriterDevice writerDevNano(EXAMPLE_PCAP_NANO_PATH, pcpp::LINKTYPE_ETHERNET, true);
116-
pcpp::Logger::getInstance().enableLogs();
117-
PTF_ASSERT_EQUAL(writerDevNano.getTimestampPrecision(),
118-
pcpp::PcapFileWriterDevice::isNanoSecondPrecisionSupported()
119-
? pcpp::FileTimestampPrecision::Nanoseconds
120-
: pcpp::FileTimestampPrecision::Microseconds,
121-
enumclass);
173+
pcpp::PcapFileWriterDevice writerDevNano(EXAMPLE_PCAP_NANO_WRITE_PATH, pcpp::LINKTYPE_ETHERNET, true);
174+
PTF_ASSERT_EQUAL(writerDevNano.getTimestampPrecision(), pcpp::FileTimestampPrecision::Nanoseconds, enumclass);
122175
PTF_ASSERT_TRUE(writerDevNano.open());
123-
PTF_ASSERT_EQUAL(writerDevNano.getTimestampPrecision(),
124-
pcpp::PcapFileWriterDevice::isNanoSecondPrecisionSupported()
125-
? pcpp::FileTimestampPrecision::Nanoseconds
126-
: pcpp::FileTimestampPrecision::Microseconds,
127-
enumclass);
176+
PTF_ASSERT_EQUAL(writerDevNano.getTimestampPrecision(), pcpp::FileTimestampPrecision::Nanoseconds, enumclass);
177+
178+
// File precision should remain Nano. Micro precision packet will be scaled to Nano precision.
128179
PTF_ASSERT_TRUE(writerDevNano.writePacket(rawPacketMicro));
129180
PTF_ASSERT_TRUE(writerDevNano.writePacket(rawPacketNano));
130181
writerDevNano.close();
131182

132-
// Write micro precision file
133-
pcpp::PcapFileWriterDevice writerDevMicro(EXAMPLE_PCAP_MICRO_PATH, pcpp::LINKTYPE_ETHERNET, false);
134-
PTF_ASSERT_EQUAL(writerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Microseconds, enumclass);
135-
PTF_ASSERT_TRUE(writerDevMicro.open());
136-
PTF_ASSERT_EQUAL(writerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Microseconds, enumclass);
137-
PTF_ASSERT_TRUE(writerDevMicro.writePacket(rawPacketMicro));
138-
PTF_ASSERT_TRUE(writerDevMicro.writePacket(rawPacketNano));
139-
writerDevMicro.close();
140-
141-
// Read nano precision file
142-
pcpp::PcapFileReaderDevice readerDevNano(EXAMPLE_PCAP_NANO_PATH);
143-
PTF_ASSERT_EQUAL(readerDevNano.getTimestampPrecision(), pcpp::FileTimestampPrecision::Unknown, enumclass);
144-
PTF_ASSERT_TRUE(readerDevNano.open());
145-
PTF_ASSERT_EQUAL(readerDevNano.getTimestampPrecision(),
146-
pcpp::PcapFileReaderDevice::isNanoSecondPrecisionSupported()
147-
? pcpp::FileTimestampPrecision::Nanoseconds
148-
: pcpp::FileTimestampPrecision::Microseconds,
149-
enumclass);
150-
151-
pcpp::RawPacket readPacketNano, readPacketMicro;
152-
PTF_ASSERT_TRUE(readerDevNano.getNextPacket(readPacketMicro));
153-
PTF_ASSERT_EQUAL(readPacketMicro.getPacketTimeStamp().tv_sec, 1);
154-
PTF_ASSERT_EQUAL(readPacketMicro.getPacketTimeStamp().tv_nsec, 2000);
155-
156-
PTF_ASSERT_TRUE(readerDevNano.getNextPacket(readPacketNano));
157-
PTF_ASSERT_EQUAL(readPacketNano.getPacketTimeStamp().tv_sec, 1);
158-
PTF_ASSERT_EQUAL(readPacketNano.getPacketTimeStamp().tv_nsec,
159-
pcpp::PcapFileReaderDevice::isNanoSecondPrecisionSupported() ? 1234 : 1000);
160-
161-
readerDevNano.close();
162-
163-
// Read micro precision file
164-
pcpp::PcapFileReaderDevice readerDevMicro(EXAMPLE_PCAP_MICRO_PATH);
165-
PTF_ASSERT_EQUAL(readerDevMicro.getTimestampPrecision(), pcpp::FileTimestampPrecision::Unknown, enumclass);
166-
PTF_ASSERT_TRUE(readerDevMicro.open());
167-
PTF_ASSERT_EQUAL(readerDevMicro.getTimestampPrecision(),
168-
pcpp::PcapFileReaderDevice::isNanoSecondPrecisionSupported()
169-
? pcpp::FileTimestampPrecision::Nanoseconds
170-
: pcpp::FileTimestampPrecision::Microseconds,
171-
enumclass);
172-
173-
pcpp::RawPacket readPacketNano2, readPacketMicro2;
174-
PTF_ASSERT_TRUE(readerDevMicro.getNextPacket(readPacketMicro2));
175-
PTF_ASSERT_EQUAL(readPacketMicro2.getPacketTimeStamp().tv_sec, 1);
176-
PTF_ASSERT_EQUAL(readPacketMicro2.getPacketTimeStamp().tv_nsec, 2000);
177-
178-
PTF_ASSERT_TRUE(readerDevMicro.getNextPacket(readPacketNano2));
179-
PTF_ASSERT_EQUAL(readPacketNano2.getPacketTimeStamp().tv_sec, 1);
180-
PTF_ASSERT_EQUAL(readPacketNano2.getPacketTimeStamp().tv_nsec, 1000);
181-
182-
readerDevMicro.close();
183-
} // TestPcapFilePrecision
183+
// Read nano precision file, both original and written
184+
for (auto const path : { EXAMPLE_PCAP_NANO_PATH, EXAMPLE_PCAP_NANO_WRITE_PATH })
185+
{
186+
pcpp::PcapFileReaderDevice readerDevNano(path);
187+
PTF_ASSERT_EQUAL(readerDevNano.getTimestampPrecision(), pcpp::FileTimestampPrecision::Unknown, enumclass);
188+
PTF_ASSERT_TRUE(readerDevNano.open());
189+
PTF_ASSERT_EQUAL(readerDevNano.getTimestampPrecision(), pcpp::FileTimestampPrecision::Nanoseconds, enumclass);
190+
191+
pcpp::RawPacket readPacketNano, readPacketMicro;
192+
PTF_ASSERT_TRUE(readerDevNano.getNextPacket(readPacketMicro));
193+
PTF_ASSERT_EQUAL(readPacketMicro.getPacketTimeStamp().tv_sec, 1);
194+
PTF_ASSERT_EQUAL(readPacketMicro.getPacketTimeStamp().tv_nsec, 2000);
195+
196+
PTF_ASSERT_TRUE(readerDevNano.getNextPacket(readPacketNano));
197+
PTF_ASSERT_EQUAL(readPacketNano.getPacketTimeStamp().tv_sec, 1);
198+
PTF_ASSERT_EQUAL(readPacketNano.getPacketTimeStamp().tv_nsec, 1234);
199+
readerDevNano.close();
200+
}
201+
} // TestPcapFileNanoPrecision
184202

185203
PTF_TEST_CASE(TestPcapNgFilePrecision)
186204
{

Tests/Pcap++Test/main.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ int main(int argc, char* argv[])
216216
PTF_RUN_TEST(TestLoggerMultiThread, "no_network;logger;skip_mem_leak_check");
217217

218218
PTF_RUN_TEST(TestPcapFileReadWrite, "no_network;pcap");
219-
PTF_RUN_TEST(TestPcapFilePrecision, "no_network;pcap");
219+
PTF_RUN_TEST(TestPcapFileMicroPrecision, "no_network;pcap");
220+
PTF_RUN_TEST(TestPcapFileNanoPrecision, "no_network;pcap");
220221
PTF_RUN_TEST(TestPcapSllFileReadWrite, "no_network;pcap");
221222
PTF_RUN_TEST(TestPcapSll2FileReadWrite, "no_network;pcap");
222223
PTF_RUN_TEST(TestPcapRawIPFileReadWrite, "no_network;pcap");

0 commit comments

Comments
 (0)