bug 872: ns3::PcapFileWrapper::Write explodes stack

This commit is contained in:
Mathieu Lacage
2010-04-16 07:48:12 +02:00
parent d848a2fdb8
commit 9cf441b3be
14 changed files with 409 additions and 535 deletions

View File

@@ -219,7 +219,7 @@ main (int argc, char *argv[])
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
PcapHelper pcapHelper;
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
Simulator::Stop (Seconds(20));

View File

@@ -31,19 +31,19 @@ using namespace ns3;
// Some utility functions for the tests.
// ===========================================================================
uint16_t
static uint16_t
Swap (uint16_t val)
{
return ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00);
}
uint32_t
static uint32_t
Swap (uint32_t val)
{
return ((val >> 24) & 0x000000ff) | ((val >> 8) & 0x0000ff00) | ((val << 8) & 0x00ff0000) | ((val << 24) & 0xff000000);
}
bool
static bool
CheckFileExists (std::string filename)
{
FILE * p = fopen (filename.c_str (), "rb");
@@ -57,7 +57,7 @@ CheckFileExists (std::string filename)
}
bool
static bool
CheckFileLength (std::string filename, uint64_t sizeExpected)
{
FILE * p = fopen (filename.c_str (), "rb");
@@ -93,7 +93,7 @@ private:
};
WriteModeCreateTestCase::WriteModeCreateTestCase ()
: TestCase ("Check to see that PcapFile::Open with mode \"w\" works")
: TestCase ("Check to see that PcapFile::Open with mode std::ios::out works")
{
}
@@ -125,25 +125,26 @@ WriteModeCreateTestCase::DoRun (void)
// Opening a new file in write mode should result in an empty file of the
// given name.
//
bool err = f.Open (m_testFilename, "w");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Close ();
NS_TEST_ASSERT_MSG_EQ (CheckFileExists (m_testFilename), true,
"Open (" << m_testFilename << ", \"w\") does not create file");
"Open (" << m_testFilename << ", \"std::ios::out\") does not create file");
NS_TEST_ASSERT_MSG_EQ (CheckFileLength (m_testFilename, 0), true,
"Open (" << m_testFilename << ", \"w\") does not result in an empty file");
"Open (" << m_testFilename << ", \"std::ios::out\") does not result in an empty file");
//
// Calling Init() on a file created with "w" should result in a file just
// Calling Init() on a file created with "std::ios::out" should result in a file just
// long enough to contain the pcap file header.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
err = f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1234, 5678, 7) returns error");
f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
f.Close ();
@@ -154,8 +155,9 @@ WriteModeCreateTestCase::DoRun (void)
// Opening an existing file in write mode should result in that file being
// emptied.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
f.Close ();
@@ -165,22 +167,23 @@ WriteModeCreateTestCase::DoRun (void)
//
// Initialize the file again.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false,
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false,
"Open (" << m_testFilename << ", \"w\") returns error");
err = f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1234, 5678, 7) returns error");
f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
//
// Now we should be able to write to it since it was opened in "w" mode.
// Now we should be able to write to it since it was opened in std::ios::out mode.
// This is just a permissions check so we don't actually look at the
// data.
//
uint8_t buffer[128];
memset(buffer, 0, sizeof(buffer));
err = f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (write-only-file " << m_testFilename << ") returns error");
f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename <<
") returns error");
return false;
}
@@ -204,7 +207,7 @@ private:
};
ReadModeCreateTestCase::ReadModeCreateTestCase ()
: TestCase ("Check to see that PcapFile::Open with mode \"r\" works")
: TestCase ("Check to see that PcapFile::Open with mode \"std::ios::in\" works")
{
}
@@ -235,55 +238,64 @@ ReadModeCreateTestCase::DoRun (void)
//
// Opening a non-existing file in read mode should result in an error.
//
bool err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, true, "Open (non-existing-filename " << m_testFilename << ", \"r\") does not return error");
NS_TEST_ASSERT_MSG_EQ (CheckFileExists (m_testFilename), false,
"Open (" << m_testFilename << ", \"r\") unexpectedly created a file");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-existing-filename " << m_testFilename <<
", \"std::ios::in\") does not return error");
f.Close ();
f.Clear ();
NS_TEST_ASSERT_MSG_EQ (CheckFileExists (m_testFilename), false, "Open (" << m_testFilename <<
", \"std::ios::in\") unexpectedly created a file");
//
// Okay, now create an uninitialized file using previously tested operations
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (filename, \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (filename, \"std::ios::out\") returns error");
f.Close ();
//
// Opening this file should result in an error since it has no pcap file header.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, true, "Open (non-initialized-filename " << m_testFilename << ", \"r\") does not return error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-initialized-filename " << m_testFilename <<
", \"std::ios::in\") does not return error");
f.Close ();
f.Clear ();
//
// Okay, now open that non-initialized file in write mode and initialize it
// Note that we open it in write mode to initialize it.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
err = f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1234, 5678, 7) returns error");
f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
f.Close ();
//
// Opening this file should now work since it has a pcap file header.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (initialized-filename " << m_testFilename << ", \"r\") returns error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (initialized-filename " << m_testFilename <<
", \"std::ios::in\") returns error");
//
// Now we should not be able to write to it since it was opened in "r" mode
// even if it has been initialized..
//
uint8_t buffer[128];
err = f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (err, true, "Write (read-only-file " << m_testFilename << ") does not return error");
f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Write (read-only-file " << m_testFilename <<
") does not return error");
f.Close ();
f.Clear ();
return false;
}
#if 0
// ===========================================================================
// Test case to make sure that the Pcap File Object can open an existing pcap
// file for appending.
@@ -303,7 +315,7 @@ private:
};
AppendModeCreateTestCase::AppendModeCreateTestCase ()
: TestCase ("Check to see that PcapFile::Open with mode \"a\" works")
: TestCase ("Check to see that PcapFile::Open with mode \"std::ios::app\" works")
{
}
@@ -334,54 +346,63 @@ AppendModeCreateTestCase::DoRun (void)
//
// Opening a non-existing file in append mode should result in an error.
//
bool err = f.Open (m_testFilename, "a");
NS_TEST_ASSERT_MSG_EQ (err, true, "Open (non-existing-filename " << m_testFilename << ", \"a\") does not return error");
f.Open (m_testFilename, std::ios::out | std::ios::app);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-existing-filename " << m_testFilename <<
", \"std::ios::app\") does not return error");
f.Close ();
f.Clear ();
NS_TEST_ASSERT_MSG_EQ (CheckFileExists (m_testFilename), false,
"Open (" << m_testFilename << ", \"a\") unexpectedly created a file");
"Open (" << m_testFilename << ", \"std::ios::app\") unexpectedly created a file");
//
// Okay, now create an uninitialized file using previously tested operations
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
f.Close ();
//
// Opening this file should result in an error since it has no pcap file header.
//
err = f.Open (m_testFilename, "a");
NS_TEST_ASSERT_MSG_EQ (err, true, "Open (non-initialized-filename " << m_testFilename << ", \"a\") does not return error");
f.Open (m_testFilename, std::ios::out | std::ios::app);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-initialized-filename " << m_testFilename <<
", \"std::ios::app\") does not return error");
f.Close ();
f.Clear ();
//
// Okay, now open that non-initialized file in write mode and initialize it.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (non-initialized-filename " << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (non-initialized-filename " << m_testFilename <<
", \"std::ios::out\") returns error");
err = f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1234, 5678, 7) returns error");
f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
f.Close ();
//
// Opening this file should now work since it has a pcap file header.
//
err = f.Open (m_testFilename, "a");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (initialized-filename " << m_testFilename << ", \"r\") returns error");
f.Open (m_testFilename, std::ios::out | std::ios::app);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (initialized-filename " << m_testFilename <<
", \"std::ios::app\") returns error");
//
// We should be able to write to it since it was opened in "a" mode.
// We should be able to write to it since it was opened in "std::ios::app" mode.
//
uint8_t buffer[128];
memset(buffer, 0, sizeof(buffer));
err = f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (append-mode-file " << m_testFilename << ") returns error");
f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (append-mode-file " << m_testFilename << ") returns error");
f.Close ();
return false;
}
#endif
// ===========================================================================
// Test case to make sure that the Pcap File Object can write out correct pcap
@@ -433,14 +454,15 @@ FileHeaderTestCase::DoRun (void)
//
// Create an uninitialized file using previously tested operations
//
bool err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
//
// Initialize the pcap file header.
//
err = f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (err, false,
f.Init (1234, 5678, 7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false,
"Init (1234, 5678, 7) returns error");
f.Close ();
@@ -525,8 +547,9 @@ FileHeaderTestCase::DoRun (void)
// automagically fixed up when using a PcapFile to read the values, so we
// don't have to do anything special here.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (existing-initialized-file " << m_testFilename << ", \"r\") returns error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (existing-initialized-file " << m_testFilename <<
", \"std::ios::in\") returns error");
NS_TEST_ASSERT_MSG_EQ (f.GetMagic (), 0xa1b2c3d4, "Read back magic number incorrectly");
NS_TEST_ASSERT_MSG_EQ (f.GetVersionMajor (), 2, "Read back version major incorrectly");
@@ -535,12 +558,14 @@ FileHeaderTestCase::DoRun (void)
NS_TEST_ASSERT_MSG_EQ (f.GetSigFigs (), 0, "Read back sig figs incorrectly");
NS_TEST_ASSERT_MSG_EQ (f.GetSnapLen (), 5678, "Read back snap len incorrectly");
NS_TEST_ASSERT_MSG_EQ (f.GetDataLinkType (), 1234, "Read back data link type incorrectly");
f.Close ();
//
// Re-open the file to erase its contents.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
//
// Initialize the pcap file header, turning on swap mode manually to force
@@ -550,8 +575,8 @@ FileHeaderTestCase::DoRun (void)
// a no-op and we're always writing foreign-endian files. In that case,
// this test case is really just a duplicate of the previous.
//
err = f.Init (1234, 5678, 7, true);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1234, 5678, 7) returns error");
f.Init (1234, 5678, 7, true);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
f.Close ();
//
@@ -599,8 +624,9 @@ FileHeaderTestCase::DoRun (void)
// machine is writing out a big-endian file by default, but we can't do that
// since it breaks regression testing.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (existing-initialized-file " << m_testFilename << ", \"r\") returns error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (existing-initialized-file " << m_testFilename <<
", \"std::ios::in\") returns error");
NS_TEST_ASSERT_MSG_EQ (f.GetSwapMode (), true, "Byte-swapped file not correctly indicated");
@@ -667,14 +693,15 @@ RecordHeaderTestCase::DoRun (void)
//
// Create an uninitialized file using previously tested operations
//
bool err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
//
// Initialize the pcap file header.
//
err = f.Init (37, 43, -7);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (37, 43, -7) returns error");
f.Init (37, 43, -7);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (37, 43, -7) returns error");
//
// Initialize a buffer with a counting pattern to check the data later.
@@ -690,8 +717,8 @@ RecordHeaderTestCase::DoRun (void)
// mode. The packet data written should be limited to 43 bytes in length
// by the Init() call above.
//
err = f.Write (1234, 5678, bufferOut, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (write-only-file " << m_testFilename << ") returns error");
f.Write (1234, 5678, bufferOut, 128);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename << ") returns error");
f.Close ();
//
@@ -785,18 +812,20 @@ RecordHeaderTestCase::DoRun (void)
// Let's see if the PcapFile object can figure out how to do the same thing and
// correctly read in a packet.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"r\") of existing good file returns error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::in\") of existing good file returns error");
uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
err = f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (err, false, "Read() of known good packet returns error");
f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good packet returns error");
NS_TEST_ASSERT_MSG_EQ (tsSec, 1234, "Incorrectly read seconds timestap from known good packet");
NS_TEST_ASSERT_MSG_EQ (tsUsec, 5678, "Incorrectly read microseconds timestap from known good packet");
NS_TEST_ASSERT_MSG_EQ (inclLen, 43, "Incorrectly read included length from known good packet");
NS_TEST_ASSERT_MSG_EQ (origLen, 128, "Incorrectly read original length from known good packet");
NS_TEST_ASSERT_MSG_EQ (readLen, 43, "Incorrectly constructed actual read length from known good packet given buffer size");
f.Close ();
//
// Did the data come back correctly?
@@ -815,22 +844,23 @@ RecordHeaderTestCase::DoRun (void)
//
// Open the file in write mode to clear the data.
//
err = f.Open (m_testFilename, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"w\") returns error");
f.Open (m_testFilename, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::out\") returns error");
//
// Initialize the pcap file header, forcing the object into swap mode.
//
err = f.Init (37, 43, -7, true);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (37, 43, -7) returns error");
f.Init (37, 43, -7, true);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (37, 43, -7) returns error");
//
// Now we should be able to write a packet to it since it was opened in "w"
// mode. The packet data written should be limited to 43 bytes in length
// by the Init() call above.
//
err = f.Write (1234, 5678, bufferOut, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (write-only-file " << m_testFilename << ") returns error");
f.Write (1234, 5678, bufferOut, 128);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename << ") returns error");
f.Close ();
//
@@ -892,11 +922,12 @@ RecordHeaderTestCase::DoRun (void)
// correctly read in a packet. The record header info should come back to us
// swapped back into correct form.
//
err = f.Open (m_testFilename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << m_testFilename << ", \"r\") of existing good file returns error");
f.Open (m_testFilename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
", \"std::ios::in\") of existing good file returns error");
err = f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (err, false, "Read() of known good packet returns error");
f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good packet returns error");
NS_TEST_ASSERT_MSG_EQ (tsSec, 1234, "Incorrectly read seconds timestap from known good packet");
NS_TEST_ASSERT_MSG_EQ (tsUsec, 5678, "Incorrectly read microseconds timestap from known good packet");
NS_TEST_ASSERT_MSG_EQ (inclLen, 43, "Incorrectly read included length from known good packet");
@@ -988,8 +1019,9 @@ ReadFileTestCase::DoRun (void)
//
//
std::string filename = NS_TEST_SOURCEDIR + "known.pcap";
bool err = f.Open (filename, "r");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << filename << ", \"w\") returns error");
f.Open (filename, std::ios::in);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << filename <<
", \"std::ios::in\") returns error");
//
// We are going to read out the file header and all of the packets to make
@@ -1006,8 +1038,8 @@ ReadFileTestCase::DoRun (void)
for (uint32_t i = 0; i < N_KNOWN_PACKETS; ++i, ++p)
{
err = f.Read (data, sizeof(data), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (err, false, "Read() of known good pcap file returns error");
f.Read (data, sizeof(data), tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good pcap file returns error");
NS_TEST_ASSERT_MSG_EQ (tsSec, p->tsSec, "Incorrectly read seconds timestap from known good pcap file");
NS_TEST_ASSERT_MSG_EQ (tsUsec, p->tsUsec, "Incorrectly read microseconds timestap from known good pcap file");
NS_TEST_ASSERT_MSG_EQ (inclLen, p->inclLen, "Incorrectly read included length from known good packet");
@@ -1019,8 +1051,8 @@ ReadFileTestCase::DoRun (void)
// The file should now be at EOF since we've read all of the packets.
// Another packet read should return an error.
//
err = f.Read (data, 1, tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (err, true, "Read() of known good pcap file at EOF does not return error");
f.Read (data, 1, tsSec, tsUsec, inclLen, origLen, readLen);
NS_TEST_ASSERT_MSG_EQ (f.Eof (), true, "Read() of known good pcap file at EOF does not return error");
f.Close ();
@@ -1061,17 +1093,17 @@ DiffTestCase::DoRun (void)
std::string filename2 = "different.pcap";
PcapFile f;
bool err = f.Open (filename2, "w");
NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << filename2 << ", \"w\") returns error");
err = f.Init (1, N_PACKET_BYTES);
NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1, " << N_PACKET_BYTES << ") returns error");
f.Open (filename2, std::ios::out);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << filename2 << ", \"std::ios::out\") returns error");
f.Init (1, N_PACKET_BYTES);
NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1, " << N_PACKET_BYTES << ") returns error");
for (uint32_t i = 0; i < N_KNOWN_PACKETS; ++i)
{
PacketEntry const & p = knownPackets[i];
err = f.Write (p.tsSec, p.tsUsec, (uint8_t const *)p.data, p.origLen);
NS_TEST_EXPECT_MSG_EQ (err, false, "Write must not fail");
f.Write (p.tsSec, p.tsUsec, (uint8_t const *)p.data, p.origLen);
NS_TEST_EXPECT_MSG_EQ (f.Fail (), false, "Write must not fail");
}
f.Close ();
@@ -1094,7 +1126,7 @@ PcapFileTestSuite::PcapFileTestSuite ()
{
AddTestCase (new WriteModeCreateTestCase);
AddTestCase (new ReadModeCreateTestCase);
AddTestCase (new AppendModeCreateTestCase);
//AddTestCase (new AppendModeCreateTestCase);
AddTestCase (new FileHeaderTestCase);
AddTestCase (new RecordHeaderTestCase);
AddTestCase (new ReadFileTestCase);

View File

@@ -54,19 +54,36 @@ PcapFileWrapper::~PcapFileWrapper ()
Close ();
}
bool
PcapFileWrapper::Fail (void) const
{
return m_file.Fail ();
}
bool
PcapFileWrapper::Eof (void) const
{
return m_file.Eof ();
}
void
PcapFileWrapper::Clear (void)
{
m_file.Clear ();
}
void
PcapFileWrapper::Close (void)
{
m_file.Close ();
}
bool
PcapFileWrapper::Open (std::string const &filename, std::string const &mode)
void
PcapFileWrapper::Open (std::string const &filename, std::ios::openmode mode)
{
return m_file.Open (filename, mode);
m_file.Open (filename, mode);
}
bool
void
PcapFileWrapper::Init (uint32_t dataLinkType, uint32_t snapLen, int32_t tzCorrection)
{
//
@@ -76,66 +93,42 @@ PcapFileWrapper::Init (uint32_t dataLinkType, uint32_t snapLen, int32_t tzCorrec
//
if (snapLen != std::numeric_limits<uint32_t>::max ())
{
return m_file.Init (dataLinkType, snapLen, tzCorrection);
m_file.Init (dataLinkType, snapLen, tzCorrection);
}
else
{
return m_file.Init (dataLinkType, m_snapLen, tzCorrection);
m_file.Init (dataLinkType, m_snapLen, tzCorrection);
}
//
// Quiet the compiler
//
return true;
}
bool
void
PcapFileWrapper::Write (Time t, Ptr<const Packet> p)
{
uint8_t buffer[PcapFile::SNAPLEN_DEFAULT];
uint64_t current = t.GetMicroSeconds ();
uint64_t s = current / 1000000;
uint64_t us = current % 1000000;
uint32_t bufferSize = p->GetSize ();
p->CopyData (buffer, bufferSize);
bool rc = m_file.Write (s, us, buffer, bufferSize);
return rc;
m_file.Write (s, us, p);
}
bool
void
PcapFileWrapper::Write (Time t, Header &header, Ptr<const Packet> p)
{
uint8_t buffer[PcapFile::SNAPLEN_DEFAULT];
uint64_t current = t.GetMicroSeconds ();
uint64_t s = current / 1000000;
uint64_t us = current % 1000000;
Buffer headerBuffer;
uint32_t headerSize = header.GetSerializedSize ();
uint32_t packetSize = p->GetSize ();
uint32_t bufferSize = headerSize + packetSize;
headerBuffer.AddAtStart (headerSize);
header.Serialize (headerBuffer.Begin ());
headerBuffer.Begin ().Read (buffer, headerSize);
p->CopyData (&buffer[headerSize], packetSize);
bool rc = m_file.Write (s, us, buffer, bufferSize);
return rc;
m_file.Write (s, us, header, p);
}
bool
void
PcapFileWrapper::Write (Time t, uint8_t const *buffer, uint32_t length)
{
uint64_t current = t.GetMicroSeconds ();
uint64_t s = current / 1000000;
uint64_t us = current % 1000000;
return m_file.Write (s, us, buffer, length);
m_file.Write (s, us, buffer, length);
}
uint32_t

View File

@@ -21,6 +21,7 @@
#include <string.h>
#include <limits>
#include <fstream>
#include "ns3/ptr.h"
#include "ns3/packet.h"
#include "ns3/nstime.h"
@@ -42,64 +43,34 @@ public:
PcapFileWrapper ();
~PcapFileWrapper ();
/**
* Create a new pcap file wrapper representing a new or existing pcap file.
* Semantics are similar to the C standard library function \c fopen
*
* Possible modes are:
*
* \verbatim
* "r": Open a file for reading. The file must exist. The pcap header
* is assumed to exist in the file and will be read and checked.
* The file seek position indicator is set to point to the first
* packet on exit.
*
* "w": Create an empty file for writing. If a file with the same name
* already exists its content is erased and the file is treated as a
* new empty pcap file. The file is assumed not to have a pcap
* header and the caller is responsible for calling Init before saving
* any packet data. The file seek position indicator is set to point
* to the beginning of the file on exit since there will be no pcap
* header.
*
* "a": Append to an existing file. This mode allows for adding packet data
* to the end of an existing pcap file. The file must exist and have a
* valid pcap header written (N.B. this is different from standard fopen
* semantics). The file seek position indicator is set to point
* to the end of the file on exit.
*
* "r+": Open a file for update -- both reading and writing. The file must
* exist. The pcap header is assumed to have been written to the
* file and will be read and checked. The file seek position indicator
* is set to point to the first packet on exit.
*
* "w+": Create an empty file for both reading and writing. If a file with
* the same name already exists, its content is erased and the file is
* treated as a new empty pcap file. Since this new file will not have
* a pcap header, the caller is responsible for calling Init before
* saving any packet data. On exit, the file seek position indicator is
* set to point to the beginning of the file.
*
* "a+" Open a file for reading and appending. The file must exist and have a
* valid pcap header written (N.B. this is different from standard fopen
* semantics). The file seek position indicator is set to point
* to the end of the file on exit. Existing content is preserved.
* \endverbatim
* \return true if the 'fail' bit is set in the underlying iostream, false otherwise.
*/
bool Fail (void) const;
/**
* \return true if the 'eof' bit is set in the underlying iostream, false otherwise.
*/
bool Eof (void) const;
/**
* Clear all state bits of the underlying iostream.
*/
void Clear (void);
/**
* Create a new pcap file or open an existing pcap file. Semantics are
* similar to the stdc++ io stream classes.
*
* Since a pcap file is always a binary file, the file type is automatically
* selected as a binary file. For example, providing a mode string "a+"
* results in the underlying OS file being opened in "a+b" mode.
* selected as a binary file (fstream::binary is automatically ored with the mode
* field).
*
* \param filename String containing the name of the file.
*
* \param mode String containing the access mode for the file.
*
* \returns Error indication that should be interpreted as, "did an error
* happen"? That is, the method returns false if the open succeeds, true
* otherwise. The errno variable will be set by the OS to to provide a
* more descriptive failure indication.
*/
bool Open (std::string const &filename, std::string const &mode);
void Open (std::string const &filename, std::ios::openmode mode);
/**
* Close the underlying pcap file.
@@ -126,12 +97,10 @@ public:
* time zone from UTC/GMT. For example, Pacific Standard Time in the US is
* GMT-8, so one would enter -8 for that correction. Defaults to 0 (UTC).
*
* \return false if the open succeeds, true otherwise.
*
* \warning Calling this method on an existing file will result in the loss
* any existing data.
*/
bool Init (uint32_t dataLinkType,
void Init (uint32_t dataLinkType,
uint32_t snapLen = std::numeric_limits<uint32_t>::max (),
int32_t tzCorrection = PcapFile::ZONE_DEFAULT);
@@ -141,9 +110,8 @@ public:
* \param t Packet timestamp as ns3::Time.
* \param p Packet to write to the pcap file.
*
* \return true on error, false otherwise
*/
bool Write (Time t, Ptr<const Packet> p);
void Write (Time t, Ptr<const Packet> p);
/**
* \brief Write the provided header along with the packet to the pcap file.
@@ -156,9 +124,8 @@ public:
* \param header The Header to prepend to the packet.
* \param p Packet to write to the pcap file.
*
* \return true on error, false otherwise
*/
bool Write (Time t, Header &header, Ptr<const Packet> p);
void Write (Time t, Header &header, Ptr<const Packet> p);
/**
* \brief Write the provided data buffer to the pcap file.
@@ -167,9 +134,8 @@ public:
* \param buffer The buffer to write.
* \param length The size of the buffer.
*
* \return true on error, false otherwise
*/
bool Write (Time t, uint8_t const *buffer, uint32_t length);
void Write (Time t, uint8_t const *buffer, uint32_t length);
/*
* \brief Returns the magic number of the pcap file as defined by the magic_number

View File

@@ -19,10 +19,12 @@
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/fatal-error.h"
#include "ns3/header.h"
#include "ns3/buffer.h"
#include "pcap-file.h"
//
// This file is used as part of the ns-3 test framework, so please refrain from
@@ -41,28 +43,37 @@ const uint16_t VERSION_MINOR = 4; /**< Minor version of supported pc
const int32_t SIGFIGS_DEFAULT = 0; /**< Significant figures for timestamps (libpcap doesn't even bother) */
PcapFile::PcapFile ()
: m_filename (""),
m_filePtr (0),
m_haveFileHeader (false),
: m_file (),
m_swapMode (false)
{
}
{}
PcapFile::~PcapFile ()
{
Close ();
}
bool
PcapFile::Fail (void) const
{
return m_file.fail ();
}
bool
PcapFile::Eof (void) const
{
return m_file.eof ();
}
void
PcapFile::Clear (void)
{
m_file.clear ();
}
void
PcapFile::Close (void)
{
if (m_filePtr)
{
fclose (m_filePtr);
}
m_filePtr = 0;
m_filename = "";
m_haveFileHeader = false;
m_file.close ();
}
uint32_t
@@ -152,18 +163,14 @@ PcapFile::Swap (PcapRecordHeader *from, PcapRecordHeader *to)
to->m_origLen = Swap (from->m_origLen);
}
bool
void
PcapFile::WriteFileHeader (void)
{
//
// If we're initializing the file, we need to write the pcap file header
// at the start of the file.
//
int result = fseek (m_filePtr, 0, SEEK_SET);
if (result)
{
return true;
}
m_file.seekp (0, std::ios::beg);
//
// We have the ability to write out the pcap file header in a foreign endian
@@ -191,57 +198,34 @@ PcapFile::WriteFileHeader (void)
// Watch out for memory alignment differences between machines, so write
// them all individually.
//
result = 0;
result |= (fwrite (&headerOut->m_magicNumber, sizeof(headerOut->m_magicNumber), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_versionMajor, sizeof(headerOut->m_versionMajor), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_versionMinor, sizeof(headerOut->m_versionMinor), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_zone, sizeof(headerOut->m_zone), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_sigFigs, sizeof(headerOut->m_sigFigs), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_snapLen, sizeof(headerOut->m_snapLen), 1, m_filePtr) != 1);
result |= (fwrite (&headerOut->m_type, sizeof(headerOut->m_type), 1, m_filePtr) != 1);
//
// If any of the fwrites above did not succeed in writinging the correct
// number of objects, result will be nonzero and will indicate an error.
//
return result != 0;
m_file.write ((const char *)&headerOut->m_magicNumber, sizeof(headerOut->m_magicNumber));
m_file.write ((const char *)&headerOut->m_versionMajor, sizeof(headerOut->m_versionMajor));
m_file.write ((const char *)&headerOut->m_versionMinor, sizeof(headerOut->m_versionMinor));
m_file.write ((const char *)&headerOut->m_zone, sizeof(headerOut->m_zone));
m_file.write ((const char *)&headerOut->m_sigFigs, sizeof(headerOut->m_sigFigs));
m_file.write ((const char *)&headerOut->m_snapLen, sizeof(headerOut->m_snapLen));
m_file.write ((const char *)&headerOut->m_type, sizeof(headerOut->m_type));
}
bool
void
PcapFile::ReadAndVerifyFileHeader (void)
{
//
// Pcap file header is always at the start of the file
//
int result = fseek (m_filePtr, 0, SEEK_SET);
if (result)
{
return true;
}
m_file.seekg (0, std::ios::beg);
//
// Watch out for memory alignment differences between machines, so read
// them all individually.
//
result = 0;
result |= (fread (&m_fileHeader.m_magicNumber, sizeof(m_fileHeader.m_magicNumber), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_versionMajor, sizeof(m_fileHeader.m_versionMajor), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_versionMinor, sizeof(m_fileHeader.m_versionMinor), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_zone, sizeof(m_fileHeader.m_zone), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_sigFigs, sizeof(m_fileHeader.m_sigFigs), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_snapLen, sizeof(m_fileHeader.m_snapLen), 1, m_filePtr) != 1);
result |= (fread (&m_fileHeader.m_type, sizeof(m_fileHeader.m_type), 1, m_filePtr) != 1);
//
// If any of the freads above did not succeed in reading the correct number of
// objects, result will be nonzero.
//
if (result)
{
return true;
}
m_file.read ((char *)&m_fileHeader.m_magicNumber, sizeof(m_fileHeader.m_magicNumber));
m_file.read ((char *)&m_fileHeader.m_versionMajor, sizeof(m_fileHeader.m_versionMajor));
m_file.read ((char *)&m_fileHeader.m_versionMinor, sizeof(m_fileHeader.m_versionMinor));
m_file.read ((char *)&m_fileHeader.m_zone, sizeof(m_fileHeader.m_zone));
m_file.read ((char *)&m_fileHeader.m_sigFigs, sizeof(m_fileHeader.m_sigFigs));
m_file.read ((char *)&m_fileHeader.m_snapLen, sizeof(m_fileHeader.m_snapLen));
m_file.read ((char *)&m_fileHeader.m_type, sizeof(m_fileHeader.m_type));
//
// There are four possible magic numbers that can be there. Normal and byte
@@ -251,14 +235,15 @@ PcapFile::ReadAndVerifyFileHeader (void)
if (m_fileHeader.m_magicNumber != MAGIC && m_fileHeader.m_magicNumber != SWAPPED_MAGIC &&
m_fileHeader.m_magicNumber != NS_MAGIC && m_fileHeader.m_magicNumber != NS_SWAPPED_MAGIC)
{
return true;
m_file.setstate (std::ios::failbit);
}
//
// If the magic number is swapped, then we can assume that everything else we read
// is swapped.
//
m_swapMode = (m_fileHeader.m_magicNumber == SWAPPED_MAGIC || m_fileHeader.m_magicNumber == NS_SWAPPED_MAGIC) ? true : false;
m_swapMode = (m_fileHeader.m_magicNumber == SWAPPED_MAGIC
|| m_fileHeader.m_magicNumber == NS_SWAPPED_MAGIC) ? true : false;
if (m_swapMode)
{
@@ -270,7 +255,7 @@ PcapFile::ReadAndVerifyFileHeader (void)
//
if (m_fileHeader.m_versionMajor != VERSION_MAJOR || m_fileHeader.m_versionMinor != VERSION_MINOR)
{
return true;
m_file.setstate (std::ios::failbit);
}
//
@@ -279,111 +264,34 @@ PcapFile::ReadAndVerifyFileHeader (void)
//
if (m_fileHeader.m_zone < -12 || m_fileHeader.m_zone > 12)
{
return true;
m_file.setstate (std::ios::failbit);
}
m_haveFileHeader = true;
return false;
if (m_file.fail ())
{
m_file.close ();
}
}
bool
PcapFile::Open (std::string const &filename, std::string const &mode)
void
PcapFile::Open (std::string const &filename, std::ios::openmode mode)
{
//
// If opening a new file, implicit close of any existing file required.
//
Close ();
NS_ASSERT ((mode & std::ios::app) == 0);
NS_ASSERT (!m_file.fail ());
//
// All pcap files are binary files, so we just do this automatically.
//
std::string realMode = mode + "b";
mode |= std::ios::binary;
//
// Our modes may be subtly different from the standard fopen semantics since
// we need to have a pcap file header to succeed in some cases; so we need
// to process different modes according to our own definitions of the modes.
//
// In the case of read modes, we must read, check and save the pcap file
// header as well as just opening the file.
//
// In the case of write modes, we just pass the call on through to the
// library.
//
// In the case of append modes, we change the semantics to require the
// given file to exist. We can't just create a file since we can't make up
// a pcap file header on our own.
//
if (realMode == "rb" || realMode == "r+b")
m_file.open (filename.c_str (), mode);
if (mode & std::ios::in)
{
m_filePtr = fopen (filename.c_str (), realMode.c_str ());
if (m_filePtr == 0)
{
return true;
}
m_filename = filename;
return ReadAndVerifyFileHeader ();
}
else if (realMode == "wb" || realMode == "w+b")
{
m_filePtr = fopen (filename.c_str (), realMode.c_str ());
if (m_filePtr)
{
m_filename = filename;
return false;
}
else
{
return true;
}
}
else if (realMode == "ab" || realMode == "a+b")
{
//
// Remember that semantics for append are different here. We never create
// a file since we can't make up a pcap file header. We first have to
// open the file in read-only mode and check to see that it exists and
// read the file header. If this all works out, then we can go ahead and
// open the file in append mode and seek to the end (imlicitly).
//
m_filePtr = fopen (filename.c_str (), "rb");
if (m_filePtr == 0)
{
return true;
}
bool result = ReadAndVerifyFileHeader ();
if (result == true)
{
Close ();
return true;
}
//
// We have a properly initialized file and have the pcap file header
// loaded and checked. This means that the file meets all of the
// critera for opening in append mode, but the file is in read-only mode
// now -- we must close it and open it in the correct mode.
//
fclose (m_filePtr);
m_filePtr = 0;
m_filePtr = fopen (filename.c_str (), realMode.c_str ());
if (m_filePtr == 0)
{
return true;
}
m_filename = filename;
return false;
}
else
{
return true;
// will set the fail bit if file header is invalid.
ReadAndVerifyFileHeader ();
}
}
bool
void
PcapFile::Init (uint32_t dataLinkType, uint32_t snapLen, int32_t timeZoneCorrection, bool swapMode)
{
//
@@ -397,8 +305,6 @@ PcapFile::Init (uint32_t dataLinkType, uint32_t snapLen, int32_t timeZoneCorrect
m_fileHeader.m_snapLen = snapLen;
m_fileHeader.m_type = dataLinkType;
m_haveFileHeader = true;
//
// We use pcap files for regression testing. We do byte-for-byte comparisons
// in those tests to determine pass or fail. If we allow big endian systems
@@ -426,16 +332,13 @@ PcapFile::Init (uint32_t dataLinkType, uint32_t snapLen, int32_t timeZoneCorrect
//
m_swapMode = swapMode | bigEndian;
return WriteFileHeader ();
WriteFileHeader ();
}
bool
PcapFile::Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, uint32_t totalLen)
uint32_t
PcapFile::WritePacketHeader (uint32_t tsSec, uint32_t tsUsec, uint32_t totalLen)
{
if (m_haveFileHeader == false)
{
return true;
}
NS_ASSERT (m_file.good ());
uint32_t inclLen = totalLen > m_fileHeader.m_snapLen ? m_fileHeader.m_snapLen : totalLen;
@@ -454,19 +357,44 @@ PcapFile::Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, ui
// Watch out for memory alignment differences between machines, so write
// them all individually.
//
uint32_t result = 0;
result |= (fwrite (&header.m_tsSec, sizeof(header.m_tsSec), 1, m_filePtr) != 1);
result |= (fwrite (&header.m_tsUsec, sizeof(header.m_tsUsec), 1, m_filePtr) != 1);
result |= (fwrite (&header.m_inclLen, sizeof(header.m_inclLen), 1, m_filePtr) != 1);
result |= (fwrite (&header.m_origLen, sizeof(header.m_origLen), 1, m_filePtr) != 1);
result |= fwrite (data, 1, inclLen, m_filePtr) != inclLen;
return result != 0;
m_file.write ((const char *)&header.m_tsSec, sizeof(header.m_tsSec));
m_file.write ((const char *)&header.m_tsUsec, sizeof(header.m_tsUsec));
m_file.write ((const char *)&header.m_inclLen, sizeof(header.m_inclLen));
m_file.write ((const char *)&header.m_origLen, sizeof(header.m_origLen));
return inclLen;
}
bool
void
PcapFile::Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, uint32_t totalLen)
{
uint32_t inclLen = WritePacketHeader (tsSec, tsUsec, totalLen);
m_file.write ((const char *)data, inclLen);
}
void
PcapFile::Write (uint32_t tsSec, uint32_t tsUsec, Ptr<const Packet> p)
{
uint32_t inclLen = WritePacketHeader (tsSec, tsUsec, p->GetSize ());
p->CopyData (&m_file, inclLen);
}
void
PcapFile::Write (uint32_t tsSec, uint32_t tsUsec, Header &header, Ptr<const Packet> p)
{
uint32_t headerSize = header.GetSerializedSize ();
uint32_t totalSize = headerSize + p->GetSize ();
uint32_t inclLen = WritePacketHeader (tsSec, tsUsec, totalSize);
Buffer headerBuffer;
headerBuffer.AddAtStart (headerSize);
header.Serialize (headerBuffer.Begin ());
uint32_t toCopy = std::min (headerSize, inclLen);
headerBuffer.CopyData (&m_file, toCopy);
inclLen -= toCopy;
p->CopyData (&m_file, inclLen);
}
void
PcapFile::Read (
uint8_t * const data,
uint32_t maxBytes,
@@ -476,10 +404,7 @@ PcapFile::Read (
uint32_t &origLen,
uint32_t &readLen)
{
if (m_haveFileHeader == false)
{
return true;
}
NS_ASSERT (m_file.good ());
PcapRecordHeader header;
@@ -487,21 +412,10 @@ PcapFile::Read (
// Watch out for memory alignment differences between machines, so read
// them all individually.
//
uint32_t result = 0;
result |= (fread (&header.m_tsSec, sizeof(header.m_tsSec), 1, m_filePtr) != 1);
result |= (fread (&header.m_tsUsec, sizeof(header.m_tsUsec), 1, m_filePtr) != 1);
result |= (fread (&header.m_inclLen, sizeof(header.m_inclLen), 1, m_filePtr) != 1);
result |= (fread (&header.m_origLen, sizeof(header.m_origLen), 1, m_filePtr) != 1);
//
// If any of the freads above did not succeed in reading the correct number of
// objects, result will be nonzero.
//
if (result)
{
return true;
}
m_file.read ((char *)&header.m_tsSec, sizeof(header.m_tsSec));
m_file.read ((char *)&header.m_tsUsec, sizeof(header.m_tsUsec));
m_file.read ((char *)&header.m_inclLen, sizeof(header.m_inclLen));
m_file.read ((char *)&header.m_origLen, sizeof(header.m_origLen));
if (m_swapMode)
{
@@ -521,11 +435,7 @@ PcapFile::Read (
// for example, to figure out what is going on.
//
readLen = maxBytes < header.m_inclLen ? maxBytes : header.m_inclLen;
result = fread (data, 1, readLen, m_filePtr) != readLen;
if (result)
{
return result;
}
m_file.read ((char *)data, readLen);
//
// To keep the file pointer pointed in the right place, however, we always
@@ -533,15 +443,8 @@ PcapFile::Read (
//
if (readLen < header.m_inclLen)
{
uint64_t pos = ftell (m_filePtr);
int result = fseek (m_filePtr, pos + header.m_inclLen - readLen, SEEK_SET);
if (result)
{
return true;
}
m_file.seekg (header.m_inclLen - readLen, std::ios::cur);
}
return false;
}
bool
@@ -549,59 +452,58 @@ PcapFile::Diff (std::string const & f1, std::string const & f2,
uint32_t & sec, uint32_t & usec,
uint32_t snapLen)
{
PcapFile pcap[2];
for (int i = 0; i < 2; ++i)
PcapFile pcap1, pcap2;
pcap1.Open (f1, std::ios::in);
pcap2.Open (f2, std::ios::in);
bool bad = pcap1.Fail () || pcap2.Fail ();
if (bad)
{
std::string const & file = (i == 0) ? f1 : f2;
bool err = pcap[i].Open (file, "r");
if (err)
{
// Can't open file
return true;
}
return true;
}
uint8_t data[2][snapLen];
uint32_t tsSec[2], tsUsec[2], inclLen[2], origLen[2], readLen[2];
bool err[2];
bool diff(false);
uint8_t *data1 = new uint8_t [snapLen] ();
uint8_t *data2 = new uint8_t [snapLen] ();
uint32_t tsSec1, tsSec2;
uint32_t tsUsec1, tsUsec2;
uint32_t inclLen1, inclLen2;
uint32_t origLen1, origLen2;
uint32_t readLen1, readLen2;
bool diff = false;
while (1)
while (!pcap1.Eof () && !pcap2.Eof ()
&& !pcap1.Fail () && !pcap2.Fail ())
{
for (int i = 0; i < 2; ++i)
err[i] = pcap[i].Read (data[i], snapLen, tsSec[i], tsUsec[i], inclLen[i], origLen[i], readLen[i]);
sec = tsSec[0];
usec = tsUsec[0];
if (err[0] != err[1])
{
diff = true; // Read status doesn't match
break;
}
if (err[0]) break; // nothing left
if (tsSec[0] != tsSec[1] || tsUsec[0] != tsUsec[1])
pcap1.Read (data1, snapLen, tsSec1, tsUsec1, inclLen1, origLen1, readLen1);
pcap2.Read (data2, snapLen, tsSec2, tsUsec2, inclLen2, origLen2, readLen2);
if (tsSec1 != tsSec2 || tsUsec1 != tsUsec2)
{
diff = true; // Next packet timestamps do not match
break;
}
if (readLen[0] != readLen[1])
if (readLen1 != readLen2)
{
diff = true; // Packet lengths do not match
break;
}
if (std::memcmp(data[0], data[1], readLen[0]) != 0)
if (std::memcmp(data1, data2, readLen1) != 0)
{
diff = true; // Packet data do not match
break;
}
}
pcap[0].Close ();
pcap[1].Close ();
sec = tsSec1;
usec = tsUsec1;
bad = pcap1.Fail () || pcap2.Fail ();
bool eof = pcap1.Eof () && pcap2.Eof ();
if (bad && !eof)
{
diff = true;
}
return diff;
}

View File

@@ -22,10 +22,15 @@
#define PCAP_FILE_H
#include <string>
#include <fstream>
#include <stdint.h>
#include "ns3/ptr.h"
namespace ns3 {
class Packet;
class Header;
/*
* A class representing a pcap file. This allows easy creation, writing and
* reading of files composed of stored packets; which may be viewed using
@@ -42,68 +47,36 @@ public:
PcapFile ();
~PcapFile ();
/**
* \return true if the 'fail' bit is set in the underlying iostream, false otherwise.
*/
bool Fail (void) const;
/**
* \return true if the 'eof' bit is set in the underlying iostream, false otherwise.
*/
bool Eof (void) const;
/**
* Clear all state bits of the underlying iostream.
*/
void Clear (void);
/**
* Create a new pcap file or open an existing pcap file. Semantics are
* similar to the C standard library function \c fopen, but differ in that
* similar to the stdc++ io stream classes, but differ in that
* positions in the file are based on packets not characters. For example
* if the file is opened for reading, the file position indicator (seek
* position) points to the beginning of the first packet in the file, not
* zero (which would point to the start of the pcap header).
*
* Possible modes are:
*
* \verbatim
* "r": Open a file for reading. The file must exist. The pcap header
* is assumed to exist in the file and will be read and checked.
* The file seek position indicator is set to point to the first
* packet on exit.
*
* "w": Create an empty file for writing. If a file with the same name
* already exists its content is erased and the file is treated as a
* new empty pcap file. The file is assumed not to have a pcap
* header and the caller is responsible for calling Init before saving
* any packet data. The file seek position indicator is set to point
* to the beginning of the file on exit since there will be no pcap
* header.
*
* "a": Append to an existing file. This mode allows for adding packet data
* to the end of an existing pcap file. The file must exist and have a
* valid pcap header written (N.B. this is different from standard fopen
* semantics). The file seek position indicator is set to point
* to the end of the file on exit.
*
* "r+": Open a file for update -- both reading and writing. The file must
* exist. The pcap header is assumed to have been written to the
* file and will be read and checked. The file seek position indicator
* is set to point to the first packet on exit.
*
* "w+": Create an empty file for both reading and writing. If a file with
* the same name already exists, its content is erased and the file is
* treated as a new empty pcap file. Since this new file will not have
* a pcap header, the caller is responsible for calling Init before
* saving any packet data. On exit, the file seek position indicator is
* set to point to the beginning of the file.
*
* "a+" Open a file for reading and appending. The file must exist and have a
* valid pcap header written (N.B. this is different from standard fopen
* semantics). The file seek position indicator is set to point
* to the end of the file on exit. Existing content is preserved.
* \endverbatim
*
* Since a pcap file is always a binary file, the file type is automatically
* selected as a binary file. For example, providing a mode string "a+"
* results in the underlying OS file being opened in "a+b" mode.
* selected as a binary file (fstream::binary is automatically ored with the mode
* field).
*
* \param filename String containing the name of the file.
*
* \param mode String containing the access mode for the file.
*
* \returns Error indication that should be interpreted as, "did an error
* happen"? That is, the method returns false if the open succeeds, true
* otherwise. The errno variable will be set by the OS to to provide a
* more descriptive failure indication.
* \param mode the access mode for the file.
*/
bool Open (std::string const &filename, std::string const &mode);
void Open (std::string const &filename, std::ios::openmode mode);
/**
* Close the underlying file.
@@ -138,7 +111,7 @@ public:
* \warning Calling this method on an existing file will result in the loss
* any existing data.
*/
bool Init (uint32_t dataLinkType,
void Init (uint32_t dataLinkType,
uint32_t snapLen = SNAPLEN_DEFAULT,
int32_t timeZoneCorrection = ZONE_DEFAULT,
bool swapMode = false);
@@ -151,9 +124,29 @@ public:
* \param data Data buffer
* \param totalLen Total packet length
*
* \return true on error, false otherwise
*/
bool Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, uint32_t totalLen);
void Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, uint32_t totalLen);
/**
* \brief Write next packet to file
*
* \param tsSec Packet timestamp, seconds
* \param tsUsec Packet timestamp, microseconds
* \param p Packet to write
*
*/
void Write (uint32_t tsSec, uint32_t tsUsec, Ptr<const Packet> p);
/**
* \brief Write next packet to file
*
* \param tsSec Packet timestamp, seconds
* \param tsUsec Packet timestamp, microseconds
* \param header Header to write, in front of packet
* \param p Packet to write
*
*/
void Write (uint32_t tsSec, uint32_t tsUsec, Header &header, Ptr<const Packet> p);
/**
* \brief Read next packet from file
@@ -166,9 +159,8 @@ public:
* \param origLen [out] Original length
* \param readLen [out] Number of bytes read
*
* \return true if read failed, false otherwise
*/
bool Read (uint8_t * const data,
void Read (uint8_t * const data,
uint32_t maxBytes,
uint32_t &tsSec,
uint32_t &tsUsec,
@@ -290,13 +282,13 @@ private:
void Swap (PcapFileHeader *from, PcapFileHeader *to);
void Swap (PcapRecordHeader *from, PcapRecordHeader *to);
bool WriteFileHeader (void);
bool ReadAndVerifyFileHeader (void);
void WriteFileHeader (void);
uint32_t WritePacketHeader (uint32_t tsSec, uint32_t tsUsec, uint32_t totalLen);
void ReadAndVerifyFileHeader (void);
std::string m_filename;
FILE *m_filePtr;
std::fstream m_file;
PcapFileHeader m_fileHeader;
bool m_haveFileHeader;
bool m_swapMode;
};

View File

@@ -98,7 +98,8 @@ CsmaHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool prom
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_EN10MB);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out,
PcapHelper::DLT_EN10MB);
if (promiscuous)
{
pcapHelper.HookDefaultSink<CsmaNetDevice> (device, "PromiscSniffer", file);
@@ -159,7 +160,7 @@ CsmaHelper::EnableAsciiInternal (
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//
// The MacRx trace source provides our "r" event.

View File

@@ -91,7 +91,7 @@ EmuHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promi
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_EN10MB);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_EN10MB);
if (promiscuous)
{
pcapHelper.HookDefaultSink<EmuNetDevice> (device, "PromiscSniffer", file);
@@ -152,7 +152,7 @@ EmuHelper::EnableAsciiInternal (
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//
// The MacRx trace source provides our "r" event.

View File

@@ -470,7 +470,7 @@ InternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4,
filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_RAW);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
//
// However, we only hook the trace source once to avoid multiple trace sink
@@ -562,7 +562,7 @@ InternetStackHelper::EnablePcapIpv6Internal (std::string prefix, Ptr<Ipv6> ipv6,
filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_RAW);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
//
// However, we only hook the trace source once to avoid multiple trace sink
@@ -714,7 +714,7 @@ InternetStackHelper::EnableAsciiIpv4Internal (
filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//
// However, we only hook the trace sources once to avoid multiple trace sink
@@ -909,7 +909,7 @@ InternetStackHelper::EnableAsciiIpv6Internal (
filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//
// However, we only hook the trace sources once to avoid multiple trace sink

View File

@@ -99,7 +99,8 @@ PointToPointHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, b
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_PPP);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out,
PcapHelper::DLT_PPP);
pcapHelper.HookDefaultSink<PointToPointNetDevice> (device, "PromiscSniffer", file);
}
@@ -154,7 +155,7 @@ PointToPointHelper::EnableAsciiInternal (
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//
// The MacRx trace source provides our "r" event.

View File

@@ -48,7 +48,7 @@ PcapHelper::~PcapHelper ()
Ptr<PcapFileWrapper>
PcapHelper::CreateFile (
std::string filename,
std::string filemode,
std::ios::openmode filemode,
uint32_t dataLinkType,
uint32_t snapLen,
int32_t tzCorrection)
@@ -56,11 +56,11 @@ PcapHelper::CreateFile (
NS_LOG_FUNCTION (filename << filemode << dataLinkType << snapLen << tzCorrection);
Ptr<PcapFileWrapper> file = CreateObject<PcapFileWrapper> ();
bool err = file->Open (filename, filemode);
NS_ABORT_MSG_IF (err, "Unable to Open " << filename << " for mode " << filemode);
file->Open (filename, filemode);
NS_ABORT_MSG_IF (file->Fail (), "Unable to Open " << filename << " for mode " << filemode);
err = file->Init (dataLinkType, snapLen, tzCorrection);
NS_ABORT_MSG_IF (err, "Unable to Init " << filename);
file->Init (dataLinkType, snapLen, tzCorrection);
NS_ABORT_MSG_IF (file->Fail (), "Unable to Init " << filename);
//
// Note that the pcap helper promptly forgets all about the pcap file. We
@@ -181,27 +181,13 @@ AsciiTraceHelper::~AsciiTraceHelper ()
}
Ptr<OutputStreamWrapper>
AsciiTraceHelper::CreateFileStream (std::string filename, std::string filemode)
AsciiTraceHelper::CreateFileStream (std::string filename, std::ios::openmode filemode)
{
NS_LOG_FUNCTION (filename << filemode);
std::ofstream *ofstream = new std::ofstream;
std::ios_base::openmode mode = std::ios_base::out | std::ios_base::trunc;
if (filemode == "a")
{
mode = std::ios_base::out | std::ios_base::app;
}
else if (filemode == "w")
{
mode = std::ios_base::out | std::ios_base::trunc;
}
else
{
NS_ABORT_MSG ("AsciiTraceHelper::CreateFileStream(): Unexpected file mode");
}
ofstream->open (filename.c_str (), mode);
ofstream->open (filename.c_str (), filemode);
NS_ABORT_MSG_UNLESS (ofstream->is_open (), "AsciiTraceHelper::CreateFileStream(): Unable to Open " <<
filename << " for mode " << filemode);

View File

@@ -84,7 +84,7 @@ public:
/**
* @brief Create and initialize a pcap file.
*/
Ptr<PcapFileWrapper> CreateFile (std::string filename, std::string filemode,
Ptr<PcapFileWrapper> CreateFile (std::string filename, std::ios::openmode filemode,
uint32_t dataLinkType, uint32_t snapLen = 65535, int32_t tzCorrection = 0);
/**
* @brief Hook a trace source to the default trace sink
@@ -156,7 +156,8 @@ public:
* that can solve the problem so we use one of those to carry the stream
* around and deal with the lifetime issues.
*/
Ptr<OutputStreamWrapper> CreateFileStream (std::string filename, std::string filemode = "w");
Ptr<OutputStreamWrapper> CreateFileStream (std::string filename,
std::ios::openmode filemode = std::ios::out);
/**
* @brief Hook a trace source to the default enqueue operation trace sink that

View File

@@ -480,7 +480,7 @@ WimaxHelper::EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
{
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename, "w");
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
uint32_t nodeid = nd->GetNode ()->GetId ();
uint32_t deviceid = nd->GetIfIndex ();
@@ -586,7 +586,7 @@ WimaxHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool exp
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", PcapHelper::DLT_EN10MB);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_EN10MB);
phy->TraceConnectWithoutContext ("Tx", MakeBoundCallback (&PcapSniffTxEvent, file));
phy->TraceConnectWithoutContext ("Rx", MakeBoundCallback (&PcapSniffRxEvent, file));

View File

@@ -409,7 +409,7 @@ YansWifiPhyHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bo
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, "w", m_pcapDlt);
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, m_pcapDlt);
phy->TraceConnectWithoutContext ("PromiscSnifferTx", MakeBoundCallback (&PcapSniffTxEvent, file));
phy->TraceConnectWithoutContext ("PromiscSnifferRx", MakeBoundCallback (&PcapSniffRxEvent, file));