A Discrete-Event Network Simulator
API
tcp-header-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Natale Patriciello <natale.patriciello@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  */
18 
19 #define __STDC_LIMIT_MACROS
20 #include "ns3/buffer.h"
21 #include "ns3/core-module.h"
22 #include "ns3/tcp-header.h"
23 #include "ns3/tcp-option-rfc793.h"
24 #include "ns3/test.h"
25 
26 #include <stdint.h>
27 
28 using namespace ns3;
29 
30 #define GET_RANDOM_UINT32(RandomVariable) \
31  static_cast<uint32_t>(RandomVariable->GetInteger(0, UINT32_MAX))
32 
33 #define GET_RANDOM_UINT16(RandomVariable) \
34  static_cast<uint16_t>(RandomVariable->GetInteger(0, UINT16_MAX))
35 
36 #define GET_RANDOM_UINT8(RandomVariable) \
37  static_cast<uint8_t>(RandomVariable->GetInteger(0, UINT8_MAX))
38 
39 #define GET_RANDOM_UINT6(RandomVariable) \
40  static_cast<uint8_t>(RandomVariable->GetInteger(0, UINT8_MAX >> 2))
41 
48 {
49  public:
54  TcpHeaderGetSetTestCase(std::string name);
55 
56  protected:
57  private:
58  void DoRun() override;
59  void DoTeardown() override;
60 };
61 
63  : TestCase(name)
64 {
65 }
66 
67 void
69 {
70  uint16_t sourcePort; // Source port
71  uint16_t destinationPort; // Destination port
72  SequenceNumber32 sequenceNumber; // Sequence number
73  SequenceNumber32 ackNumber; // ACK number
74  uint8_t flags; // Flags (really a uint6_t)
75  uint16_t windowSize; // Window size
76  uint16_t urgentPointer; // Urgent pointer
77  TcpHeader header;
78  Buffer buffer;
79 
80  Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
81  for (uint32_t i = 0; i < 1000; ++i)
82  {
83  sourcePort = GET_RANDOM_UINT16(x);
84  destinationPort = GET_RANDOM_UINT16(x);
85  sequenceNumber = SequenceNumber32(GET_RANDOM_UINT32(x));
86  ackNumber = SequenceNumber32(GET_RANDOM_UINT32(x));
87  flags = GET_RANDOM_UINT6(x);
88  windowSize = GET_RANDOM_UINT16(x);
89  urgentPointer = GET_RANDOM_UINT16(x);
90 
91  header.SetSourcePort(sourcePort);
92  header.SetDestinationPort(destinationPort);
93  header.SetSequenceNumber(sequenceNumber);
94  header.SetAckNumber(ackNumber);
95  header.SetFlags(flags);
96  header.SetWindowSize(windowSize);
97  header.SetUrgentPointer(urgentPointer);
98 
100  5,
101  "TcpHeader without option is"
102  " not 5 word");
103 
104  buffer.AddAtStart(header.GetSerializedSize());
105  header.Serialize(buffer.Begin());
106 
107  NS_TEST_ASSERT_MSG_EQ(sourcePort, header.GetSourcePort(), "Different source port found");
108  NS_TEST_ASSERT_MSG_EQ(destinationPort,
109  header.GetDestinationPort(),
110  "Different destination port found");
111  NS_TEST_ASSERT_MSG_EQ(sequenceNumber,
112  header.GetSequenceNumber(),
113  "Different sequence number found");
114  NS_TEST_ASSERT_MSG_EQ(ackNumber, header.GetAckNumber(), "Different ack number found");
115  NS_TEST_ASSERT_MSG_EQ(flags, header.GetFlags(), "Different flags found");
116  NS_TEST_ASSERT_MSG_EQ(windowSize, header.GetWindowSize(), "Different window size found");
117  NS_TEST_ASSERT_MSG_EQ(urgentPointer,
118  header.GetUrgentPointer(),
119  "Different urgent pointer found");
120 
122  5,
123  "TcpHeader without option is"
124  " not 5 word");
125 
126  TcpHeader copyHeader;
127 
128  copyHeader.Deserialize(buffer.Begin());
129 
130  NS_TEST_ASSERT_MSG_EQ(sourcePort,
131  copyHeader.GetSourcePort(),
132  "Different source port found in deserialized header");
133  NS_TEST_ASSERT_MSG_EQ(destinationPort,
134  copyHeader.GetDestinationPort(),
135  "Different destination port found in deserialized header");
136  NS_TEST_ASSERT_MSG_EQ(sequenceNumber,
137  copyHeader.GetSequenceNumber(),
138  "Different sequence number found in deserialized header");
139  NS_TEST_ASSERT_MSG_EQ(ackNumber,
140  copyHeader.GetAckNumber(),
141  "Different ack number found in deserialized header");
142  NS_TEST_ASSERT_MSG_EQ(flags,
143  copyHeader.GetFlags(),
144  "Different flags found in deserialized header");
145  NS_TEST_ASSERT_MSG_EQ(windowSize,
146  copyHeader.GetWindowSize(),
147  "Different window size found in deserialized header");
148  NS_TEST_ASSERT_MSG_EQ(urgentPointer,
149  copyHeader.GetUrgentPointer(),
150  "Different urgent pointer found in deserialized header");
151  }
152 }
153 
154 void
156 {
157 }
158 
165 {
166  public:
171  TcpHeaderWithRFC793OptionTestCase(std::string name);
172 
173  private:
174  void DoRun() override;
175  void DoTeardown() override;
176 
180  void OneOptionAtTime();
184  void CheckNoPadding();
189 };
190 
192  : TestCase(name)
193 {
194 }
195 
196 void
198 {
199  OneOptionAtTime();
200  CheckNoPadding();
202 }
203 
204 void
206 {
207  TcpHeader source;
208  TcpHeader destination;
209  TcpOptionNOP temp;
210  Buffer buffer;
211  buffer.AddAtStart(40);
212 
213  Buffer::Iterator i = buffer.Begin();
214  source.AppendOption(&temp);
215 
216  source.Serialize(i);
217 
218  i.ReadU8();
219  i.WriteU8(59);
220 
221  i = buffer.Begin();
222  destination.Deserialize(i);
223 
224  NS_TEST_ASSERT_MSG_EQ(destination.HasOption(59), false, "Kind 59 registered");
225 }
226 
227 void
229 {
230  {
231  TcpOptionNOP oNop1;
232  TcpOptionNOP oNop2;
233  TcpOptionNOP oNop3;
234  TcpOptionNOP oNop4;
235  TcpHeader header;
236  Buffer buffer;
237 
239  5,
240  "TcpHeader without option is"
241  " not 5 word");
242  header.AppendOption(&oNop1);
243  header.AppendOption(&oNop2);
244  header.AppendOption(&oNop3);
245  header.AppendOption(&oNop4);
246 
248  6,
249  "Four byte added as option "
250  "are not a word");
252  24,
253  "Four byte added as option "
254  "are not a word");
255 
256  buffer.AddAtStart(header.GetSerializedSize());
257  header.Serialize(buffer.Begin());
258 
260  buffer.GetSize(),
261  "Header not correctly serialized");
262 
263  // Inserted 4 byte NOP, no padding should be present
264  Buffer::Iterator i = buffer.Begin();
265  i.Next(20);
266 
267  for (uint32_t j = 0; j < 4; ++j)
268  {
269  std::stringstream ss;
270  ss << j;
271  uint8_t value = i.ReadU8();
272  NS_TEST_ASSERT_MSG_EQ(value, TcpOption::NOP, "NOP not present at position " + ss.str());
273  }
274  }
275 }
276 
277 void
279 {
280  {
281  TcpOptionEnd oEnd;
282  TcpHeader header;
283  Buffer buffer;
284 
286  5,
287  "TcpHeader without option is"
288  " not 5 word");
289  header.AppendOption(&oEnd);
291  5,
292  "Length has changed also for"
293  " END option");
295  20,
296  "Length has changed also for"
297  " END option");
298 
299  buffer.AddAtStart(header.GetSerializedSize());
300  header.Serialize(buffer.Begin());
301 
303  buffer.GetSize(),
304  "Header not correctly serialized");
305  }
306 
307  {
308  TcpOptionNOP oNop;
309  TcpHeader header;
310  Buffer buffer;
311 
313  5,
314  "TcpHeader without option is"
315  " not 5 word");
316  header.AppendOption(&oNop);
317  NS_TEST_ASSERT_MSG_EQ(header.GetLength(), 6, "NOP option not handled correctly");
319  24,
320  "Different length found for"
321  "NOP option");
322 
323  buffer.AddAtStart(header.GetSerializedSize());
324  header.Serialize(buffer.Begin());
325 
327  buffer.GetSize(),
328  "Header not correctly serialized");
329 
330  // Inserted only 1 byte NOP, and so implementation should pad; so
331  // the other 3 bytes should be END, PAD, PAD (n.b. PAD is same as END)
332  Buffer::Iterator i = buffer.Begin();
333  i.Next(20);
334 
335  uint8_t value = i.ReadU8();
336  NS_TEST_ASSERT_MSG_EQ(value, TcpOption::NOP, "NOP not present at byte 1");
337  value = i.ReadU8();
338  NS_TEST_ASSERT_MSG_EQ(value, TcpOption::END, "END not present at byte 2");
339  value = i.ReadU8();
340  NS_TEST_ASSERT_MSG_EQ(value, TcpOption::END, "pad not present at byte 3");
341  value = i.ReadU8();
342  NS_TEST_ASSERT_MSG_EQ(value, TcpOption::END, "pad not present at byte 4");
343  }
344 
345  {
346  TcpOptionMSS oMSS;
347  oMSS.SetMSS(50);
348  TcpHeader header;
349  TcpHeader dest;
350  Buffer buffer;
351 
353  5,
354  "TcpHeader without option is"
355  " not 5 word");
356  header.AppendOption(&oMSS);
357  NS_TEST_ASSERT_MSG_EQ(header.GetLength(), 6, "MSS option not handled correctly");
359  24,
360  "Different length found for"
361  "MSS option");
362 
363  buffer.AddAtStart(header.GetSerializedSize());
364  header.Serialize(buffer.Begin());
365 
367  buffer.GetSize(),
368  "Header not correctly serialized");
369 
370  dest.Deserialize(buffer.Begin());
371  NS_TEST_ASSERT_MSG_EQ(header.HasOption(TcpOption::MSS),
372  true,
373  "MSS option not correctly serialized");
375  oMSS.GetSerializedSize(),
376  "MSS Option not counted in the total");
377  }
378 }
379 
380 void
382 {
383 }
384 
391 {
392  public:
397  TcpHeaderFlagsToString(std::string name);
398 
399  private:
400  void DoRun() override;
401 };
402 
404  : TestCase(name)
405 {
406 }
407 
408 void
410 {
411  std::string str;
412  std::string target;
413  str = TcpHeader::FlagsToString(0x0);
414  target = "";
415  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
416  str = TcpHeader::FlagsToString(0x1);
417  target = "FIN";
418  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
419  str = TcpHeader::FlagsToString(0x2);
420  target = "SYN";
421  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
422  str = TcpHeader::FlagsToString(0x4);
423  target = "RST";
424  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
425  str = TcpHeader::FlagsToString(0x8);
426  target = "PSH";
427  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
428  str = TcpHeader::FlagsToString(0x10);
429  target = "ACK";
430  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
431  str = TcpHeader::FlagsToString(0x20);
432  target = "URG";
433  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
434  str = TcpHeader::FlagsToString(0x40);
435  target = "ECE";
436  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
437  str = TcpHeader::FlagsToString(0x80);
438  target = "CWR";
439  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
440  str = TcpHeader::FlagsToString(0x3);
441  target = "FIN|SYN";
442  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
443  str = TcpHeader::FlagsToString(0x5);
444  target = "FIN|RST";
445  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
446  str = TcpHeader::FlagsToString(0xff);
447  target = "FIN|SYN|RST|PSH|ACK|URG|ECE|CWR";
448  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
449  str = TcpHeader::FlagsToString(0xff, ":");
450  target = "FIN:SYN:RST:PSH:ACK:URG:ECE:CWR";
451  NS_TEST_ASSERT_MSG_EQ(str, target, "str " << str << " does not equal target " << target);
452 }
453 
460 {
461  public:
463  : TestSuite("tcp-header", UNIT)
464  {
465  AddTestCase(new TcpHeaderGetSetTestCase("GetSet test cases"), TestCase::QUICK);
466  AddTestCase(new TcpHeaderWithRFC793OptionTestCase("Test for options in RFC 793"),
467  TestCase::QUICK);
468  AddTestCase(new TcpHeaderFlagsToString("Test flags to string function"), TestCase::QUICK);
469  }
470 };
471 
TCP header Flags to String test.
void DoRun() override
Implementation to actually run this TestCase.
TcpHeaderFlagsToString(std::string name)
Constructor.
TCP header Get/Set test.
void DoRun() override
Implementation to actually run this TestCase.
TcpHeaderGetSetTestCase(std::string name)
Constructor.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
TCP header TestSuite.
TCP header with RFC793 Options test.
void OneOptionAtTime()
Check an header with only one kind of option.
TcpHeaderWithRFC793OptionTestCase(std::string name)
Constructor.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void CheckNoPadding()
Check an header for the correct padding.
void CheckCorrectDeserialize()
Check the correct header deserialization.
iterator in a Buffer instance
Definition: buffer.h:100
uint8_t ReadU8()
Definition: buffer.h:1027
void WriteU8(uint8_t data)
Definition: buffer.h:881
void Next()
go forward by one byte
Definition: buffer.h:853
automatically resized byte buffer
Definition: buffer.h:94
uint32_t GetSize() const
Definition: buffer.h:1068
void AddAtStart(uint32_t start)
Definition: buffer.cc:314
Buffer::Iterator Begin() const
Definition: buffer.h:1074
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
void SetUrgentPointer(uint16_t urgentPointer)
Set the urgent pointer.
Definition: tcp-header.cc:100
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:70
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition: tcp-header.cc:76
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:118
uint8_t GetLength() const
Get the length in words.
Definition: tcp-header.cc:130
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:112
uint32_t Deserialize(Buffer::Iterator start) override
Definition: tcp-header.cc:330
void SetFlags(uint8_t flags)
Set flags of the header.
Definition: tcp-header.cc:88
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition: tcp-header.cc:94
uint32_t GetSerializedSize() const override
Definition: tcp-header.cc:279
uint16_t GetWindowSize() const
Get the window size.
Definition: tcp-header.cc:154
uint8_t GetOptionLength() const
Get the total length of appended options.
Definition: tcp-header.cc:136
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
Definition: tcp-header.cc:432
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
Definition: tcp-header.cc:478
void Serialize(Buffer::Iterator start) const override
Definition: tcp-header.cc:285
uint16_t GetSourcePort() const
Get the source port.
Definition: tcp-header.cc:106
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:64
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition: tcp-header.cc:82
uint16_t GetUrgentPointer() const
Get the urgent pointer.
Definition: tcp-header.cc:160
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:148
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:124
Defines the TCP option of kind 0 (end of option list) as in RFC 793
Defines the TCP option of kind 2 (maximum segment size) as in RFC 793
void SetMSS(uint16_t mss)
Set the Maximum Segment Size stored in the Option.
uint32_t GetSerializedSize() const override
Returns number of bytes required for Option serialization.
Defines the TCP option of kind 1 (no operation) as in RFC 793
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
#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:144
Every class exported by the ns3 library is enclosed in the ns3 namespace.
value
Definition: second.py:48
#define END
End of a line.
static TcpHeaderTestSuite g_TcpHeaderTestSuite
Static variable for test initialization.
#define GET_RANDOM_UINT32(RandomVariable)
#define GET_RANDOM_UINT6(RandomVariable)
#define GET_RANDOM_UINT16(RandomVariable)