A Discrete-Event Network Simulator
API
pcap-file-test-suite.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation;
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Author: Craig Dowell (craigdo@ee.washington.edu)
17 */
18
19#include <iostream>
20#include <cstdio>
21#include <cstdlib>
22#include <sstream>
23#include <cstring>
24
25#include "ns3/log.h"
26#include "ns3/test.h"
27#include "ns3/pcap-file.h"
28
29using namespace ns3;
30
31NS_LOG_COMPONENT_DEFINE ("pcap-file-test-suite");
32
33// ===========================================================================
34// Some utility functions for the tests.
35// ===========================================================================
36
37static uint16_t
38Swap (uint16_t val)
39{
40 return ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00);
41}
42
43static uint32_t
45{
46 return ((val >> 24) & 0x000000ff) | ((val >> 8) & 0x0000ff00) | ((val << 8) & 0x00ff0000) | ((val << 24) & 0xff000000);
47}
48
49static bool
50CheckFileExists (std::string filename)
51{
52 FILE * p = std::fopen (filename.c_str (), "rb");
53 if (p == 0)
54 {
55 return false;
56 }
57
58 std::fclose (p);
59 return true;
60}
61
62
63static bool
64CheckFileLength (std::string filename, uint64_t sizeExpected)
65{
66 FILE * p = std::fopen (filename.c_str (), "rb");
67 if (p == 0)
68 {
69 return false;
70 }
71
72 std::fseek (p, 0, SEEK_END);
73
74 uint64_t sizeActual = std::ftell (p);
75 std::fclose (p);
76
77 return sizeActual == sizeExpected;
78}
79
88{
89public:
91 virtual ~WriteModeCreateTestCase ();
92
93private:
94 virtual void DoSetup (void);
95 virtual void DoRun (void);
96 virtual void DoTeardown (void);
97
98 std::string m_testFilename;
99};
100
102 : TestCase ("Check to see that PcapFile::Open with mode std::ios::out works")
103{
104}
105
107{
108}
109
110void
112{
113 std::stringstream filename;
114 uint32_t n = rand ();
115 filename << n;
116 m_testFilename = CreateTempDirFilename (filename.str () + ".pcap");
117}
118
119void
121{
122 if (remove (m_testFilename.c_str ()))
123 {
124 NS_LOG_ERROR ("Failed to delete file " << m_testFilename);
125 }
126}
127
128void
130{
131 PcapFile f;
132
133 //
134 // Opening a new file in write mode should result in an empty file of the
135 // given name.
136 //
137 f.Open (m_testFilename, std::ios::out);
138
139 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename << ", \"w\") returns error");
140 f.Close ();
141
143 "Open (" << m_testFilename << ", \"std::ios::out\") does not create file");
145 "Open (" << m_testFilename << ", \"std::ios::out\") does not result in an empty file");
146
147 //
148 // Calling Init() on a file created with "std::ios::out" should result in a file just
149 // long enough to contain the pcap file header.
150 //
151 f.Open (m_testFilename, std::ios::out);
152 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
153 ", \"std::ios::out\") returns error");
154
155 f.Init (1234, 5678, 7);
156 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
157
158 f.Close ();
159
161 "Init () does not result in a file with a pcap file header");
162
163 //
164 // Opening an existing file in write mode should result in that file being
165 // emptied.
166 //
167 f.Open (m_testFilename, std::ios::out);
168 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
169 ", \"std::ios::out\") returns error");
170
171 f.Close ();
172
174 "Open (" << m_testFilename << ", \"w\") does not result in an empty file");
175
176 //
177 // Initialize the file again.
178 //
179 f.Open (m_testFilename, std::ios::out);
180 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false,
181 "Open (" << m_testFilename << ", \"w\") returns error");
182
183 f.Init (1234, 5678, 7);
184 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
185
186 //
187 // Now we should be able to write to it since it was opened in std::ios::out mode.
188 // This is just a permissions check so we don't actually look at the
189 // data.
190 //
191 uint8_t buffer[128];
192 memset (buffer, 0, sizeof(buffer));
193 f.Write (0, 0, buffer, 128);
194 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename <<
195 ") returns error");
196}
197
206{
207public:
209 virtual ~ReadModeCreateTestCase ();
210
211private:
212 virtual void DoSetup (void);
213 virtual void DoRun (void);
214 virtual void DoTeardown (void);
215
216 std::string m_testFilename;
217};
218
220 : TestCase ("Check to see that PcapFile::Open with mode std::ios::in works")
221{
222}
223
225{
226}
227
228void
230{
231 std::stringstream filename;
232 uint32_t n = rand ();
233 filename << n;
234 m_testFilename = CreateTempDirFilename (filename.str () + ".pcap");
235}
236
237void
239{
240 if (remove (m_testFilename.c_str ()))
241 {
242 NS_LOG_ERROR ("Failed to delete file " << m_testFilename);
243 }
244}
245
246void
248{
249 PcapFile f;
250
251 //
252 // Opening a non-existing file in read mode should result in an error.
253 //
254 f.Open (m_testFilename, std::ios::in);
255 NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-existing-filename " << m_testFilename <<
256 ", \"std::ios::in\") does not return error");
257 f.Close ();
258 f.Clear ();
260 ", \"std::ios::in\") unexpectedly created a file");
261
262 //
263 // Okay, now create an uninitialized file using previously tested operations
264 //
265 f.Open (m_testFilename, std::ios::out);
266 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (filename, \"std::ios::out\") returns error");
267 f.Close ();
268
269 //
270 // Opening this file should result in an error since it has no pcap file header.
271 //
272 f.Open (m_testFilename, std::ios::in);
273 NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-initialized-filename " << m_testFilename <<
274 ", \"std::ios::in\") does not return error");
275 f.Close ();
276 f.Clear ();
277
278 //
279 // Okay, now open that non-initialized file in write mode and initialize it
280 // Note that we open it in write mode to initialize it.
281 //
282 f.Open (m_testFilename, std::ios::out);
283 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
284 ", \"std::ios::out\") returns error");
285
286 f.Init (1234, 5678, 7);
287 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
288 f.Close ();
289
290 //
291 // Opening this file should now work since it has a pcap file header.
292 //
293 f.Open (m_testFilename, std::ios::in);
294 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (initialized-filename " << m_testFilename <<
295 ", \"std::ios::in\") returns error");
296
297 //
298 // Now we should not be able to write to it since it was opened in "r" mode
299 // even if it has been initialized..
300 //
301 uint8_t buffer[128];
302 f.Write (0, 0, buffer, 128);
303 NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Write (read-only-file " << m_testFilename <<
304 ") does not return error");
305 f.Close ();
306 f.Clear ();
307}
308
309#if 0
310// ===========================================================================
311// Test case to make sure that the Pcap File Object can open an existing pcap
312// file for appending.
313// ===========================================================================
314class AppendModeCreateTestCase : public TestCase
315{
316public:
317 AppendModeCreateTestCase ();
318 virtual ~AppendModeCreateTestCase ();
319
320private:
321 virtual void DoSetup (void);
322 virtual void DoRun (void);
323 virtual void DoTeardown (void);
324
325 std::string m_testFilename;
326};
327
328AppendModeCreateTestCase::AppendModeCreateTestCase ()
329 : TestCase ("Check to see that PcapFile::Open with mode std::ios::app works")
330{
331}
332
333AppendModeCreateTestCase::~AppendModeCreateTestCase ()
334{
335}
336
337void
338AppendModeCreateTestCase::DoSetup (void)
339{
340 std::stringstream filename;
341 uint32_t n = rand ();
342 filename << n;
343 m_testFilename = CreateTempDirFilename (filename.str () + ".pcap");
344}
345
346void
347AppendModeCreateTestCase::DoTeardown (void)
348{
349 if (remove (m_testFilename.c_str ()))
350 {
351 NS_LOG_ERROR ("Failed to delete file " << m_testFilename);
352 }
353}
354
355void
356AppendModeCreateTestCase::DoRun (void)
357{
358 PcapFile f;
359
360 //
361 // Opening a non-existing file in append mode should result in an error.
362 //
363 f.Open (m_testFilename, std::ios::out | std::ios::app);
364 NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-existing-filename " << m_testFilename <<
365 ", \"std::ios::app\") does not return error");
366 f.Close ();
367 f.Clear ();
368
369 NS_TEST_ASSERT_MSG_EQ (CheckFileExists (m_testFilename), false,
370 "Open (" << m_testFilename << ", \"std::ios::app\") unexpectedly created a file");
371
372 //
373 // Okay, now create an uninitialized file using previously tested operations
374 //
375 f.Open (m_testFilename, std::ios::out);
376 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
377 ", \"std::ios::out\") returns error");
378 f.Close ();
379
380 //
381 // Opening this file should result in an error since it has no pcap file header.
382 //
383 f.Open (m_testFilename, std::ios::out | std::ios::app);
384 NS_TEST_ASSERT_MSG_EQ (f.Fail (), true, "Open (non-initialized-filename " << m_testFilename <<
385 ", \"std::ios::app\") does not return error");
386 f.Close ();
387 f.Clear ();
388
389 //
390 // Okay, now open that non-initialized file in write mode and initialize it.
391 //
392 f.Open (m_testFilename, std::ios::out);
393 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (non-initialized-filename " << m_testFilename <<
394 ", \"std::ios::out\") returns error");
395
396 f.Init (1234, 5678, 7);
397 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
398 f.Close ();
399
400 //
401 // Opening this file should now work since it has a pcap file header.
402 //
403 f.Open (m_testFilename, std::ios::out | std::ios::app);
404 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (initialized-filename " << m_testFilename <<
405 ", \"std::ios::app\") returns error");
406
407 //
408 // We should be able to write to it since it was opened in "std::ios::app" mode.
409 //
410 uint8_t buffer[128];
411 memset (buffer, 0, sizeof(buffer));
412 f.Write (0, 0, buffer, 128);
413 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (append-mode-file " << m_testFilename << ") returns error");
414
415 f.Close ();
416}
417#endif
418
428{
429public:
431 virtual ~FileHeaderTestCase ();
432
433private:
434 virtual void DoSetup (void);
435 virtual void DoRun (void);
436 virtual void DoTeardown (void);
437
438 std::string m_testFilename;
439};
440
442 : TestCase ("Check to see that PcapFileHeader is managed correctly")
443{
444}
445
447{
448}
449
450void
452{
453 std::stringstream filename;
454 uint32_t n = rand ();
455 filename << n;
456 m_testFilename = CreateTempDirFilename (filename.str () + ".pcap");
457}
458
459void
461{
462 if (remove (m_testFilename.c_str ()))
463 {
464 NS_LOG_ERROR ("Failed to delete file " << m_testFilename);
465 }
466}
467
468void
470{
471 PcapFile f;
472
473 //
474 // Create an uninitialized file using previously tested operations
475 //
476 f.Open (m_testFilename, std::ios::out);
477 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
478 ", \"std::ios::out\") returns error");
479
480 //
481 // Initialize the pcap file header.
482 //
483 f.Init (1234, 5678, 7);
484 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false,
485 "Init (1234, 5678, 7) returns error");
486 f.Close ();
487
488 //
489 // Take a look and see what was done to the file
490 //
491 FILE *p = std::fopen (m_testFilename.c_str (), "r+b");
492 NS_TEST_ASSERT_MSG_NE (p, 0, "fopen(" << m_testFilename << ") should have been able to open a correctly created pcap file");
493
494 uint32_t val32;
495 uint16_t val16;
496
497 //
498 // Because the regression tests require that pcap file output be compared
499 // byte-by-byte, we had to decide on a single format for written pcap files.
500 // This was little endian. So we have to do something special with big-
501 // endian machines here.
502 //
503 // When a big endian machine writes a pcap file, it is forced into swap
504 // mode and actually writes little endian files. This is automagically
505 // fixed up when using a PcapFile to read the values, but when a big-
506 // endian machine reads these values directly, they will be swapped.
507 //
508 // We can remove this nonsense when we get rid of the pcap-file-comparison
509 // regression tests.
510 //
511 // So, determine the endian-ness of the running system, and if we're on
512 // a big-endian machine, swap all of the results below before checking.
513 //
514 union {
515 uint32_t a;
516 uint8_t b[4];
517 } u;
518
519 u.a = 1;
520 bool bigEndian = u.b[3];
521
522 size_t result = std::fread (&val32, sizeof(val32), 1, p);
523 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() magic number");
524 if (bigEndian) val32 = Swap (val32);
525 NS_TEST_ASSERT_MSG_EQ (val32, 0xa1b2c3d4, "Magic number written incorrectly");
526
527 result = std::fread (&val16, sizeof(val16), 1, p);
528 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() version major");
529 if (bigEndian) val16 = Swap (val16);
530 NS_TEST_ASSERT_MSG_EQ (val16, 2, "Version major written incorrectly");
531
532 result = std::fread (&val16, sizeof(val16), 1, p);
533 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() version minor");
534 if (bigEndian) val16 = Swap (val16);
535 NS_TEST_ASSERT_MSG_EQ (val16, 4, "Version minor written incorrectly");
536
537 result = std::fread (&val32, sizeof(val32), 1, p);
538 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() time zone correction");
539 if (bigEndian) val32 = Swap (val32);
540 NS_TEST_ASSERT_MSG_EQ (val32, 7, "Version minor written incorrectly");
541
542 result = std::fread (&val32, sizeof(val32), 1, p);
543 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() sig figs");
544 if (bigEndian) val32 = Swap (val32);
545 NS_TEST_ASSERT_MSG_EQ (val32, 0, "Sig figs written incorrectly");
546
547 result = std::fread (&val32, sizeof(val32), 1, p);
548 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() snap length");
549 if (bigEndian) val32 = Swap (val32);
550 NS_TEST_ASSERT_MSG_EQ (val32, 5678, "Snap length written incorrectly");
551
552 result = std::fread (&val32, sizeof(val32), 1, p);
553 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() data link type");
554 if (bigEndian) val32 = Swap (val32);
555 NS_TEST_ASSERT_MSG_EQ (val32, 1234, "Data length type written incorrectly");
556
557 std::fclose (p);
558 p = 0;
559
560 //
561 // We wrote a little-endian file out correctly, now let's see if we can read
562 // it back in correctly.
563 //
564 // As mentioned above, when a big endian machine writes a pcap file, it is
565 // forced into swap mode and actually writes little endian files. This is
566 // automagically fixed up when using a PcapFile to read the values, so we
567 // don't have to do anything special here.
568 //
569 f.Open (m_testFilename, std::ios::in);
570 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (existing-initialized-file " << m_testFilename <<
571 ", \"std::ios::in\") returns error");
572
573 NS_TEST_ASSERT_MSG_EQ (f.GetMagic (), 0xa1b2c3d4, "Read back magic number incorrectly");
574 NS_TEST_ASSERT_MSG_EQ (f.GetVersionMajor (), 2, "Read back version major incorrectly");
575 NS_TEST_ASSERT_MSG_EQ (f.GetVersionMinor (), 4, "Read back version minor incorrectly");
576 NS_TEST_ASSERT_MSG_EQ (f.GetTimeZoneOffset (), 7, "Read back time zone offset incorrectly");
577 NS_TEST_ASSERT_MSG_EQ (f.GetSigFigs (), 0, "Read back sig figs incorrectly");
578 NS_TEST_ASSERT_MSG_EQ (f.GetSnapLen (), 5678, "Read back snap len incorrectly");
579 NS_TEST_ASSERT_MSG_EQ (f.GetDataLinkType (), 1234, "Read back data link type incorrectly");
580 f.Close ();
581
582 //
583 // Re-open the file to erase its contents.
584 //
585 f.Open (m_testFilename, std::ios::out);
586 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
587 ", \"std::ios::out\") returns error");
588
589 //
590 // Initialize the pcap file header, turning on swap mode manually to force
591 // the pcap file header to be written out in foreign-endian form, whichever
592 // endian-ness that might be. Since big-endian machines are automatically
593 // forced into swap mode, the <true> parameter to f.Init() below is actually
594 // a no-op and we're always writing foreign-endian files. In that case,
595 // this test case is really just a duplicate of the previous.
596 //
597 f.Init (1234, 5678, 7, true);
598 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1234, 5678, 7) returns error");
599 f.Close ();
600
601 //
602 // Take a look and see what was done to the file. Everything should now
603 // appear byte-swapped.
604 //
605 p = std::fopen (m_testFilename.c_str (), "r+b");
606 NS_TEST_ASSERT_MSG_NE (p, 0, "fopen(" << m_testFilename << ") should have been able to open a correctly created pcap file");
607
608 result = std::fread (&val32, sizeof(val32), 1, p);
609 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() magic number");
610 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (0xa1b2c3d4)), "Magic number written incorrectly");
611
612 result = std::fread (&val16, sizeof(val16), 1, p);
613 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() version major");
614 NS_TEST_ASSERT_MSG_EQ (val16, Swap (uint16_t (2)), "Version major written incorrectly");
615
616 result = std::fread (&val16, sizeof(val16), 1, p);
617 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() version minor");
618 NS_TEST_ASSERT_MSG_EQ (val16, Swap (uint16_t (4)), "Version minor written incorrectly");
619
620 result = std::fread (&val32, sizeof(val32), 1, p);
621 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() time zone correction");
622 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (7)), "Version minor written incorrectly");
623
624 result = std::fread (&val32, sizeof(val32), 1, p);
625 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() sig figs");
626 NS_TEST_ASSERT_MSG_EQ (val32, 0, "Sig figs written incorrectly");
627
628 result = std::fread (&val32, sizeof(val32), 1, p);
629 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() snap length");
630 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (5678)), "Snap length written incorrectly");
631
632 result = std::fread (&val32, sizeof(val32), 1, p);
633 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() data link type");
634 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (1234)), "Data length type written incorrectly");
635
636 std::fclose (p);
637 p = 0;
638
639 //
640 // We wrote an opposite-endian file out correctly, now let's see if we can read
641 // it back in correctly. Again, in the case of a big-endian machine, we already
642 // did this test and it is just a duplicate. What we don't test on a big endian
643 // machine is writing out a big-endian file by default, but we can't do that
644 // since it breaks regression testing.
645 //
646 f.Open (m_testFilename, std::ios::in);
647 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (existing-initialized-file " << m_testFilename <<
648 ", \"std::ios::in\") returns error");
649
650 NS_TEST_ASSERT_MSG_EQ (f.GetSwapMode (), true, "Byte-swapped file not correctly indicated");
651
652 NS_TEST_ASSERT_MSG_EQ (f.GetMagic (), 0xa1b2c3d4, "Read back magic number incorrectly");
653 NS_TEST_ASSERT_MSG_EQ (f.GetVersionMajor (), 2, "Read back version major incorrectly");
654 NS_TEST_ASSERT_MSG_EQ (f.GetVersionMinor (), 4, "Read back version minor incorrectly");
655 NS_TEST_ASSERT_MSG_EQ (f.GetTimeZoneOffset (), 7, "Read back time zone offset incorrectly");
656 NS_TEST_ASSERT_MSG_EQ (f.GetSigFigs (), 0, "Read back sig figs incorrectly");
657 NS_TEST_ASSERT_MSG_EQ (f.GetSnapLen (), 5678, "Read back snap len incorrectly");
658 NS_TEST_ASSERT_MSG_EQ (f.GetDataLinkType (), 1234, "Read back data link type incorrectly");
659
660 f.Close ();
661}
662
672{
673public:
675 virtual ~RecordHeaderTestCase ();
676
677private:
678 virtual void DoSetup (void);
679 virtual void DoRun (void);
680 virtual void DoTeardown (void);
681
682 std::string m_testFilename;
683};
684
686 : TestCase ("Check to see that PcapRecordHeader is managed correctly")
687{
688}
689
691{
692}
693
694void
696{
697 std::stringstream filename;
698 uint32_t n = rand ();
699 filename << n;
700 m_testFilename = CreateTempDirFilename (filename.str () + ".pcap");
701}
702
703void
705{
706 if (remove (m_testFilename.c_str ()))
707 {
708 NS_LOG_ERROR ("Failed to delete file " << m_testFilename);
709 }
710}
711
712void
714{
715 PcapFile f;
716
717 //
718 // Create an uninitialized file using previously tested operations
719 //
720 f.Open (m_testFilename, std::ios::out);
721 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
722 ", \"std::ios::out\") returns error");
723
724 //
725 // Initialize the pcap file header.
726 //
727 f.Init (37, 43, -7);
728 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (37, 43, -7) returns error");
729
730 //
731 // Initialize a buffer with a counting pattern to check the data later.
732 //
733 uint8_t bufferOut[128];
734 for (uint32_t i = 0; i < 128; ++i)
735 {
736 bufferOut[i] = i;
737 }
738
739 //
740 // Now we should be able to write a packet to it since it was opened in "w"
741 // mode. The packet data written should be limited to 43 bytes in length
742 // by the Init() call above.
743 //
744 f.Write (1234, 5678, bufferOut, 128);
745 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename << ") returns error");
746 f.Close ();
747
748 //
749 // Let's peek into the file and see what actually went out for that
750 // packet.
751 //
752 FILE *p = std::fopen (m_testFilename.c_str (), "r+b");
753 NS_TEST_ASSERT_MSG_NE (p, 0, "fopen() should have been able to open a correctly created pcap file");
754
755 //
756 // A pcap file header takes up 24 bytes, a pcap record header takes up 16 bytes
757 // and we wrote in 43 bytes, so the file must be 83 bytes long. Let's just
758 // double check that this is exactly what happened.
759 //
760 std::fseek (p, 0, SEEK_END);
761 uint64_t size = std::ftell (p);
762 NS_TEST_ASSERT_MSG_EQ (size, 83, "Pcap file with one 43 byte packet is incorrect size");
763
764 //
765 // A pcap file header takes up 24 bytes, so we should see a pcap record header
766 // starting there in the file. We've tested this all before so we just assume
767 // it's all right and just seek to just past that point..
768 //
769 std::fseek (p, 24, SEEK_SET);
770
771 uint32_t val32;
772
773 //
774 // Because the regression tests require that pcap file output be compared
775 // byte-by-byte, we had to decide on a single format for written pcap files.
776 // This was little endian. So we have to do something special with big-
777 // endian machines here.
778 //
779 // When a big endian machine writes a pcap file, it is forced into swap
780 // mode and actually writes little endian files. This is automagically
781 // fixed up when using a PcapFile to read the values, but when a big-
782 // endian machine reads these values directly, they will be swapped.
783 //
784 // We can remove this nonsense when we get rid of the pcap-file-comparison
785 // regression tests.
786 //
787 // So, determine the endian-ness of the running system, and if we're on
788 // a big-endian machine, swap all of the results below before checking.
789 //
790 union {
791 uint32_t a;
792 uint8_t b[4];
793 } u;
794
795 u.a = 1;
796 bool bigEndian = u.b[3];
797
798 size_t result = std::fread (&val32, sizeof(val32), 1, p);
799 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() seconds timestamp");
800 if (bigEndian) val32 = Swap (val32);
801 NS_TEST_ASSERT_MSG_EQ (val32, 1234, "Seconds timestamp written incorrectly");
802
803 result = std::fread (&val32, sizeof(val32), 1, p);
804 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() microseconds timestamp");
805 if (bigEndian) val32 = Swap (val32);
806 NS_TEST_ASSERT_MSG_EQ (val32, 5678, "Microseconds timestamp written incorrectly");
807
808 result = std::fread (&val32, sizeof(val32), 1, p);
809 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() included length");
810 if (bigEndian) val32 = Swap (val32);
811 NS_TEST_ASSERT_MSG_EQ (val32, 43, "Included length written incorrectly");
812
813 result = std::fread (&val32, sizeof(val32), 1, p);
814 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() actual length");
815 if (bigEndian) val32 = Swap (val32);
816 NS_TEST_ASSERT_MSG_EQ (val32, 128, "Actual length written incorrectly");
817
818 //
819 // Take a look and see what went out into the file. The packet data
820 // should be unchanged (unswapped).
821 //
822 uint8_t bufferIn[128];
823
824 result = std::fread (bufferIn, 1, 43, p);
825 NS_TEST_ASSERT_MSG_EQ (result, 43, "Unable to fread() packet data of expected length");
826
827 for (uint32_t i = 0; i < 43; ++i)
828 {
829 NS_TEST_ASSERT_MSG_EQ (bufferIn[i], bufferOut[i], "Incorrect packet data written");
830 }
831
832 std::fclose (p);
833 p = 0;
834
835 //
836 // Let's see if the PcapFile object can figure out how to do the same thing and
837 // correctly read in a packet.
838 //
839 f.Open (m_testFilename, std::ios::in);
840 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
841 ", \"std::ios::in\") of existing good file returns error");
842
843 uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
844
845 f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
846 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good packet returns error");
847 NS_TEST_ASSERT_MSG_EQ (tsSec, 1234, "Incorrectly read seconds timestamp from known good packet");
848 NS_TEST_ASSERT_MSG_EQ (tsUsec, 5678, "Incorrectly read microseconds timestamp from known good packet");
849 NS_TEST_ASSERT_MSG_EQ (inclLen, 43, "Incorrectly read included length from known good packet");
850 NS_TEST_ASSERT_MSG_EQ (origLen, 128, "Incorrectly read original length from known good packet");
851 NS_TEST_ASSERT_MSG_EQ (readLen, 43, "Incorrectly constructed actual read length from known good packet given buffer size");
852 f.Close ();
853
854 //
855 // Did the data come back correctly?
856 //
857 for (uint32_t i = 0; i < 43; ++i)
858 {
859 NS_TEST_ASSERT_MSG_EQ (bufferIn[i], bufferOut[i], "Incorrect packet data read from known good packet");
860 }
861
862 //
863 // We have to check to make sure that the pcap record header is swapped
864 // correctly. Since big-endian machines are automatically forced into
865 // swap mode, the <true> parameter to f.Init() below is actually
866 // a no-op and we're always writing foreign-endian files. In that case,
867 // this test case is really just a duplicate of the previous.
868 //
869 // Open the file in write mode to clear the data.
870 //
871 f.Open (m_testFilename, std::ios::out);
872 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
873 ", \"std::ios::out\") returns error");
874
875 //
876 // Initialize the pcap file header, forcing the object into swap mode.
877 //
878 f.Init (37, 43, -7, true);
879 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (37, 43, -7) returns error");
880
881 //
882 // Now we should be able to write a packet to it since it was opened in "w"
883 // mode. The packet data written should be limited to 43 bytes in length
884 // by the Init() call above.
885 //
886 f.Write (1234, 5678, bufferOut, 128);
887 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Write (write-only-file " << m_testFilename << ") returns error");
888 f.Close ();
889
890 //
891 // Let's peek into the file and see what actually went out for that
892 // packet.
893 //
894 p = std::fopen (m_testFilename.c_str (), "r+b");
895 NS_TEST_ASSERT_MSG_NE (p, 0, "fopen() should have been able to open a correctly created pcap file");
896
897 //
898 // A pcap file header takes up 24 bytes, a pcap record header takes up 16 bytes
899 // and we wrote in 43 bytes, so the file must be 83 bytes long. Let's just
900 // double check that this is exactly what happened.
901 //
902 std::fseek (p, 0, SEEK_END);
903 size = std::ftell (p);
904 NS_TEST_ASSERT_MSG_EQ (size, 83, "Pcap file with one 43 byte packet is incorrect size");
905
906 //
907 // A pcap file header takes up 24 bytes, so we should see a pcap record header
908 // starting there in the file. We've tested this all before so we just assume
909 // it's all right and just seek past it.
910 //
911 result = std::fseek (p, 24, SEEK_SET);
912 NS_TEST_ASSERT_MSG_EQ (result, 0, "Failed seeking past pcap header");
913
914 result = std::fread (&val32, sizeof(val32), 1, p);
915 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() seconds timestamp");
916 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (1234)), "Swapped seconds timestamp written incorrectly");
917
918 result = std::fread (&val32, sizeof(val32), 1, p);
919 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() microseconds timestamp");
920 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (5678)), "Swapped microseconds timestamp written incorrectly");
921
922 result = std::fread (&val32, sizeof(val32), 1, p);
923 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() included length");
924 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (43)), "Swapped included length written incorrectly");
925
926 result = std::fread (&val32, sizeof(val32), 1, p);
927 NS_TEST_ASSERT_MSG_EQ (result, 1, "Unable to fread() actual length");
928 NS_TEST_ASSERT_MSG_EQ (val32, Swap (uint32_t (128)), "Swapped Actual length written incorrectly");
929
930 //
931 // Take a look and see what went out into the file. The packet data
932 // should be unchanged (unswapped).
933 //
934 result = std::fread (bufferIn, 1, 43, p);
935 NS_TEST_ASSERT_MSG_EQ (result, 43, "Unable to fread() packet data of expected length");
936
937 for (uint32_t i = 0; i < 43; ++i)
938 {
939 NS_TEST_ASSERT_MSG_EQ (bufferIn[i], bufferOut[i], "Incorrect packet data written");
940 }
941
942 std::fclose (p);
943 p = 0;
944
945 //
946 // Let's see if the PcapFile object can figure out how to do the same thing and
947 // correctly read in a packet. The record header info should come back to us
948 // swapped back into correct form.
949 //
950 f.Open (m_testFilename, std::ios::in);
951 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << m_testFilename <<
952 ", \"std::ios::in\") of existing good file returns error");
953
954 f.Read (bufferIn, sizeof(bufferIn), tsSec, tsUsec, inclLen, origLen, readLen);
955 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good packet returns error");
956 NS_TEST_ASSERT_MSG_EQ (tsSec, 1234, "Incorrectly read seconds timestamp from known good packet");
957 NS_TEST_ASSERT_MSG_EQ (tsUsec, 5678, "Incorrectly read microseconds timestamp from known good packet");
958 NS_TEST_ASSERT_MSG_EQ (inclLen, 43, "Incorrectly read included length from known good packet");
959 NS_TEST_ASSERT_MSG_EQ (origLen, 128, "Incorrectly read original length from known good packet");
960 NS_TEST_ASSERT_MSG_EQ (readLen, 43, "Incorrectly constructed actual read length from known good packet given buffer size");
961
962 //
963 // Did the data come back correctly (unchanged / unswapped)?
964 //
965 for (uint32_t i = 0; i < 43; ++i)
966 {
967 NS_TEST_ASSERT_MSG_EQ (bufferIn[i], bufferOut[i], "Incorrect packet data read from known good packet");
968 }
969
970 f.Close ();
971}
972
981{
982public:
984 virtual ~ReadFileTestCase ();
985
986private:
987 virtual void DoSetup (void);
988 virtual void DoRun (void);
989 virtual void DoTeardown (void);
990
991 std::string m_testFilename;
992};
993
995 : TestCase ("Check to see that PcapFile can read out a known good pcap file")
996{
997}
998
1000{
1001}
1002
1003void
1005{
1006}
1007
1008void
1010{
1011}
1012
1013static const uint32_t N_KNOWN_PACKETS = 6;
1014static const uint32_t N_PACKET_BYTES = 16;
1015
1019typedef struct PACKET_ENTRY {
1025} PacketEntry;
1026
1027static const PacketEntry knownPackets[] = {
1028 { 2, 3696, 46, 46, { 0x0001, 0x0800, 0x0604, 0x0001, 0x0000, 0x0000, 0x0003, 0x0a01,
1029 0x0201, 0xffff, 0xffff, 0xffff, 0x0a01, 0x0204, 0x0000, 0x0000}},
1030 { 2, 3707, 46, 46, { 0x0001, 0x0800, 0x0604, 0x0002, 0x0000, 0x0000, 0x0006, 0x0a01,
1031 0x0204, 0x0000, 0x0000, 0x0003, 0x0a01, 0x0201, 0x0000, 0x0000}},
1032 { 2, 3801, 1070, 1070, { 0x4500, 0x041c, 0x0000, 0x0000, 0x3f11, 0x0000, 0x0a01, 0x0101,
1033 0x0a01, 0x0204, 0xc001, 0x0009, 0x0408, 0x0000, 0x0000, 0x0000}},
1034 { 2, 3811, 46, 46, { 0x0001, 0x0800, 0x0604, 0x0001, 0x0000, 0x0000, 0x0006, 0x0a01,
1035 0x0204, 0xffff, 0xffff, 0xffff, 0x0a01, 0x0201, 0x0000, 0x0000}},
1036 { 2, 3822, 46, 46, { 0x0001, 0x0800, 0x0604, 0x0002, 0x0000, 0x0000, 0x0003, 0x0a01,
1037 0x0201, 0x0000, 0x0000, 0x0006, 0x0a01, 0x0204, 0x0000, 0x0000}},
1038 { 2, 3915, 1070, 1070, { 0x4500, 0x041c, 0x0000, 0x0000, 0x4011, 0x0000, 0x0a01, 0x0204,
1039 0x0a01, 0x0101, 0x0009, 0xc001, 0x0408, 0x0000, 0x0000, 0x0000}}
1040};
1041
1042
1043void
1045{
1046 PcapFile f;
1047
1048 //
1049 //
1050 std::string filename = CreateDataDirFilename ("known.pcap");
1051 f.Open (filename, std::ios::in);
1052 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << filename <<
1053 ", \"std::ios::in\") returns error");
1054
1055 //
1056 // We are going to read out the file header and all of the packets to make
1057 // sure that we read what we know, a priori, to be there.
1058 //
1059 // The packet data was gotten using "tcpdump -nn -tt -r known.pcap -x"
1060 // and the timestamp and first 32 bytes of the resulting dump were
1061 // duplicated in the structure above.
1062 //
1063 uint8_t data[N_PACKET_BYTES];
1064 uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
1065
1066 for (uint32_t i = 0; i < N_KNOWN_PACKETS; ++i)
1067 {
1068 PacketEntry const & p = knownPackets[i];
1069
1070 f.Read (data, sizeof(data), tsSec, tsUsec, inclLen, origLen, readLen);
1071 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Read() of known good pcap file returns error");
1072 NS_TEST_ASSERT_MSG_EQ (tsSec, p.tsSec, "Incorrectly read seconds timestap from known good pcap file");
1073 NS_TEST_ASSERT_MSG_EQ (tsUsec, p.tsUsec, "Incorrectly read microseconds timestap from known good pcap file");
1074 NS_TEST_ASSERT_MSG_EQ (inclLen, p.inclLen, "Incorrectly read included length from known good packet");
1075 NS_TEST_ASSERT_MSG_EQ (origLen, p.origLen, "Incorrectly read original length from known good packet");
1076 NS_TEST_ASSERT_MSG_EQ (readLen, N_PACKET_BYTES, "Incorrect actual read length from known good packet given buffer size");
1077 }
1078
1079 //
1080 // The file should now be at EOF since we've read all of the packets.
1081 // Another packet read should return an error.
1082 //
1083 f.Read (data, 1, tsSec, tsUsec, inclLen, origLen, readLen);
1084 NS_TEST_ASSERT_MSG_EQ (f.Eof (), true, "Read() of known good pcap file at EOF does not return error");
1085
1086 f.Close ();
1087}
1088
1096{
1097public:
1098 DiffTestCase ();
1099
1100private:
1101 virtual void DoRun (void);
1102};
1103
1105 : TestCase ("Check that PcapFile::Diff works as expected")
1106{
1107}
1108
1109void
1111{
1112 //
1113 // Check that PcapDiff(file, file) is false
1114 //
1115 std::string filename = CreateDataDirFilename ("known.pcap");
1116 uint32_t sec (0), usec (0), packets (0);
1117 bool diff = PcapFile::Diff (filename, filename, sec, usec, packets);
1118 NS_TEST_EXPECT_MSG_EQ (diff, false, "PcapDiff(file, file) must always be false");
1119
1120 //
1121 // Create different PCAP file (with the same timestamps, but different packets) and check that it is indeed different
1122 //
1123 std::string filename2 = CreateTempDirFilename ("different.pcap");
1124 PcapFile f;
1125
1126 f.Open (filename2, std::ios::out);
1127 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << filename2 << ", \"std::ios::out\") returns error");
1128 f.Init (1, N_PACKET_BYTES);
1129 NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Init (1, " << N_PACKET_BYTES << ") returns error");
1130
1131 for (uint32_t i = 0; i < N_KNOWN_PACKETS; ++i)
1132 {
1133 PacketEntry const & p = knownPackets[i];
1134
1135 f.Write (p.tsSec, p.tsUsec, (uint8_t const *)p.data, p.origLen);
1136 NS_TEST_EXPECT_MSG_EQ (f.Fail (), false, "Write must not fail");
1137 }
1138 f.Close ();
1139
1140 packets = 0;
1141 diff = PcapFile::Diff (filename, filename2, sec, usec, packets);
1142 NS_TEST_EXPECT_MSG_EQ (diff, true, "PcapDiff(file, file2) must be true");
1143 NS_TEST_EXPECT_MSG_EQ (sec, 2, "Files are different from 2.3696 seconds");
1144 NS_TEST_EXPECT_MSG_EQ (usec, 3696, "Files are different from 2.3696 seconds");
1145}
1146
1154{
1155public:
1157};
1158
1160 : TestSuite ("pcap-file", UNIT)
1161{
1162 SetDataDir (NS_TEST_SOURCEDIR);
1163 AddTestCase (new WriteModeCreateTestCase, TestCase::QUICK);
1164 AddTestCase (new ReadModeCreateTestCase, TestCase::QUICK);
1165 //AddTestCase (new AppendModeCreateTestCase, TestCase::QUICK);
1166 AddTestCase (new FileHeaderTestCase, TestCase::QUICK);
1167 AddTestCase (new RecordHeaderTestCase, TestCase::QUICK);
1168 AddTestCase (new ReadFileTestCase, TestCase::QUICK);
1169 AddTestCase (new DiffTestCase, TestCase::QUICK);
1170}
1171
double f(double x, void *params)
Definition: 80211b.c:70
Test case to make sure that the Pcap::Diff method works as expected.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Test case to make sure that the Pcap File Object can write out correct pcap file headers in both endi...
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
std::string m_testFilename
File name.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
PCAP file utils TestSuite.
Test case to make sure that the Pcap File Object can read out the contents of a known good pcap file.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
std::string m_testFilename
File name.
Test case to make sure that the Pcap File Object can open an existing pcap file.
std::string m_testFilename
File name.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
Test case to make sure that the Pcap File Object can write pcap packet records in both endian cases,...
std::string m_testFilename
File name.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Test case to make sure that the Pcap File Object can do its most basic job and create an empty pcap f...
virtual void DoRun(void)
Implementation to actually run this TestCase.
std::string m_testFilename
File name.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
A class representing a pcap file.
Definition: pcap-file.h:43
encapsulates test code
Definition: test.h:994
std::string CreateDataDirFilename(std::string filename)
Construct the full path to a file in the data directory.
Definition: test.cc:412
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:472
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:477
std::string CreateTempDirFilename(std::string filename)
Construct the full path to a file in a temporary directory.
Definition: test.cc:430
virtual void DoRun(void)=0
Implementation to actually run this TestCase.
void SetDataDir(std::string directory)
Set the data directory where reference trace files can be found.
Definition: test.cc:465
A suite of tests to run.
Definition: test.h:1188
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:257
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:141
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:542
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const uint32_t N_KNOWN_PACKETS
static bool CheckFileExists(std::string filename)
static bool CheckFileLength(std::string filename, uint64_t sizeExpected)
static uint16_t Swap(uint16_t val)
static const PacketEntry knownPackets[]
static PcapFileTestSuite pcapFileTestSuite
Static variable for test initialization.
static const uint32_t N_PACKET_BYTES
uint8_t data[writeSize]
PCAP Packet structure.
uint32_t tsUsec
Time (micro seconds part)
uint32_t origLen
length of the original packet
uint16_t data[N_PACKET_BYTES]
Packet data.
uint32_t tsSec
Time (seconds part)
uint32_t inclLen
Length of the entry in the PCAP.