INET Framework for OMNeT++/OMNEST
inet::DhcpMessageSerializer Class Reference

Converts between DhcpMessage and binary (network byte order) DHCP message. More...

#include <DhcpMessageSerializer.h>

Inheritance diagram for inet::DhcpMessageSerializer:
inet::FieldsChunkSerializer inet::ChunkSerializer

Public Member Functions

 DhcpMessageSerializer ()
 
- Public Member Functions inherited from inet::FieldsChunkSerializer
virtual void serialize (MemoryOutputStream &stream, const Ptr< const Chunk > &chunk, b offset, b length) const override
 Serializes a chunk into a stream by writing the bytes representing the chunk at the end of the stream. More...
 
virtual const Ptr< Chunkdeserialize (MemoryInputStream &stream, const std::type_info &typeInfo) const override
 Deserializes a chunk from a stream by reading the bytes at the current position of the stream. More...
 

Protected Member Functions

virtual void serialize (MemoryOutputStream &stream, const Ptr< const Chunk > &chunk) const override
 Serializes a chunk into a stream by writing all bytes representing the chunk at the end of the stream. More...
 
virtual const Ptr< Chunkdeserialize (MemoryInputStream &stream) const override
 Deserializes a chunk from a stream by reading the bytes at the current position of the stream. More...
 

Additional Inherited Members

- Static Public Attributes inherited from inet::ChunkSerializer
static b totalSerializedLength = b(0)
 
static b totalDeserializedLength = b(0)
 

Detailed Description

Converts between DhcpMessage and binary (network byte order) DHCP message.

Constructor & Destructor Documentation

◆ DhcpMessageSerializer()

inet::DhcpMessageSerializer::DhcpMessageSerializer ( )
inline
25 : FieldsChunkSerializer() {}

Member Function Documentation

◆ deserialize()

const Ptr< Chunk > inet::DhcpMessageSerializer::deserialize ( MemoryInputStream stream) const
overrideprotectedvirtual

Deserializes a chunk from a stream by reading the bytes at the current position of the stream.

The current stream position is updated according to the length of the returned chunk.

Implements inet::FieldsChunkSerializer.

220 {
221  auto dhcpMessage = makeShared<DhcpMessage>();
222 
223  int length = 236;
224 
225  dhcpMessage->setOp((stream.readByte() == 1 ? BOOTREQUEST : BOOTREPLY));
226  dhcpMessage->setHtype(stream.readByte());
227  dhcpMessage->setHlen(stream.readByte());
228  dhcpMessage->setHops(stream.readByte());
229  dhcpMessage->setXid(stream.readUint32Be());
230  dhcpMessage->setSecs(stream.readUint16Be());
231  dhcpMessage->setBroadcast(stream.readBit());
232  dhcpMessage->setReserved(stream.readNBitsToUint64Be(15));
233  dhcpMessage->setCiaddr(stream.readIpv4Address());
234  dhcpMessage->setYiaddr(stream.readIpv4Address());
235  // FIXME siaddr is missing from the packet representation
236  stream.readUint32Be();
237  dhcpMessage->setGiaddr(stream.readIpv4Address());
238  dhcpMessage->setChaddr(stream.readMacAddress());
239  stream.readByte();
240  stream.readByte();
241  stream.readUint64Be();
242 
243  char sname[64];
244  for (int i = 0; i < 64; ++i) {
245  sname[i] = stream.readByte();
246  }
247  dhcpMessage->setSname(sname);
248 
249  char file[128];
250  for (int i = 0; i < 128; ++i) {
251  file[i] = stream.readByte();
252  }
253  dhcpMessage->setFile(file);
254 
255  // The first four octets of the 'options' field of the DHCP message
256  // contain the (decimal) values 99, 130, 83 and 99, respectively (this
257  // is the same magic cookie as is defined in RFC 1497 [17]).
258  uint8_t b1 = stream.readByte();
259  uint8_t b2 = stream.readByte();
260  uint8_t b3 = stream.readByte();
261  uint8_t b4 = stream.readByte();
262  ASSERT(b1 == 99 && b2 == 130 && b3 == 83 && b4 == 99);
263  length += 4;
264 
265  DhcpOptions& options = dhcpMessage->getOptionsForUpdate();
266  uint8_t code = stream.readByte();
267 
268  while (code != 255) {
269  switch (code) {
270  case DHCP_MSG_TYPE: {
271  uint8_t size = stream.readByte();
272  ASSERT(size == 1);
273  options.setMessageType((DhcpMessageType)stream.readByte());
274  length += 2 + size;
275  break;
276  }
277  case HOSTNAME: {
278  uint8_t size = stream.readByte();
279  char *hostName = new char[size + 1];
280  stream.readBytes((uint8_t *)hostName, B(size));
281  hostName[size] = '\0';
282  options.setHostName(hostName);
283  delete[] hostName;
284  length += 2 + size;
285  break;
286  }
287  case PARAM_LIST: {
288  uint8_t size = stream.readByte();
289  options.setParameterRequestListArraySize(size);
290  for (uint8_t i = 0; i < size; ++i) {
291  options.setParameterRequestList(i, static_cast<DhcpOptionCode>(stream.readUint8()));
292  }
293  length += 2 + size;
294  break;
295  }
296  case CLIENT_ID: {
297  uint8_t size = stream.readByte();
298  uint8_t type = stream.readByte();
299  ASSERT(size == 7 && type == 1);
300  options.setClientIdentifier(stream.readMacAddress());
301  length += 2 + size;
302  break;
303  }
304  case REQUESTED_IP: {
305  uint8_t size = stream.readByte();
306  ASSERT(size == 4); // IPv4_ADDRESS_SIZE
307  options.setRequestedIp(stream.readIpv4Address());
308  length += 2 + size;
309  break;
310  }
311  case SUBNET_MASK: {
312  uint8_t size = stream.readByte();
313  ASSERT(size == 4); // IPv4_ADDRESS_SIZE
314  options.setSubnetMask(stream.readIpv4Address());
315  length += 2 + size;
316  break;
317  }
318  case ROUTER: {
319  uint8_t size = stream.readByte();
320  ASSERT((size % 4) == 0); // n * IPv4_ADDRESS_SIZE
321  uint8_t dim = size / 4; // IPv4_ADDRESS_SIZE
322  options.setRouterArraySize(dim);
323  for (uint8_t i = 0; i < dim; ++i) {
324  options.setRouter(i, stream.readIpv4Address());
325  }
326  length += 2 + size;
327  break;
328  }
329  case DNS: {
330  uint8_t size = stream.readByte();
331  ASSERT((size % 4) == 0); // n * IPv4_ADDRESS_SIZE
332  uint8_t dim = size / 4; // IPv4_ADDRESS_SIZE
333  options.setDnsArraySize(dim);
334  for (uint8_t i = 0; i < dim; ++i) {
335  options.setDns(i, stream.readIpv4Address());
336  }
337  length += 2 + size;
338  break;
339  }
340  case NTP_SRV: {
341  uint8_t size = stream.readByte();
342  ASSERT((size % 4) == 0); // n * IPv4_ADDRESS_SIZE
343  uint8_t dim = size / 4; // IPv4_ADDRESS_SIZE
344  options.setNtpArraySize(dim);
345  for (uint8_t i = 0; i < dim; ++i) {
346  options.setNtp(i, stream.readIpv4Address());
347  }
348  length += 2 + size;
349  break;
350  }
351  case SERVER_ID: {
352  uint8_t size = stream.readByte();
353  ASSERT(size == 4); // IPv4_ADDRESS_SIZE
354  options.setServerIdentifier(stream.readIpv4Address());
355  length += 2 + size;
356  break;
357  }
358  case RENEWAL_TIME: {
359  uint8_t size = stream.readByte();
360  ASSERT(size == 4); // Time size
361  options.setRenewalTime(SimTime(stream.readUint32Be(), SIMTIME_S));
362  length += 2 + size;
363  break;
364  }
365  case REBIND_TIME: {
366  uint8_t size = stream.readByte();
367  ASSERT(size == 4); // Time size
368  options.setRebindingTime(SimTime(stream.readUint32Be(), SIMTIME_S));
369  length += 2 + size;
370  break;
371  }
372  case LEASE_TIME: {
373  uint8_t size = stream.readByte();
374  ASSERT(size == 4); // Time size
375  options.setLeaseTime(SimTime(stream.readUint32Be(), SIMTIME_S));
376  length += 2 + size;
377  break;
378  }
379  default: {
380  uint8_t size = stream.readByte();
381  dhcpMessage->markIncorrect();
382  std::vector<uint8_t> buffer;
383  stream.readBytes(buffer, B(size));
384  length += 2 + size;
385  break;
386  }
387  }
388  code = stream.readByte();
389  }
390  ++length;
391 
392  dhcpMessage->setChunkLength(B(length));
393  return dhcpMessage;
394 }

◆ serialize()

void inet::DhcpMessageSerializer::serialize ( MemoryOutputStream stream,
const Ptr< const Chunk > &  chunk 
) const
overrideprotectedvirtual

Serializes a chunk into a stream by writing all bytes representing the chunk at the end of the stream.

Implements inet::FieldsChunkSerializer.

18 {
19  const auto& dhcpMessage = staticPtrCast<const DhcpMessage>(chunk);
20 
21  // length of a DHCP message without options
22  uint16_t length = 236;
23 
24  stream.writeByte(dhcpMessage->getOp());
25  stream.writeByte(dhcpMessage->getHtype());
26  stream.writeByte(dhcpMessage->getHlen());
27  stream.writeByte(dhcpMessage->getHops());
28  stream.writeUint32Be(dhcpMessage->getXid());
29  stream.writeUint16Be(dhcpMessage->getSecs());
30  stream.writeBit(dhcpMessage->getBroadcast());
31  stream.writeNBitsOfUint64Be(dhcpMessage->getReserved(), 15);
32  stream.writeIpv4Address(dhcpMessage->getCiaddr());
33  stream.writeIpv4Address(dhcpMessage->getYiaddr());
34  // FIXME siaddr is missing from the packet representation
35  stream.writeUint32Be(0);
36  stream.writeIpv4Address(dhcpMessage->getGiaddr());
37  stream.writeMacAddress(dhcpMessage->getChaddr());
38  stream.writeByte(0);
39  stream.writeByte(0);
40  stream.writeUint64Be(0);
41 
42  int e = 0;
43 
44  const char *sname = dhcpMessage->getSname();
45  if (sname != nullptr) {
46  if (strlen(sname) > 64)
47  throw cRuntimeError("Cannot serialize DHCP message: server host name (sname) exceeds the allowed 64 byte limit.");
48  // write the string until '\0'
49  for (e = 0; sname[e] != '\0'; ++e) {
50  stream.writeByte(sname[e]);
51  }
52  // write the '\0'
53  stream.writeByte('\0');
54  // fill in the remaining bytes
55  stream.writeByteRepeatedly(0, 64 - (e + 1));
56  }
57 
58  const char *file = dhcpMessage->getFile();
59  if (file != nullptr) {
60  if (strlen(file) > 128)
61  throw cRuntimeError("Cannot serialize DHCP message: file name (file) exceeds the allowed 128 byte limit.");
62  // write the string until '\0'
63  for (e = 0; file[e] != '\0'; ++e) {
64  stream.writeByte(file[e]);
65  }
66  // write the '\0'
67  stream.writeByte('\0');
68  // fill in the remaining bytes
69  stream.writeByteRepeatedly(0, 128 - (e + 1));
70  }
71 
72  DhcpOptions options = dhcpMessage->getOptions();
73 
74  // The first four octets of the 'options' field of the DHCP message
75  // contain the (decimal) values 99, 130, 83 and 99, respectively (this
76  // is the same magic cookie as is defined in RFC 1497 [17]).
77 
78  stream.writeByte(99);
79  stream.writeByte(130);
80  stream.writeByte(83);
81  stream.writeByte(99);
82  length += 4;
83 
84  // options structure
85  // | Tag | Length | Data |
86  // | 1 byte | 1 byte | Length byte(s) |
87 
88  // DHCP Message Type
89  if (options.getMessageType() != static_cast<inet::DhcpMessageType>(-1)) {
90  stream.writeByte(DHCP_MSG_TYPE);
91  stream.writeByte(1);
92  stream.writeByte(options.getMessageType());
93  length += 3;
94  }
95 
96  // Host Name Option
97  const char *hostName = options.getHostName();
98  // FIXME nullptr and strcmp does not seem to work
99  if (hostName != nullptr && false) {
100  stream.writeByte(HOSTNAME);
101  uint16_t size = strlen(hostName);
102  stream.writeByte(size);
103  for (size_t i = 0; hostName[i] != '\0'; ++i) {
104  stream.writeByte(hostName[i]);
105  }
106  length += (2 + size);
107  }
108 
109  // Parameter Request List
110  if (options.getParameterRequestListArraySize() > 0) {
111  stream.writeByte(PARAM_LIST);
112  uint16_t size = options.getParameterRequestListArraySize();
113  stream.writeByte(size);
114  for (size_t i = 0; i < options.getParameterRequestListArraySize(); ++i) {
115  stream.writeUint8(options.getParameterRequestList(i));
116  }
117  length += (2 + size);
118  }
119 
120  // Client-Identifier
121  if (!options.getClientIdentifier().isUnspecified()) {
122  stream.writeByte(CLIENT_ID);
123  uint8_t size = 1 + 6;
124  stream.writeByte(size);
125  // TODO arp hardware type?
126  stream.writeByte(1);
127  stream.writeMacAddress(options.getClientIdentifier());
128  length += (2 + size);
129  }
130 
131  // Requested IP Address
132  if (!options.getRequestedIp().isUnspecified()) {
133  stream.writeByte(REQUESTED_IP);
134  stream.writeByte(4);
135  stream.writeIpv4Address(options.getRequestedIp());
136  length += 6;
137  }
138 
139  // Subnet Mask
140  if (!options.getSubnetMask().isUnspecified()) {
141  stream.writeByte(SUBNET_MASK);
142  stream.writeByte(4);
143  stream.writeIpv4Address(options.getSubnetMask());
144  length += 6;
145  }
146 
147  // Router
148  if (options.getRouterArraySize() > 0) {
149  stream.writeByte(ROUTER);
150  uint16_t size = options.getRouterArraySize() * 4; // IPv4_ADDRESS_SIZE
151  stream.writeByte(size);
152  for (size_t i = 0; i < options.getRouterArraySize(); ++i) {
153  stream.writeIpv4Address(options.getRouter(i));
154  }
155  length += (2 + size);
156  }
157 
158  // Domain Name Server Option
159  if (options.getDnsArraySize() > 0) {
160  stream.writeByte(DNS);
161  uint16_t size = options.getDnsArraySize() * 4; // IPv4_ADDRESS_SIZE
162  stream.writeByte(size);
163  for (size_t i = 0; i < options.getDnsArraySize(); ++i) {
164  stream.writeIpv4Address(options.getDns(i));
165  }
166  length += (2 + size);
167  }
168 
169  // Network Time Protocol Servers Option
170  if (options.getNtpArraySize() > 0) {
171  stream.writeByte(NTP_SRV);
172  uint16_t size = options.getNtpArraySize() * 4; // IPv4_ADDRESS_SIZE
173  stream.writeByte(size);
174  for (size_t i = 0; i < options.getNtpArraySize(); ++i) {
175  stream.writeIpv4Address(options.getNtp(i));
176  }
177  length += (2 + size);
178  }
179 
180  // Server Identifier
181  if (!options.getServerIdentifier().isUnspecified()) {
182  stream.writeByte(SERVER_ID);
183  stream.writeByte(4);
184  stream.writeIpv4Address(options.getServerIdentifier());
185  length += 6;
186  }
187 
188  // Renewal (T1) Time Value
189  if (!options.getRenewalTime().isZero()) {
190  stream.writeByte(RENEWAL_TIME);
191  stream.writeByte(4);
192  stream.writeUint32Be(options.getRenewalTime().inUnit(SIMTIME_S));
193  length += 2 + 4;
194  }
195 
196  // Rebinding (T2) Time Value
197  if (!options.getRebindingTime().isZero()) {
198  stream.writeByte(REBIND_TIME);
199  stream.writeByte(4);
200  stream.writeUint32Be(options.getRebindingTime().inUnit(SIMTIME_S));
201  length += 2 + 4;
202  }
203 
204  // IP Address Lease Time
205  if (!options.getLeaseTime().isZero()) {
206  stream.writeByte(LEASE_TIME);
207  stream.writeByte(4);
208  stream.writeUint32Be(options.getLeaseTime().inUnit(SIMTIME_S));
209  length += 2 + 4;
210  }
211 
212  // End Option
213  stream.writeByte(255);
214  length += 1;
215 
216  ASSERT(dhcpMessage->getChunkLength() == B(length));
217 }

The documentation for this class was generated from the following files:
inet::SUBNET_MASK
@ SUBNET_MASK
Definition: DhcpMessage_m.h:124
inet::CLIENT_ID
@ CLIENT_ID
Definition: DhcpMessage_m.h:120
inet::PARAM_LIST
@ PARAM_LIST
Definition: DhcpMessage_m.h:123
inet::units::constants::e
const value< double, units::C > e(1.602176487e-19)
inet::DHCP_MSG_TYPE
@ DHCP_MSG_TYPE
Definition: DhcpMessage_m.h:119
inet::DhcpOptionCode
DhcpOptionCode
Enum generated from inet/applications/dhcp/DhcpMessage.msg:35 by opp_msgtool.
Definition: DhcpMessage_m.h:118
inet::REQUESTED_IP
@ REQUESTED_IP
Definition: DhcpMessage_m.h:122
inet::ROUTER
@ ROUTER
Definition: DhcpMessage_m.h:125
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::LEASE_TIME
@ LEASE_TIME
Definition: DhcpMessage_m.h:130
type
removed type
Definition: IUdp-gates.txt:7
inet::DhcpMessageType
DhcpMessageType
Enum generated from inet/applications/dhcp/DhcpMessage.msg:23 by opp_msgtool.
Definition: DhcpMessage_m.h:83
inet::HOSTNAME
@ HOSTNAME
Definition: DhcpMessage_m.h:121
inet::NTP_SRV
@ NTP_SRV
Definition: DhcpMessage_m.h:127
inet::RENEWAL_TIME
@ RENEWAL_TIME
Definition: DhcpMessage_m.h:128
inet::DNS
@ DNS
Definition: DhcpMessage_m.h:126
inet::REBIND_TIME
@ REBIND_TIME
Definition: DhcpMessage_m.h:129
inet::BOOTREQUEST
@ BOOTREQUEST
Definition: DhcpMessage_m.h:60
inet::BOOTREPLY
@ BOOTREPLY
Definition: DhcpMessage_m.h:61
inet::SERVER_ID
@ SERVER_ID
Definition: DhcpMessage_m.h:131