tftp_common  1.3.0
parsers.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "packets.hpp"
4 
5 namespace tftp_common::packets {
6 
8 struct ParseResult {
10  bool Success;
12  std::size_t BytesRead;
13 };
14 
19 ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, Request &Packet) {
20  assert(Buffer != nullptr);
21  assert(Len > 0);
22 
23  std::string Name;
24  std::string Value;
25  std::size_t Step = 0;
26  std::size_t BytesRead = 0;
27  for (std::size_t Idx = 0; Idx != Len; ++Idx) {
28  const auto Byte = Buffer[Idx];
29  BytesRead++;
30 
31  switch (Step) {
32  // Opcode (2 bytes)
33  case 0:
34  Packet.Type_ = std::uint16_t(Byte) << 0;
35  Step++;
36  break;
37  case 1:
38  Packet.Type_ |= std::uint16_t(Byte) << 8;
39  Packet.Type_ = ntohs(Packet.Type_);
40  if (Packet.Type_ != types::ReadRequest && Packet.Type_ != types::WriteRequest) {
41  Step = 0;
42  continue;
43  }
44  Step++;
45  break;
46  // Filename
47  case 2:
48  if (Byte == 0u) {
49  Step++;
50  } else {
51  Packet.Filename.push_back(Byte);
52  }
53  break;
54  // Mode
55  case 3:
56  if (Byte == 0u) {
57  if (Idx == Len - 1) {
58  return ParseResult{true, BytesRead};
59  }
60  Step++;
61  } else {
62  Packet.Mode.push_back(Byte);
63  }
64  break;
65  // Option name
66  case 4:
67  if (Byte == 0u) {
68  Packet.OptionsNames.push_back(std::move(Name));
69  Step++;
70  } else {
71  Name.push_back(Byte);
72  }
73  break;
74  // Option value
75  case 5:
76  if (Byte == 0u) {
77  Packet.OptionsValues.push_back(std::move(Value));
78 
79  if (Idx == Len - 1) {
80  return ParseResult{true, BytesRead};
81  }
82  Step--;
83  } else {
84  Value.push_back(Byte);
85  }
86  break;
87  default:
88  assert(false);
89  }
90  }
91  return ParseResult{false, BytesRead};
92 }
93 
98 ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, Data &Packet) {
99  assert(Buffer != nullptr);
100  assert(Len > 0);
101 
102  std::size_t Step = 0;
103  std::size_t BytesRead = 0;
104  for (std::size_t Idx = 0; Idx != Len; ++Idx) {
105  const auto Byte = Buffer[Idx];
106  BytesRead++;
107 
108  switch (Step) {
109  // Opcode (2 bytes)
110  case 0:
111  Packet.Type_ = std::uint16_t(Byte) << 0;
112  Step++;
113  break;
114  case 1:
115  Packet.Type_ |= std::uint16_t(Byte) << 8;
116  Packet.Type_ = ntohs(Packet.Type_);
117  if (Packet.Type_ != types::DataPacket) {
118  Step = 0;
119  continue;
120  }
121  Step++;
122  break;
123  // Block # (2 bytes)
124  case 2:
125  Packet.Block = std::uint16_t(Byte) << 0;
126  Step++;
127  break;
128  case 3:
129  Packet.Block |= std::uint16_t(Byte) << 8;
130  Packet.Block = ntohs(Packet.Block);
131  Step++;
132  break;
133  // buffer
134  case 4:
135  Packet.DataBuffer.push_back(Byte);
136 
137  if (Idx == Len - 1) {
138  return ParseResult{true, BytesRead};
139  }
140 
141  break;
142  default:
143  assert(false);
144  }
145  }
146  return ParseResult{false, BytesRead};
147 }
148 
153 ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, Acknowledgment &Packet) {
154  assert(Buffer != nullptr);
155  assert(Len > 0);
156 
157  std::size_t Step = 0;
158  std::size_t BytesRead = 0;
159  for (std::size_t Idx = 0; Idx != Len; ++Idx) {
160  const auto Byte = Buffer[Idx];
161  BytesRead++;
162 
163  switch (Step) {
164  // Opcode (2 bytes)
165  case 0:
166  Packet.Type_ = std::uint16_t(Byte) << 0;
167  Step++;
168  break;
169  case 1:
170  Packet.Type_ |= std::uint16_t(Byte) << 8;
171  Packet.Type_ = ntohs(Packet.Type_);
172  if (Packet.Type_ != types::AcknowledgmentPacket) {
173  Step = 0;
174  continue;
175  }
176  Step++;
177  break;
178  // Block # (2 bytes)
179  case 2:
180  Packet.Block = std::uint16_t(Byte) << 0;
181  Step++;
182  break;
183  case 3:
184  Packet.Block |= std::uint16_t(Byte) << 8;
185  Packet.Block = ntohs(Packet.Block);
186  return ParseResult{true, BytesRead};
187  default:
188  assert(false);
189  }
190  }
191  return ParseResult{false, BytesRead};
192 }
193 
198 ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, Error &Packet) {
199  assert(Buffer != nullptr);
200  assert(Len > 0);
201 
202  std::size_t Step = 0;
203  std::size_t BytesRead = 0;
204  for (std::size_t Idx = 0; Idx != Len; ++Idx) {
205  const auto Byte = Buffer[Idx];
206  BytesRead++;
207 
208  switch (Step) {
209  // Opcode (2 bytes)
210  case 0:
211  Packet.Type_ = std::uint16_t(Byte) << 0;
212  Step++;
213  break;
214  case 1:
215  Packet.Type_ |= std::uint16_t(Byte) << 8;
216  Packet.Type_ = ntohs(Packet.Type_);
217  if (Packet.Type_ != types::ErrorPacket) {
218  Step = 0;
219  continue;
220  }
221  Step++;
222  break;
223  // ErrorCode (2 bytes)
224  case 2:
225  Packet.ErrorCode = std::uint16_t(Byte) << 0;
226  Step++;
227  break;
228  case 3:
229  Packet.ErrorCode |= std::uint16_t(Byte) << 8;
230  Packet.ErrorCode = ntohs(Packet.ErrorCode);
231  Step++;
232  break;
233  // ErrorMessage
234  case 4:
235  if (Byte == 0u) {
236  return ParseResult{true, BytesRead};
237  } else {
238  Packet.ErrorMessage.push_back(Byte);
239  }
240  break;
241  default:
242  assert(false);
243  }
244  }
245  return ParseResult{false, BytesRead};
246 }
247 
252 ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, OptionAcknowledgment &Packet) {
253  assert(Buffer != nullptr);
254  assert(Len > 0);
255 
256  std::string Name;
257  std::string Value;
258  std::size_t Step = 0;
259  std::size_t BytesRead = 0;
260  for (std::size_t Idx = 0; Idx != Len; ++Idx) {
261  const auto Byte = Buffer[Idx];
262  BytesRead++;
263 
264  switch (Step) {
265  // Opcode (2 bytes)
266  case 0:
267  Packet.Type_ = std::uint16_t(Byte) << 0;
268  Step++;
269  break;
270  case 1:
271  Packet.Type_ |= std::uint16_t(Byte) << 8;
272  Packet.Type_ = ntohs(Packet.Type_);
273  if (Packet.Type_ != types::OptionAcknowledgmentPacket) {
274  Step = 0;
275  continue;
276  }
277  Step++;
278  break;
279  // Option name
280  case 2:
281  if (Byte == 0u)
282  Step++;
283  else
284  Name.push_back(Byte);
285  break;
286  // Option value
287  case 3:
288  if (Byte == 0u) {
289  Packet.Options.emplace(std::move(Name), std::move(Value));
290 
291  if (Idx == Len - 1) {
292  return ParseResult{true, BytesRead};
293  }
294  Step--;
295  } else {
296  Value.push_back(Byte);
297  }
298  break;
299  default:
300  assert(false);
301  }
302  }
303  return ParseResult{false, BytesRead};
304 }
305 
306 } // namespace tftp_common::packets
Acknowledgment Trivial File Transfer Protocol packet.
Definition: packets.hpp:219
Data Trivial File Transfer Protocol packet.
Definition: packets.hpp:166
Error Trivial File Transfer Protocol packet.
Definition: packets.hpp:253
Option Acknowledgment Trivial File Transfer Protocol packet.
Definition: packets.hpp:301
Read/Write Request (RRQ/WRQ) Trivial File Transfer Protocol packet.
Definition: packets.hpp:77
@ AcknowledgmentPacket
Acknowledgment (ACK) operation code.
Definition: packets.hpp:31
@ ReadRequest
Read request (RRQ) operation code.
Definition: packets.hpp:25
@ OptionAcknowledgmentPacket
Option Acknowledgment (OACK) operation code.
Definition: packets.hpp:35
@ DataPacket
Data (DATA) operation code.
Definition: packets.hpp:29
@ WriteRequest
Write request (WRQ) operation code.
Definition: packets.hpp:27
@ ErrorPacket
Error (ERROR) operation code.
Definition: packets.hpp:33
Definition: packets.hpp:16
ParseResult parse(const std::uint8_t *Buffer, std::size_t Len, Request &Packet)
Definition: parsers.hpp:19
The result of parsing a single packet.
Definition: parsers.hpp:8
bool Success
if the parsing was successful
Definition: parsers.hpp:10
std::size_t BytesRead
count of bytes read
Definition: parsers.hpp:12