A Discrete-Event Network Simulator
API
tcp-header.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 Georgia Tech Research Corporation
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Raj Bhattacharjea <raj.b@gatech.edu>
19  */
20 
21 #include <stdint.h>
22 #include <iostream>
23 #include "tcp-header.h"
24 #include "tcp-option.h"
25 #include "ns3/buffer.h"
26 #include "ns3/address-utils.h"
27 #include "ns3/log.h"
28 
29 namespace ns3 {
30 
31 NS_LOG_COMPONENT_DEFINE ("TcpHeader");
32 
33 NS_OBJECT_ENSURE_REGISTERED (TcpHeader);
34 
36  : m_sourcePort (0),
37  m_destinationPort (0),
38  m_sequenceNumber (0),
39  m_ackNumber (0),
40  m_length (5),
41  m_flags (0),
42  m_windowSize (0xffff),
43  m_urgentPointer (0),
44  m_calcChecksum (false),
45  m_goodChecksum (true),
46  m_optionsLen (0)
47 {
48 }
49 
51 {
52 }
53 
54 std::string
55 TcpHeader::FlagsToString (uint8_t flags, const std::string& delimiter)
56 {
57  static const char* flagNames[8] = {
58  "FIN",
59  "SYN",
60  "RST",
61  "PSH",
62  "ACK",
63  "URG",
64  "ECE",
65  "CWR"
66  };
67  std::string flagsDescription = "";
68  for (uint8_t i = 0; i < 8; ++i)
69  {
70  if (flags & (1 << i))
71  {
72  if (flagsDescription.length () > 0)
73  {
74  flagsDescription += delimiter;
75  }
76  flagsDescription.append (flagNames[i]);
77  }
78  }
79  return flagsDescription;
80 }
81 
82 void
84 {
85  m_calcChecksum = true;
86 }
87 
88 void
90 {
92 }
93 
94 void
96 {
98 }
99 
100 void
102 {
103  m_sequenceNumber = sequenceNumber;
104 }
105 
106 void
108 {
109  m_ackNumber = ackNumber;
110 }
111 
112 void
113 TcpHeader::SetFlags (uint8_t flags)
114 {
115  m_flags = flags;
116 }
117 
118 void
119 TcpHeader::SetWindowSize (uint16_t windowSize)
120 {
121  m_windowSize = windowSize;
122 }
123 
124 void
125 TcpHeader::SetUrgentPointer (uint16_t urgentPointer)
126 {
127  m_urgentPointer = urgentPointer;
128 }
129 
130 uint16_t
132 {
133  return m_sourcePort;
134 }
135 
136 uint16_t
138 {
139  return m_destinationPort;
140 }
141 
144 {
145  return m_sequenceNumber;
146 }
147 
150 {
151  return m_ackNumber;
152 }
153 
154 uint8_t
156 {
157  return m_length;
158 }
159 
160 uint8_t
162 {
163  return m_optionsLen;
164 }
165 
166 uint8_t
168 {
169  return m_maxOptionsLen;
170 }
171 
172 uint8_t
174 {
175  return m_flags;
176 }
177 
178 uint16_t
180 {
181  return m_windowSize;
182 }
183 
184 uint16_t
186 {
187  return m_urgentPointer;
188 }
189 
190 void
192  const Ipv4Address &destination,
193  uint8_t protocol)
194 {
195  m_source = source;
196  m_destination = destination;
197  m_protocol = protocol;
198 }
199 
200 void
202  const Ipv6Address &destination,
203  uint8_t protocol)
204 {
205  m_source = source;
206  m_destination = destination;
207  m_protocol = protocol;
208 }
209 
210 void
212  const Address &destination,
213  uint8_t protocol)
214 {
215  m_source = source;
216  m_destination = destination;
217  m_protocol = protocol;
218 }
219 
220 uint16_t
222 {
223  /* Buffer size must be at least as large as the largest IP pseudo-header */
224  /* [per RFC2460, but without consideration for IPv6 extension hdrs] */
225  /* Src address 16 bytes (more generally, Address::MAX_SIZE) */
226  /* Dst address 16 bytes (more generally, Address::MAX_SIZE) */
227  /* Upper layer pkt len 4 bytes */
228  /* Zero 3 bytes */
229  /* Next header 1 byte */
230 
231  uint32_t maxHdrSz = (2 * Address::MAX_SIZE) + 8;
232  Buffer buf = Buffer (maxHdrSz);
233  buf.AddAtStart (maxHdrSz);
234  Buffer::Iterator it = buf.Begin ();
235  uint32_t hdrSize = 0;
236 
237  WriteTo (it, m_source);
238  WriteTo (it, m_destination);
240  {
241  it.WriteU8 (0); /* protocol */
242  it.WriteU8 (m_protocol); /* protocol */
243  it.WriteU8 (size >> 8); /* length */
244  it.WriteU8 (size & 0xff); /* length */
245  hdrSize = 12;
246  }
247  else
248  {
249  it.WriteU16 (0);
250  it.WriteU8 (size >> 8); /* length */
251  it.WriteU8 (size & 0xff); /* length */
252  it.WriteU16 (0);
253  it.WriteU8 (0);
254  it.WriteU8 (m_protocol); /* protocol */
255  hdrSize = 40;
256  }
257 
258  it = buf.Begin ();
259  /* we don't CompleteChecksum ( ~ ) now */
260  return ~(it.CalculateIpChecksum (hdrSize));
261 }
262 
263 bool
265 {
266  return m_goodChecksum;
267 }
268 
269 TypeId
271 {
272  static TypeId tid = TypeId ("ns3::TcpHeader")
273  .SetParent<Header> ()
274  .SetGroupName ("Internet")
275  .AddConstructor<TcpHeader> ()
276  ;
277  return tid;
278 }
279 
280 TypeId
282 {
283  return GetTypeId ();
284 }
285 
286 void
287 TcpHeader::Print (std::ostream &os) const
288 {
289  os << m_sourcePort << " > " << m_destinationPort;
290 
291  if (m_flags != 0)
292  {
293  os << " [" << FlagsToString (m_flags) << "]";
294  }
295 
296  os << " Seq=" << m_sequenceNumber << " Ack=" << m_ackNumber << " Win=" << m_windowSize;
297 
298  TcpOptionList::const_iterator op;
299 
300  for (op = m_options.begin (); op != m_options.end (); ++op)
301  {
302  os << " " << (*op)->GetInstanceTypeId ().GetName () << "(";
303  (*op)->Print (os);
304  os << ")";
305  }
306 }
307 
308 uint32_t
310 {
311  return CalculateHeaderLength () * 4;
312 }
313 
314 void
316 {
322  i.WriteHtonU16 (GetLength () << 12 | m_flags); //reserved bits are all zero
324  i.WriteHtonU16 (0);
326 
327  // Serialize options if they exist
328  // This implementation does not presently try to align options on word
329  // boundaries using NOP options
330  uint32_t optionLen = 0;
331  TcpOptionList::const_iterator op;
332  for (op = m_options.begin (); op != m_options.end (); ++op)
333  {
334  optionLen += (*op)->GetSerializedSize ();
335  (*op)->Serialize (i);
336  i.Next ((*op)->GetSerializedSize ());
337  }
338 
339  // padding to word alignment; add ENDs and/or pad values (they are the same)
340  while (optionLen % 4)
341  {
343  ++optionLen;
344  }
345 
346  // Make checksum
347  if (m_calcChecksum)
348  {
349  uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
350  i = start;
351  uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
352 
353  i = start;
354  i.Next (16);
355  i.WriteU16 (checksum);
356  }
357 }
358 
359 uint32_t
361 {
362  m_optionsLen = 0;
364  m_sourcePort = i.ReadNtohU16 ();
367  m_ackNumber = i.ReadNtohU32 ();
368  uint16_t field = i.ReadNtohU16 ();
369  m_flags = field & 0xFF;
370  m_length = field >> 12;
371  m_windowSize = i.ReadNtohU16 ();
372  i.Next (2);
374 
375  // Deserialize options if they exist
376  m_options.clear ();
377  uint32_t optionLen = (m_length - 5) * 4;
378  if (optionLen > m_maxOptionsLen)
379  {
380  NS_LOG_ERROR ("Illegal TCP option length " << optionLen << "; options discarded");
381  return 20;
382  }
383  while (optionLen)
384  {
385  uint8_t kind = i.PeekU8 ();
386  Ptr<TcpOption> op;
387  uint32_t optionSize;
388  if (TcpOption::IsKindKnown (kind))
389  {
390  op = TcpOption::CreateOption (kind);
391  }
392  else
393  {
395  NS_LOG_WARN ("Option kind " << static_cast<int> (kind) << " unknown, skipping.");
396  }
397  optionSize = op->Deserialize (i);
398  if (optionSize != op->GetSerializedSize ())
399  {
400  NS_LOG_ERROR ("Option did not deserialize correctly");
401  break;
402  }
403  if (optionLen >= optionSize)
404  {
405  optionLen -= optionSize;
406  i.Next (optionSize);
407  m_options.push_back (op);
408  m_optionsLen += optionSize;
409  }
410  else
411  {
412  NS_LOG_ERROR ("Option exceeds TCP option space; option discarded");
413  break;
414  }
415  if (op->GetKind () == TcpOption::END)
416  {
417  while (optionLen)
418  {
419  // Discard padding bytes without adding to option list
420  i.Next (1);
421  --optionLen;
422  ++m_optionsLen;
423  }
424  }
425  }
426 
428  {
429  NS_LOG_ERROR ("Mismatch between calculated length and in-header value");
430  }
431 
432  // Do checksum
433  if (m_calcChecksum)
434  {
435  uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
436  i = start;
437  uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
438  m_goodChecksum = (checksum == 0);
439  }
440 
441  return GetSerializedSize ();
442 }
443 
444 uint8_t
446 {
447  uint32_t len = 20;
448  TcpOptionList::const_iterator i;
449 
450  for (i = m_options.begin (); i != m_options.end (); ++i)
451  {
452  len += (*i)->GetSerializedSize ();
453  }
454  // Option list may not include padding; need to pad up to word boundary
455  if (len % 4)
456  {
457  len += 4 - (len % 4);
458  }
459  return len >> 2;
460 }
461 
462 bool
464 {
465  if (m_optionsLen + option->GetSerializedSize () <= m_maxOptionsLen)
466  {
467  if (!TcpOption::IsKindKnown (option->GetKind ()))
468  {
469  NS_LOG_WARN ("The option kind " << static_cast<int> (option->GetKind ()) << " is unknown");
470  return false;
471  }
472 
473  if (option->GetKind () != TcpOption::END)
474  {
475  m_options.push_back (option);
476  m_optionsLen += option->GetSerializedSize ();
477 
478  uint32_t totalLen = 20 + 3 + m_optionsLen;
479  m_length = totalLen >> 2;
480  }
481 
482  return true;
483  }
484 
485  return false;
486 }
487 
490 {
491  return m_options;
492 }
493 
495 TcpHeader::GetOption(uint8_t kind) const
496 {
497  TcpOptionList::const_iterator i;
498 
499  for (i = m_options.begin (); i != m_options.end (); ++i)
500  {
501  if ((*i)->GetKind () == kind)
502  {
503  return (*i);
504  }
505  }
506 
507  return 0;
508 }
509 
510 bool
511 TcpHeader::HasOption (uint8_t kind) const
512 {
513  TcpOptionList::const_iterator i;
514 
515  for (i = m_options.begin (); i != m_options.end (); ++i)
516  {
517  if ((*i)->GetKind () == kind)
518  {
519  return true;
520  }
521  }
522 
523  return false;
524 }
525 
526 bool
527 operator== (const TcpHeader &lhs, const TcpHeader &rhs)
528 {
529  return (
530  lhs.m_sourcePort == rhs.m_sourcePort
532  && lhs.m_sequenceNumber == rhs.m_sequenceNumber
533  && lhs.m_ackNumber == rhs.m_ackNumber
534  && lhs.m_flags == rhs.m_flags
535  && lhs.m_windowSize == rhs.m_windowSize
536  && lhs.m_urgentPointer == rhs.m_urgentPointer
537  );
538 }
539 
540 std::ostream&
541 operator<< (std::ostream& os, TcpHeader const & tc)
542 {
543  tc.Print (os);
544  return os;
545 }
546 
547 } // namespace ns3
a polymophic address class
Definition: address.h:91
iterator in a Buffer instance
Definition: buffer.h:99
uint16_t ReadNtohU16(void)
Definition: buffer.h:946
uint16_t CalculateIpChecksum(uint16_t size)
Calculate the checksum.
Definition: buffer.cc:1134
void WriteU8(uint8_t data)
Definition: buffer.h:869
void Next(void)
go forward by one byte
Definition: buffer.h:845
void WriteU16(uint16_t data)
Definition: buffer.cc:871
void WriteHtonU16(uint16_t data)
Definition: buffer.h:905
void WriteHtonU32(uint32_t data)
Definition: buffer.h:924
uint8_t PeekU8(void)
Definition: buffer.h:998
uint32_t ReadNtohU32(void)
Definition: buffer.h:970
automatically resized byte buffer
Definition: buffer.h:93
void AddAtStart(uint32_t start)
Definition: buffer.cc:309
Buffer::Iterator Begin(void) const
Definition: buffer.h:1069
Protocol header serialization and deserialization.
Definition: header.h:43
virtual uint32_t Deserialize(Buffer::Iterator start)=0
Deserialize the object from a buffer iterator.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
static bool IsMatchingType(const Address &address)
Describes an IPv6 address.
Definition: ipv6-address.h:50
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
uint16_t m_urgentPointer
Urgent pointer.
Definition: tcp-header.h:342
void SetUrgentPointer(uint16_t urgentPointer)
Set the urgent pointer.
Definition: tcp-header.cc:125
Address m_source
Source IP address.
Definition: tcp-header.h:344
virtual void Serialize(Buffer::Iterator start) const
Definition: tcp-header.cc:315
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:95
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition: tcp-header.cc:101
virtual uint32_t GetSerializedSize(void) const
Definition: tcp-header.cc:309
uint8_t m_optionsLen
Tcp options length.
Definition: tcp-header.h:353
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
uint8_t GetLength() const
Get the length in words.
Definition: tcp-header.cc:155
uint8_t GetMaxOptionLength() const
Get maximum option length.
Definition: tcp-header.cc:167
uint16_t m_sourcePort
Source port.
Definition: tcp-header.h:335
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:137
uint8_t CalculateHeaderLength() const
Calculates the header length (in words)
Definition: tcp-header.cc:445
uint8_t m_length
Length (really a uint4_t) in words.
Definition: tcp-header.h:339
static TypeId GetTypeId(void)
Get the type ID.
Definition: tcp-header.cc:270
virtual void Print(std::ostream &os) const
Definition: tcp-header.cc:287
static const uint8_t m_maxOptionsLen
Maximum options length.
Definition: tcp-header.h:351
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
Definition: tcp-header.cc:495
void SetFlags(uint8_t flags)
Set flags of the header.
Definition: tcp-header.cc:113
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition: tcp-header.cc:119
bool m_calcChecksum
Flag to calculate checksum.
Definition: tcp-header.h:348
uint16_t GetWindowSize() const
Get the window size.
Definition: tcp-header.cc:179
void InitializeChecksum(const Ipv4Address &source, const Ipv4Address &destination, uint8_t protocol)
Initialize the TCP checksum.
Definition: tcp-header.cc:191
Address m_destination
Destination IP address.
Definition: tcp-header.h:345
uint8_t m_protocol
Protocol number.
Definition: tcp-header.h:346
virtual TypeId GetInstanceTypeId(void) const
Get the most derived TypeId for this Object.
Definition: tcp-header.cc:281
uint8_t GetOptionLength() const
Get the total length of appended options.
Definition: tcp-header.cc:161
SequenceNumber32 m_sequenceNumber
Sequence number.
Definition: tcp-header.h:337
uint16_t CalculateHeaderChecksum(uint16_t size) const
Calculate the header checksum.
Definition: tcp-header.cc:221
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
Definition: tcp-header.cc:463
static std::string FlagsToString(uint8_t flags, const std::string &delimiter="|")
Converts an integer into a human readable list of Tcp flags.
Definition: tcp-header.cc:55
bool IsChecksumOk(void) const
Is the TCP checksum correct ?
Definition: tcp-header.cc:264
const TcpOptionList & GetOptionList(void) const
Get the list of option in this header.
Definition: tcp-header.cc:489
uint16_t m_windowSize
Window size.
Definition: tcp-header.h:341
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
Definition: tcp-header.cc:511
bool m_goodChecksum
Flag to indicate that checksum is correct.
Definition: tcp-header.h:349
std::list< Ptr< const TcpOption > > TcpOptionList
List of TcpOption.
Definition: tcp-header.h:50
uint16_t GetSourcePort() const
Get the source port.
Definition: tcp-header.cc:131
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:89
SequenceNumber32 m_ackNumber
ACK number.
Definition: tcp-header.h:338
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition: tcp-header.cc:107
uint16_t GetUrgentPointer() const
Get the urgent pointer.
Definition: tcp-header.cc:185
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:149
void EnableChecksums(void)
Enable checksum calculation for TCP.
Definition: tcp-header.cc:83
uint8_t m_flags
Flags (really a uint6_t)
Definition: tcp-header.h:340
uint16_t m_destinationPort
Destination port.
Definition: tcp-header.h:336
TcpOptionList m_options
TcpOption present in the header.
Definition: tcp-header.h:352
virtual ~TcpHeader()
Definition: tcp-header.cc:50
virtual uint8_t GetKind(void) const =0
Get the ‘kind’ (as in RFC 793) of this option.
static Ptr< TcpOption > CreateOption(uint8_t kind)
Creates an option.
Definition: tcp-option.cc:65
static bool IsKindKnown(uint8_t kind)
Check if the option is implemented.
Definition: tcp-option.cc:99
@ UNKNOWN
not a standardized value; for unknown recv'd options
Definition: tcp-option.h:64
virtual uint32_t GetSerializedSize(void) const =0
Returns number of bytes required for Option serialization.
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
uint16_t port
Definition: dsdv-manet.cc:45
#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_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:158
void WriteTo(Buffer::Iterator &i, Ipv4Address ad)
Write an Ipv4Address to a Buffer.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:139
def start()
Definition: core.py:1853