A Discrete-Event Network Simulator
API
tcp-header.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Georgia Tech Research Corporation
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  * Author: Raj Bhattacharjea <raj.b@gatech.edu>
18  */
19 
20 #include "tcp-header.h"
21 
22 #include "tcp-option.h"
23 
24 #include "ns3/address-utils.h"
25 #include "ns3/buffer.h"
26 #include "ns3/log.h"
27 
28 #include <iostream>
29 #include <stdint.h>
30 
31 namespace ns3
32 {
33 
34 NS_LOG_COMPONENT_DEFINE("TcpHeader");
35 
37 
38 std::string
39 TcpHeader::FlagsToString(uint8_t flags, const std::string& delimiter)
40 {
41  static const char* flagNames[8] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECE", "CWR"};
42  std::string flagsDescription = "";
43  for (uint8_t i = 0; i < 8; ++i)
44  {
45  if (flags & (1 << i))
46  {
47  if (!flagsDescription.empty())
48  {
49  flagsDescription += delimiter;
50  }
51  flagsDescription.append(flagNames[i]);
52  }
53  }
54  return flagsDescription;
55 }
56 
57 void
59 {
60  m_calcChecksum = true;
61 }
62 
63 void
65 {
67 }
68 
69 void
71 {
73 }
74 
75 void
77 {
78  m_sequenceNumber = sequenceNumber;
79 }
80 
81 void
83 {
84  m_ackNumber = ackNumber;
85 }
86 
87 void
88 TcpHeader::SetFlags(uint8_t flags)
89 {
90  m_flags = flags;
91 }
92 
93 void
94 TcpHeader::SetWindowSize(uint16_t windowSize)
95 {
96  m_windowSize = windowSize;
97 }
98 
99 void
100 TcpHeader::SetUrgentPointer(uint16_t urgentPointer)
101 {
102  m_urgentPointer = urgentPointer;
103 }
104 
105 uint16_t
107 {
108  return m_sourcePort;
109 }
110 
111 uint16_t
113 {
114  return m_destinationPort;
115 }
116 
119 {
120  return m_sequenceNumber;
121 }
122 
125 {
126  return m_ackNumber;
127 }
128 
129 uint8_t
131 {
132  return m_length;
133 }
134 
135 uint8_t
137 {
138  return m_optionsLen;
139 }
140 
141 uint8_t
143 {
144  return m_maxOptionsLen;
145 }
146 
147 uint8_t
149 {
150  return m_flags;
151 }
152 
153 uint16_t
155 {
156  return m_windowSize;
157 }
158 
159 uint16_t
161 {
162  return m_urgentPointer;
163 }
164 
165 void
167  const Ipv4Address& destination,
168  uint8_t protocol)
169 {
170  m_source = source;
171  m_destination = destination;
172  m_protocol = protocol;
173 }
174 
175 void
177  const Ipv6Address& destination,
178  uint8_t protocol)
179 {
180  m_source = source;
181  m_destination = destination;
182  m_protocol = protocol;
183 }
184 
185 void
186 TcpHeader::InitializeChecksum(const Address& source, const Address& destination, uint8_t protocol)
187 {
188  m_source = source;
189  m_destination = destination;
190  m_protocol = protocol;
191 }
192 
193 uint16_t
195 {
196  /* Buffer size must be at least as large as the largest IP pseudo-header */
197  /* [per RFC2460, but without consideration for IPv6 extension hdrs] */
198  /* Src address 16 bytes (more generally, Address::MAX_SIZE) */
199  /* Dst address 16 bytes (more generally, Address::MAX_SIZE) */
200  /* Upper layer pkt len 4 bytes */
201  /* Zero 3 bytes */
202  /* Next header 1 byte */
203 
204  uint32_t maxHdrSz = (2 * Address::MAX_SIZE) + 8;
205  Buffer buf = Buffer(maxHdrSz);
206  buf.AddAtStart(maxHdrSz);
207  Buffer::Iterator it = buf.Begin();
208  uint32_t hdrSize = 0;
209 
210  WriteTo(it, m_source);
211  WriteTo(it, m_destination);
213  {
214  it.WriteU8(0); /* protocol */
215  it.WriteU8(m_protocol); /* protocol */
216  it.WriteU8(size >> 8); /* length */
217  it.WriteU8(size & 0xff); /* length */
218  hdrSize = 12;
219  }
220  else
221  {
222  it.WriteU16(0);
223  it.WriteU8(size >> 8); /* length */
224  it.WriteU8(size & 0xff); /* length */
225  it.WriteU16(0);
226  it.WriteU8(0);
227  it.WriteU8(m_protocol); /* protocol */
228  hdrSize = 40;
229  }
230 
231  it = buf.Begin();
232  /* we don't CompleteChecksum ( ~ ) now */
233  return ~(it.CalculateIpChecksum(hdrSize));
234 }
235 
236 bool
238 {
239  return m_goodChecksum;
240 }
241 
242 TypeId
244 {
245  static TypeId tid = TypeId("ns3::TcpHeader")
246  .SetParent<Header>()
247  .SetGroupName("Internet")
248  .AddConstructor<TcpHeader>();
249  return tid;
250 }
251 
252 TypeId
254 {
255  return GetTypeId();
256 }
257 
258 void
259 TcpHeader::Print(std::ostream& os) const
260 {
261  os << m_sourcePort << " > " << m_destinationPort;
262 
263  if (m_flags != 0)
264  {
265  os << " [" << FlagsToString(m_flags) << "]";
266  }
267 
268  os << " Seq=" << m_sequenceNumber << " Ack=" << m_ackNumber << " Win=" << m_windowSize;
269 
270  for (auto op = m_options.begin(); op != m_options.end(); ++op)
271  {
272  os << " " << (*op)->GetInstanceTypeId().GetName() << "(";
273  (*op)->Print(os);
274  os << ")";
275  }
276 }
277 
278 uint32_t
280 {
281  return CalculateHeaderLength() * 4;
282 }
283 
284 void
286 {
292  i.WriteHtonU16(GetLength() << 12 | m_flags); // reserved bits are all zero
294  i.WriteHtonU16(0);
296 
297  // Serialize options if they exist
298  // This implementation does not presently try to align options on word
299  // boundaries using NOP options
300  uint32_t optionLen = 0;
301 
302  for (auto op = m_options.begin(); op != m_options.end(); ++op)
303  {
304  optionLen += (*op)->GetSerializedSize();
305  (*op)->Serialize(i);
306  i.Next((*op)->GetSerializedSize());
307  }
308 
309  // padding to word alignment; add ENDs and/or pad values (they are the same)
310  while (optionLen % 4)
311  {
313  ++optionLen;
314  }
315 
316  // Make checksum
317  if (m_calcChecksum)
318  {
319  uint16_t headerChecksum = CalculateHeaderChecksum(start.GetSize());
320  i = start;
321  uint16_t checksum = i.CalculateIpChecksum(start.GetSize(), headerChecksum);
322 
323  i = start;
324  i.Next(16);
325  i.WriteU16(checksum);
326  }
327 }
328 
329 uint32_t
331 {
332  m_optionsLen = 0;
337  m_ackNumber = i.ReadNtohU32();
338  uint16_t field = i.ReadNtohU16();
339  m_flags = field & 0xFF;
340  m_length = field >> 12;
342  i.Next(2);
344 
345  // Deserialize options if they exist
346  m_options.clear();
347  uint32_t optionLen = (m_length - 5) * 4;
348  if (optionLen > m_maxOptionsLen)
349  {
350  NS_LOG_ERROR("Illegal TCP option length " << optionLen << "; options discarded");
351  return 20;
352  }
353  while (optionLen)
354  {
355  uint8_t kind = i.PeekU8();
356  Ptr<TcpOption> op;
357  uint32_t optionSize;
358  if (TcpOption::IsKindKnown(kind))
359  {
360  op = TcpOption::CreateOption(kind);
361  }
362  else
363  {
365  NS_LOG_WARN("Option kind " << static_cast<int>(kind) << " unknown, skipping.");
366  }
367  optionSize = op->Deserialize(i);
368  if (optionSize != op->GetSerializedSize())
369  {
370  NS_LOG_ERROR("Option did not deserialize correctly");
371  break;
372  }
373  if (optionLen >= optionSize)
374  {
375  optionLen -= optionSize;
376  i.Next(optionSize);
377  m_options.emplace_back(op);
378  m_optionsLen += optionSize;
379  }
380  else
381  {
382  NS_LOG_ERROR("Option exceeds TCP option space; option discarded");
383  break;
384  }
385  if (op->GetKind() == TcpOption::END)
386  {
387  while (optionLen)
388  {
389  // Discard padding bytes without adding to option list
390  i.Next(1);
391  --optionLen;
392  ++m_optionsLen;
393  }
394  }
395  }
396 
398  {
399  NS_LOG_ERROR("Mismatch between calculated length and in-header value");
400  }
401 
402  // Do checksum
403  if (m_calcChecksum)
404  {
405  uint16_t headerChecksum = CalculateHeaderChecksum(start.GetSize());
406  i = start;
407  uint16_t checksum = i.CalculateIpChecksum(start.GetSize(), headerChecksum);
408  m_goodChecksum = (checksum == 0);
409  }
410 
411  return GetSerializedSize();
412 }
413 
414 uint8_t
416 {
417  uint32_t len = 20;
418 
419  for (auto i = m_options.begin(); i != m_options.end(); ++i)
420  {
421  len += (*i)->GetSerializedSize();
422  }
423  // Option list may not include padding; need to pad up to word boundary
424  if (len % 4)
425  {
426  len += 4 - (len % 4);
427  }
428  return len >> 2;
429 }
430 
431 bool
433 {
435  {
436  if (!TcpOption::IsKindKnown(option->GetKind()))
437  {
438  NS_LOG_WARN("The option kind " << static_cast<int>(option->GetKind()) << " is unknown");
439  return false;
440  }
441 
442  if (option->GetKind() != TcpOption::END)
443  {
444  m_options.push_back(option);
445  m_optionsLen += option->GetSerializedSize();
446 
447  uint32_t totalLen = 20 + 3 + m_optionsLen;
448  m_length = totalLen >> 2;
449  }
450 
451  return true;
452  }
453 
454  return false;
455 }
456 
459 {
460  return m_options;
461 }
462 
464 TcpHeader::GetOption(uint8_t kind) const
465 {
466  for (auto i = m_options.begin(); i != m_options.end(); ++i)
467  {
468  if ((*i)->GetKind() == kind)
469  {
470  return (*i);
471  }
472  }
473 
474  return nullptr;
475 }
476 
477 bool
478 TcpHeader::HasOption(uint8_t kind) const
479 {
480  for (auto i = m_options.begin(); i != m_options.end(); ++i)
481  {
482  if ((*i)->GetKind() == kind)
483  {
484  return true;
485  }
486  }
487 
488  return false;
489 }
490 
491 bool
492 operator==(const TcpHeader& lhs, const TcpHeader& rhs)
493 {
494  return (lhs.m_sourcePort == rhs.m_sourcePort &&
496  lhs.m_sequenceNumber == rhs.m_sequenceNumber && lhs.m_ackNumber == rhs.m_ackNumber &&
497  lhs.m_flags == rhs.m_flags && lhs.m_windowSize == rhs.m_windowSize &&
498  lhs.m_urgentPointer == rhs.m_urgentPointer);
499 }
500 
501 std::ostream&
502 operator<<(std::ostream& os, const TcpHeader& tc)
503 {
504  tc.Print(os);
505  return os;
506 }
507 
508 } // namespace ns3
a polymophic address class
Definition: address.h:101
static constexpr uint32_t MAX_SIZE
The maximum size of a byte buffer which can be stored in an Address instance.
Definition: address.h:107
iterator in a Buffer instance
Definition: buffer.h:100
uint16_t CalculateIpChecksum(uint16_t size)
Calculate the checksum.
Definition: buffer.cc:1135
void WriteU8(uint8_t data)
Definition: buffer.h:881
void WriteU16(uint16_t data)
Definition: buffer.cc:859
void WriteHtonU16(uint16_t data)
Definition: buffer.h:915
uint32_t ReadNtohU32()
Definition: buffer.h:978
uint8_t PeekU8()
Definition: buffer.h:1006
void WriteHtonU32(uint32_t data)
Definition: buffer.h:933
uint16_t ReadNtohU16()
Definition: buffer.h:954
void Next()
go forward by one byte
Definition: buffer.h:853
automatically resized byte buffer
Definition: buffer.h:94
void AddAtStart(uint32_t start)
Definition: buffer.cc:314
Buffer::Iterator Begin() const
Definition: buffer.h:1074
Protocol header serialization and deserialization.
Definition: header.h:44
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:42
static bool IsMatchingType(const Address &address)
Describes an IPv6 address.
Definition: ipv6-address.h:49
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
uint16_t m_urgentPointer
Urgent pointer.
Definition: tcp-header.h:339
void SetUrgentPointer(uint16_t urgentPointer)
Set the urgent pointer.
Definition: tcp-header.cc:100
Address m_source
Source IP address.
Definition: tcp-header.h:341
void Print(std::ostream &os) const override
Definition: tcp-header.cc:259
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
uint8_t m_optionsLen
Tcp options length.
Definition: tcp-header.h:350
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
uint8_t GetMaxOptionLength() const
Get maximum option length.
Definition: tcp-header.cc:142
uint16_t m_sourcePort
Source port.
Definition: tcp-header.h:332
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:112
std::list< Ptr< const TcpOption > > TcpOptionList
List of TcpOption.
Definition: tcp-header.h:49
uint8_t CalculateHeaderLength() const
Calculates the header length (in words)
Definition: tcp-header.cc:415
uint8_t m_length
Length (really a uint4_t) in words.
Definition: tcp-header.h:336
static const uint8_t m_maxOptionsLen
Maximum options length.
Definition: tcp-header.h:348
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
Definition: tcp-header.cc:464
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
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
Definition: tcp-header.cc:458
bool m_calcChecksum
Flag to calculate checksum.
Definition: tcp-header.h:345
uint16_t GetWindowSize() const
Get the window size.
Definition: tcp-header.cc:154
void InitializeChecksum(const Ipv4Address &source, const Ipv4Address &destination, uint8_t protocol)
Initialize the TCP checksum.
Definition: tcp-header.cc:166
Address m_destination
Destination IP address.
Definition: tcp-header.h:342
uint8_t m_protocol
Protocol number.
Definition: tcp-header.h:343
uint8_t GetOptionLength() const
Get the total length of appended options.
Definition: tcp-header.cc:136
SequenceNumber32 m_sequenceNumber
Sequence number.
Definition: tcp-header.h:334
uint16_t CalculateHeaderChecksum(uint16_t size) const
Calculate the header checksum.
Definition: tcp-header.cc:194
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
Definition: tcp-header.cc:432
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:39
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
Definition: tcp-header.cc:253
uint16_t m_windowSize
Window size.
Definition: tcp-header.h:338
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
Definition: tcp-header.cc:478
bool m_goodChecksum
Flag to indicate that checksum is correct.
Definition: tcp-header.h:346
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
SequenceNumber32 m_ackNumber
ACK number.
Definition: tcp-header.h:335
void EnableChecksums()
Enable checksum calculation for TCP.
Definition: tcp-header.cc:58
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
uint8_t m_flags
Flags (really a uint6_t)
Definition: tcp-header.h:337
bool IsChecksumOk() const
Is the TCP checksum correct ?
Definition: tcp-header.cc:237
uint16_t m_destinationPort
Destination port.
Definition: tcp-header.h:333
TcpOptionList m_options
TcpOption present in the header.
Definition: tcp-header.h:349
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-header.cc:243
static Ptr< TcpOption > CreateOption(uint8_t kind)
Creates an option.
Definition: tcp-option.cc:62
virtual uint8_t GetKind() const =0
Get the ‘kind’ (as in RFC 793) of this option.
static bool IsKindKnown(uint8_t kind)
Check if the option is implemented.
Definition: tcp-option.cc:95
@ UNKNOWN
not a standardized value; for unknown recv'd options
Definition: tcp-option.h:65
virtual uint32_t GetSerializedSize() 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:931
uint16_t port
Definition: dsdv-manet.cc:44
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
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:157
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:159