Flow 2.0.0
Flow project: Full implementation reference.
low_lvl_packet.cpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
20
21namespace flow::net_flow
22{
23
24// Note: In this file, it felt more readable to group methods/etc. by signature instead of by class/struct.
25
26// Static initializations.
27
28const boost::unordered_map<std::type_index, Low_lvl_packet::Packet_type_info>
30 ({
31 // { m_raw_type_id, m_type_id_str } Careful! The m_raw_type_id values must not conflict.
32 { std::type_index(typeid(Syn_packet)),
33 { 0, "SYN" } },
34 { std::type_index(typeid(Syn_ack_packet)),
35 { 1, "SYN_ACK" } },
36 { std::type_index(typeid(Syn_ack_ack_packet)),
37 { 2, "SYN_ACK_ACK" } },
38 { std::type_index(typeid(Data_packet)),
39 { 3, "DATA" } },
40 { std::type_index(typeid(Ack_packet)),
41 { 4, "ACK" } },
42 { std::type_index(typeid(Rst_packet)),
43 { 5, "RST" } }
44 });
45
46// Implementations.
47
49 m_reserved2(0) // This guy is const and is always to be zero.
50{
51 // The rest remains uninitialized, as advertised.
52}
53
55 log::Log_context(logger, Flow_log_component::S_NET_FLOW),
56 /* This bit of cleverness creates an ostream manipulator: if f passed to `os <<`, then f(os) is called.
57 * So in this case, this->type_to_ostream(os), where os is the ostream&, will be called.
58 * Caution: This is scary, because type_to_ostream() makes virtual call, which is not OK to call in constructor in
59 * C++, since the vtable won't be set up yet, and the wrong method will be called; but we are not CALLING it;
60 * we are taking a pointer to something that'll be filled out by the time it's used later on. It works fine;
61 * just don't try using it with an actual stream IN the constructor. */
62 m_type_ostream_manip([this](std::ostream& os) -> std::ostream& { return type_to_ostream(os); }),
63 m_verbose_ostream_manip([this](std::ostream& os) -> std::ostream& { return to_ostream(os, true); }),
64 m_concise_ostream_manip([this](std::ostream& os) -> std::ostream& { return to_ostream(os, false); })
65{
66 // Note: Lots of uninitialized values, as advertised.
67}
68
70 Low_lvl_packet(logger),
71 m_serialized_metadata(logger)
72{
73 // Note: Lots of uninitialized values.
74}
75
77 Low_lvl_packet(logger)
78{
79 // Note: Lots of uninitialized values.
80}
81
83 Low_lvl_packet(logger)
84{
85 // Note: Lots of uninitialized values.
86}
87
89 Low_lvl_packet(logger),
90 m_rexmit_id(0), // If !m_opt_rexmit_on, then this will be expected to remain 0. Initialize to avoid worrying.
91 m_data(logger)
92{
93 // Note: Lots of uninitialized values.
94}
95
97 Low_lvl_packet(logger)
98{
99 // Note: Lots of uninitialized values.
100}
101
103 Low_lvl_packet(logger)
104{
105 // Nothing further.
106}
107
108const std::string& Low_lvl_packet::type_id_to_str(const std::type_index& type_id) // Static.
109{
110 using std::type_index;
111
112 assert(type_id != type_index(typeid(Low_lvl_packet)));
113 const auto it = S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO.find(type_id);
114 assert(it != S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO.end());
115
116 return it->second.m_type_id_str;
117}
118
119const uint8_t& Low_lvl_packet::type_id_native_to_raw(const std::type_info& type_id)
120{
121 using std::type_index;
122
123 assert(type_id != typeid(Low_lvl_packet));
124 const auto it = S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO.find(type_index(type_id));
125 assert(it != S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO.end());
126
127 return it->second.m_raw_type_id;
128}
129
131{
133 using std::ostream;
134
135 const size_t size = serialize_to_raw_data(raw_bufs);
136
137 auto const logger_ptr = get_logger();
138 if (logger_ptr && logger_ptr->should_log(log::Sev::S_TRACE, get_log_component()))
139 {
140 if (logger_ptr->should_log(log::Sev::S_DATA, get_log_component()))
141 {
143 ("Serialized Low_lvl_packet [" << this << "] of type [" << m_type_ostream_manip << "]; "
144 "total added output size [" << size << "] bytes; final buffer contents including added output: "
145 "[\n" << buffers_dump_string(*raw_bufs, " ") << "].");
146 }
147 else
148 {
150 ("Serialized Low_lvl_packet [" << this << "] of type [" << m_type_ostream_manip << "]; "
151 "total added output size [" << size << "] bytes.");
152 }
153 }
154
155 return size;
156}
157
159{
160 using boost::asio::const_buffer;
161 using std::type_index;
162
163 // Reminder: We're not encoding a full packet here. Just the Common Header, starting with the type specifier.
164
165 // Reminder: Keep raw_bufs->size() low, as explained near UDP async_send_to() call!
166
167 /* Look up the statically stored constant raw type ID corresponding to the true polymorphic type of `*this`.
168 * Provide the direct adress of that place in memory as part of the "scattered" serialized data. */
169 const auto& raw_type_id_ref = type_id_native_to_raw(typeid(*this)); // Important subtlety: This returns a reference.
170 // As long as this is true, we need not worry about byte order for, specifically, the raw type ID.
171 static_assert(sizeof raw_type_id_ref == 1,
172 "Raw packet type ID should be small enough for byte ordering to be a non-issue.");
173 size_t size = sizeof raw_type_id_ref;
174 raw_bufs->push_back(const_buffer(&raw_type_id_ref, size));
175
176 /* Subtlety: Now we just have to write the m_opt_rexmit_on flag byte, followed by two reserved 0 bytes.
177 * The subleties are:
178 * - The byte does not equal the bool m_opt_rexmit_on bit-wise and needs to be specially encoded.
179 * So the byte needs to be stored separately, so that a buffer pointer to it can be added
180 * to *raw_bufs. We can't just refer to some transient local object memory, as that will go away,
181 * once some { block } exits!
182 * It has to be permanent (while *this exists).
183 * - Same deal with the reserved 0 bytes.
184 *
185 * So use m_aux_raw_data to store that stuff. The reserved bytes are already set. Save the flag. */
187 raw_bufs->push_back(const_buffer(&m_aux_raw_data.m_opt_rexmit_on_raw,
189 size += raw_bufs->back().size();
190
191 // Subtlety: These are stored together in packed fashion, so refer to them in one buffer.
192 raw_bufs->push_back(const_buffer(&m_packed.m_src_port, sizeof m_packed.m_src_port + sizeof m_packed.m_dst_port));
193 size += raw_bufs->back().size();
194
195 return size;
196}
197
199{
200 using boost::asio::const_buffer;
201
202 /* Important: We directly copy various integers from memory into packet. That is only OK if
203 * the chosen network encoding convention equals that of this machine's endianness.
204 * If not, we'll need to write considerably more complex code, since flipped versions of such
205 * integers would need to be stored as well as the real versions. (Performance-wise, using
206 * the "scatter" technique would still be worthwhile, since large areas like Data_packet::m_data
207 * are stored in exact order and need no flipping. @todo Revisit but only if this assertion actually trips.
208 *
209 * We've intentionally chosen little-endian as the network byte order, since most platforms natively use it
210 * in memory (x86, etc.).
211 *
212 * Note that this technique is the basis of various "zero-copy" [de]serializers such as Cap'n Proto. */
213 static_assert(!native_is_big_endian(),
214 "Byte ordering in this platform is not conducive to zero-copy serialization.");
215
216 // Common header = type ID + common fields.
217 size_t size = serialize_common_header_to_raw_data(raw_bufs);
218
219 // Then our own stuff.
220
221 const auto* raw_seq_num = &(m_init_seq_num.raw_num_ref());
222 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
223 size += sizeof *raw_seq_num;
224
225 if (!m_serialized_metadata.empty())
226 {
227 raw_bufs->push_back(const_buffer(m_serialized_metadata.const_data(), m_serialized_metadata.size()));
228 size += m_serialized_metadata.size();
229 }
230
231 return size;
232}
233
235{
236 using boost::asio::const_buffer;
237
238 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
239
240 static_assert(!native_is_big_endian(),
241 "Byte ordering in this platform is not conducive to zero-copy serialization.");
242
243 // Common header = type ID + common fields.
244 size_t size = serialize_common_header_to_raw_data(raw_bufs);
245
246 const Sequence_number::seq_num_t* raw_seq_num = &(m_init_seq_num.raw_num_ref());
247 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
248 size += sizeof *raw_seq_num;
249
250 // Subtlety: These are stored together in packed fashion, so refer to them in one buffer.
251 raw_bufs->push_back(const_buffer(&m_packed.m_security_token,
252 sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd));
253 size += raw_bufs->back().size();
254
255 return size;
256}
257
259{
260 using boost::asio::const_buffer;
261
262 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
263
264 static_assert(!native_is_big_endian(),
265 "Byte ordering in this platform is not conducive to zero-copy serialization.");
266
267 // Common header = type ID + common fields.
268 size_t size = serialize_common_header_to_raw_data(raw_bufs);
269
270 // Subtlety: These are stored together in packed fashion, so refer to them in one buffer.
271 raw_bufs->push_back(const_buffer(&m_packed.m_security_token,
272 sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd));
273 size += raw_bufs->back().size();
274
275 return size;
276}
277
279{
280 using boost::asio::const_buffer;
281 using std::numeric_limits;
282
283 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
284
285 // Reminder: Keep raw_bufs->size() low, as explained near UDP async_send_to() call!
286
287 static_assert(!native_is_big_endian(),
288 "Byte ordering in this platform is not conducive to zero-copy serialization.");
289
290 // Common header = type ID + common fields.
291 size_t size = serialize_common_header_to_raw_data(raw_bufs);
292
293 const Sequence_number::seq_num_t* raw_seq_num = &(m_seq_num.raw_num_ref());
294 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
295 size += sizeof *raw_seq_num;
296
297 if (m_opt_rexmit_on)
298 {
299 raw_bufs->push_back(const_buffer(&m_rexmit_id, sizeof m_rexmit_id));
300 size += sizeof m_rexmit_id;
301 }
302
303 assert(!m_data.empty());
304
305 // Serialize this, even though it's not strictly required, for reasons explained near deserialization code.
306 const size_t data_size = m_data.size();
307 using data_size_raw_t = decltype(m_data_size_raw);
308 assert(data_size <= numeric_limits<data_size_raw_t>::max());
309
310 m_data_size_raw = data_size_raw_t(data_size);
311 raw_bufs->push_back(const_buffer(&m_data_size_raw, sizeof m_data_size_raw));
312 size += sizeof m_data_size_raw;
313
314 raw_bufs->push_back(const_buffer(m_data.const_data(), data_size));
315 size += m_data.size();
316
317 return size;
318}
319
321{
322 using boost::asio::const_buffer;
323 using std::numeric_limits;
324
325 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
326
327 // Reminder: Keep raw_bufs->size() low, as explained near UDP async_send_to() call!
328
329 static_assert(!native_is_big_endian(),
330 "Byte ordering in this platform is not conducive to zero-copy serialization.");
331
332 // Common header = type ID + common fields.
333 size_t size = serialize_common_header_to_raw_data(raw_bufs);
334
335 raw_bufs->push_back(const_buffer(&m_rcv_wnd, sizeof m_rcv_wnd));
336 size += sizeof m_rcv_wnd;
337
338 // Serialize this, even though it's not strictly required, for reasons explained near deserialization code.
339 const size_t pkts_size = m_opt_rexmit_on
340 ? m_rcv_acked_packets_rexmit_on_out.size()
341 : m_rcv_acked_packets_rexmit_off_out.size();
342 using pkts_size_t = decltype(m_rcv_acked_packets_rexmit_out_size);
343 assert(pkts_size <= numeric_limits<pkts_size_t>::max());
344
345 m_rcv_acked_packets_rexmit_out_size = pkts_size_t(pkts_size);
346 raw_bufs->push_back(const_buffer(&m_rcv_acked_packets_rexmit_out_size, sizeof(pkts_size_t)));
347 size += sizeof(pkts_size_t);
348
349 /* The following reaps the benefits of arranging the individual acks in a packed array or packed structures
350 * that are pre-serialized. In the past, this instead used scatter-gather semantics to cherry-pick parts of
351 * each ack and, for example, simply omitting the inapplicable m_rexmit_id when rexmit_on was false.
352 * There was thus no need for m_rcv_acked_packets_rexmit_*_out -- m_rcv_acked_packets was used for both
353 * incoming and outgoing packets. However, we then ran into the aforementioned UDP async_send_to() limitation
354 * at least for some platforms. This encouraged the optimization you see now -- which has the benefit of
355 * being better-performing in any case. The code, however, is arguably more complex (not in this function
356 * but elsewhere, with 2 more structs being needed. */
357 if (m_opt_rexmit_on)
358 {
359 raw_bufs->push_back(const_buffer(m_rcv_acked_packets_rexmit_on_out.data(),
360 m_rcv_acked_packets_rexmit_on_out.size()
361 * sizeof(decltype(m_rcv_acked_packets_rexmit_on_out)::value_type)));
362 }
363 else
364 {
365 raw_bufs->push_back(const_buffer(m_rcv_acked_packets_rexmit_off_out.data(),
366 m_rcv_acked_packets_rexmit_off_out.size()
367 * sizeof(decltype(m_rcv_acked_packets_rexmit_off_out)::value_type)));
368 }
369 size += raw_bufs->back().size();
370
371 return size;
372}
373
375{
376 // Common header = type ID + common fields. We add nothing else.
377 return serialize_common_header_to_raw_data(raw_bufs);
378}
379
381 bool prefer_no_move) // Static.
382{
384 using boost::asio::buffer;
385 using boost::asio::const_buffer;
386 using boost::endian::little_to_native;
387 using std::ostream;
388
389 Const_buffer raw_buf(raw_packet->const_data(), raw_packet->size());
390
391 // Make FLOW_LOG_...() calls below use these (we are static).
392 FLOW_LOG_SET_CONTEXT(logger_ptr, Flow_log_component::S_NET_FLOW);
393
394 const size_t raw_buf_size = raw_buf.size();
395
397 ("Deserializing Low_lvl_packet; "
398 "total raw buffer size [" << raw_buf_size << "] bytes; buffer contents: "
399 "[\n" << buffers_dump_string(raw_buf, " ") << "].");
400
401 /* The basic structure of raw_buf is as follows:
402 * - Common Header:
403 * - The raw type ID, which indicates what is after the Common Header.
404 * - We'll create the appropriate Low_lvl_packet sub-type object based on this.
405 * - Certain common fields that apply to all.
406 * - We'll fill those out in the Low_lvl_packet (super-type) area of the the just-created object.
407 * - Type-specific data:
408 * - We hand off the partially filled object and the remaining buffer to a virtual method that
409 * will appropriately fill the rest of the object. */
410
411 // This is the expected size of the Common Header mentioned above.
412 const size_t common_data_size
413 = sizeof(uint8_t) + sizeof m_packed.m_src_port + sizeof m_packed.m_dst_port
415
416 if (raw_buf_size < common_data_size)
417 {
418 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet is too small: "
419 "[" << raw_buf_size << "] bytes.");
420 return Ptr();
421 }
422
423 /* We'll advance this as we keep reading off values from raw buffer.
424 * Could also use += on *raw_buf, but I don't feel like cast<>ing all the time.
425 * Would rather reinterpret_cast<> due to it being the devil I know. Doesn't really matter. */
426
427 const uint8_t* common_data = static_cast<const uint8_t*>(raw_buf.data());
428 // Meanwhile, this guy can skip past the entire Common Header. We'll check that it matches common_data at the end.
429 raw_buf = raw_buf + common_data_size;
430
431 // Get the type specifier.
432 const auto& raw_type_id = *common_data;
433 common_data += sizeof raw_type_id;
434
435 /* The type specifier determines the polymorphic type we choose. It is not actually recorded.
436 * C++ keeps typeid() which performs that task for us without us having to do it explicitly. */
437 Ptr packet
438 = (raw_type_id == type_id_native_to_raw(typeid(Syn_packet)))
439 ? create_uninit_packet_base<Syn_packet>(logger_ptr)
440 : ((raw_type_id == type_id_native_to_raw(typeid(Syn_ack_packet)))
441 ? create_uninit_packet_base<Syn_ack_packet>(logger_ptr)
442 : ((raw_type_id == type_id_native_to_raw(typeid(Syn_ack_ack_packet)))
443 ? create_uninit_packet_base<Syn_ack_ack_packet>(logger_ptr)
444 : ((raw_type_id == type_id_native_to_raw(typeid(Data_packet)))
445 ? create_uninit_packet_base<Data_packet>(logger_ptr)
446 : ((raw_type_id == type_id_native_to_raw(typeid(Ack_packet)))
447 ? create_uninit_packet_base<Ack_packet>(logger_ptr)
448 : ((raw_type_id == type_id_native_to_raw(typeid(Rst_packet)))
449 ? create_uninit_packet_base<Rst_packet>(logger_ptr)
450 : Ptr())))));
451 if (!packet)
452 {
453 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet type is invalid: "
454 "[" << int(raw_type_id) << "].");
455 return packet;
456 }
457
458 using opt_rexmit_on_raw_t = decltype(Aux_raw_data::m_opt_rexmit_on_raw);
459 const auto& opt_rexmit_on_raw
460 = *reinterpret_cast<const opt_rexmit_on_raw_t*>(common_data);
461 common_data += sizeof opt_rexmit_on_raw;
462 packet->m_opt_rexmit_on = (opt_rexmit_on_raw != 0);
463
464 using reserved2_t = decltype(Aux_raw_data::m_reserved2);
465 const auto& reserved2 = *reinterpret_cast<const reserved2_t*>(common_data);
466 common_data += sizeof reserved2;
467 if (reserved2 != 0)
468 {
469 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet format is unknown.");
470 return Ptr();
471 }
472 // else
473
474 const auto& src_port_raw = *reinterpret_cast<const flow_port_t*>(common_data);
475 common_data += sizeof src_port_raw;
476 packet->m_packed.m_src_port = little_to_native(src_port_raw);
477
478 const auto& dst_port_raw = *reinterpret_cast<const flow_port_t*>(common_data);
479 common_data += sizeof dst_port_raw;
480 packet->m_packed.m_dst_port = little_to_native(dst_port_raw);
481
482 // Did we claculate the total size of Common Header correctly at the start?
483 assert(common_data == static_cast<const uint8_t*>(raw_buf.data()));
484
485 FLOW_LOG_TRACE("Deserialized packet [" << packet << "] common info: "
486 "NetFlow ports [" << packet->m_packed.m_src_port << "] -> [" << packet->m_packed.m_dst_port << "]; "
487 "opt_rexmit_on = [" << packet->m_opt_rexmit_on << "]; "
488 "common serialized size was [" << common_data_size << "].");
489
490 // Low_lvl_packet part is filled out. The sub-type part has junk. This will fill that part out.
491 if (!packet->deserialize_type_specific_data_from_raw_data_packet(&raw_buf, prefer_no_move, raw_packet))
492 {
493 return Ptr(); // Error. It logged.
494 }
495 // else
496
497 // raw_packet is not in valid but unknown state. Do not use.
498
499 if (logger_ptr && logger_ptr->should_log(log::Sev::S_TRACE, get_log_component()))
500 {
501 const bool data_sev = logger_ptr->should_log(log::Sev::S_DATA, get_log_component());
503 "Deserialized packet: Final version: "
504 "[\n"
505 << (data_sev ? packet->m_verbose_ostream_manip : packet->m_concise_ostream_manip)
506 << "].");
507 }
508
509 return packet;
510} // Low_lvl_packet::create_from_raw_data_packet()
511
513 [[maybe_unused]] bool prefer_no_move,
514 [[maybe_unused]] util::Blob* raw_packet)
515 // Virtual.
516{
517 using boost::asio::buffer;
518 using boost::endian::little_to_native;
519
520 // Structure: a few required fields; then arbitrary-length metadata buffer.
521
522 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
523
524 const size_t min_data_size = sizeof(Sequence_number::seq_num_t);
525 const size_t raw_buf_size = raw_buf->size();
526 if (raw_buf_size < min_data_size)
527 {
528 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
529 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
530 return false;
531 }
532 // else
533
534 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
535 (*raw_buf) = ((*raw_buf) + min_data_size);
536
537 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
538 data += sizeof seq_num_raw;
539 m_init_seq_num.set_raw_num(little_to_native(seq_num_raw));
540 /* Set some metadata. Subleties:
541 * The 'type' we know and can set sans controversy. It's the number line for remote-originated data.
542 * The multiple is, if anything, max-block-size, which we don't know, since we don't yet know socket for this,
543 * (if it's even legal at all).
544 * The zero point is the ISN + 1, and since we *are* the ISN, we could actually set it here. Pragmatically,
545 * however, it's nice to log the absolute raw number at this point and turn everything to nice relative values
546 * after that; so leave the applying of ISN to this until `sock` is detected. Note, also, that this is consistent
547 * with what's done for Data_packet and Ack_packet (though, to be fair, for those there is no choice, as ISN is
548 * not known without socket). */
550
551 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
552
553 const size_t n_copied = m_serialized_metadata.assign_copy(*raw_buf);
554 assert(n_copied == m_serialized_metadata.size());
555
556 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
557 "ISN [" << m_init_seq_num << "]; "
558 "metadata size ["<< n_copied << "] bytes; "
559 "serialized size beyond common header was [" << raw_buf_size << "].");
560
561 return true;
562} // Syn_packet::deserialize_type_specific_data_from_raw_data_packet()
563
565 [[maybe_unused]] bool prefer_no_move,
566 [[maybe_unused]] util::Blob* raw_packet)
567 // Virtual.
568{
569 using boost::endian::little_to_native;
570
571 // Structure: a few required fields; and that's it.
572
573 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
574
575 const size_t exp_data_size = sizeof(Sequence_number::seq_num_t)
576 + sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd;
577 const size_t raw_buf_size = raw_buf->size();
578 if (raw_buf_size != exp_data_size)
579 {
580 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
581 "packet: The packet is of wrong size: ["<< raw_buf_size << "] bytes.");
582 return false;
583 }
584 // else
585
586 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
587 (*raw_buf) = ((*raw_buf) + exp_data_size);
588
589 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
590 data += sizeof seq_num_raw;
591 m_init_seq_num.set_raw_num(little_to_native(seq_num_raw));
592 // See comment in same place for Syn_packet.
594
595 const auto& security_token_raw = *reinterpret_cast<const security_token_t*>(data);
596 data += sizeof security_token_raw;
597 m_packed.m_security_token = little_to_native(security_token_raw);
598
599 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
600 data += sizeof rcv_wnd_raw;
601 m_packed.m_rcv_wnd = little_to_native(rcv_wnd_raw);
602
603 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
604
605 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
606 "ISN [" << m_init_seq_num << "]; "
607 "rcv_wnd ["<< m_packed.m_rcv_wnd << "] bytes; "
608 "serialized size beyond common header was [" << raw_buf_size << "].");
609
610 return true;
611} // Syn_ack_packet::deserialize_type_specific_data_from_raw_data_packet()
612
614 [[maybe_unused]] bool prefer_no_move,
615 [[maybe_unused]] util::Blob* raw_packet)
616 // Virtual.
617{
618 using boost::endian::little_to_native;
619
620 // Structure: a few required fields; and that's it.
621
622 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
623
624 const size_t exp_data_size = sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd;
625 const size_t raw_buf_size = raw_buf->size();
626 if (raw_buf_size != exp_data_size)
627 {
628 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
629 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
630 return false;
631 }
632 // else
633
634 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
635 (*raw_buf) = ((*raw_buf) + exp_data_size);
636
637 const auto& security_token_raw = *reinterpret_cast<const security_token_t*>(data);
638 data += sizeof security_token_raw;
639 m_packed.m_security_token = little_to_native(security_token_raw);
640
641 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
642 data += sizeof rcv_wnd_raw;
643 m_packed.m_rcv_wnd = little_to_native(rcv_wnd_raw);
644
645 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
646
647 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
648 "rcv_wnd ["<< m_packed.m_rcv_wnd << "] bytes; "
649 "serialized size beyond common header was [" << raw_buf_size << "].");
650
651 return true;
652} // Syn_ack_ack_packet::deserialize_type_specific_data_from_raw_data_packet()
653
655 bool prefer_no_move,
656 util::Blob* raw_packet) // Virtual.
657{
658 using boost::asio::buffer;
659 using boost::endian::little_to_native;
660 using std::numeric_limits;
661 using std::memcpy;
662
663 using data_size_raw_t = decltype(m_data_size_raw);
664
665 // Structure: a few required fields; then the arbitrarily-long (but not 0-length) data payload.
666
667 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
668
669 const size_t min_data_size
670 = sizeof(Sequence_number::seq_num_t) + (m_opt_rexmit_on ? sizeof m_rexmit_id : 0) + sizeof(data_size_raw_t);
671 const size_t raw_buf_size = raw_buf->size();
672 if (raw_buf_size < min_data_size)
673 {
674 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
675 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
676 return false;
677 }
678 // else
679
680 const uint8_t* cur_data = static_cast<const uint8_t*>(raw_buf->data());
681 (*raw_buf) = ((*raw_buf) + min_data_size);
682
683 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(cur_data);
684 cur_data += sizeof seq_num_raw;
685 m_seq_num.set_raw_num(little_to_native(seq_num_raw));
686 // Remote seq. # line, but we don't (yet) know for which socket, so max-block-size and ISN are (for now) unknown.
688
689 if (m_opt_rexmit_on)
690 {
691 const auto& rexmit_id_raw = *reinterpret_cast<const rexmit_id_t*>(cur_data);
692 cur_data += sizeof rexmit_id_raw;
693 m_rexmit_id = little_to_native(rexmit_id_raw);
694 }
695
696 /* m_data.size() is encoded separately, even though we could figure it out simply by counting the bytes not yet
697 * deserialized to this point. The reason is that I've seen, in practice, silent truncation occur; for example
698 * with Boost 1.63 on Mac, at least, using more than ~64 scatter/gather buffers when invoking UDP sendto() caused
699 * the over-that-silent-limit buffers to simply be ignored. (Another reason is the existing socket options
700 * mechanism in this library makes it very difficult to ensure Node_options::m_dyn_low_lvl_max_packet_size is
701 * sufficiently larger than Peer_socket_options::m_st_max_block_size (because they are not both per-Node or
702 * both per-socket -- trust me, I tried, but thread considerations made checking this at all appropriate times
703 * either extremely hard or even impossible). So it has to be checked outside option checking time, but it can't
704 * be done at receipt time, because at that point the Peer_socket from which to obtain m_st_max_block_size is not
705 * yet known; one has to deserialize packet to get at that... but at that point it's kind of too late.) So all
706 * these issues can be sanity-checked away by encoding the expected size up-front and then ensuring the actual
707 * data area matches this exactly. To be clear, there are certainly ways to avoid it -- but then one must constantly
708 * be aware of it; whereas using a couple of bytes to do this eliminates that problem at a fairly low cost.
709 * @todo Revisit this sometime. */
710
711 data_size_raw_t data_size_raw;
712 // Using `= *reinterpret_cast<...*>` makes UBSAN complain; so humor it by using explicit memcpy().
713 memcpy(&data_size_raw, cur_data, sizeof data_size_raw);
714 cur_data += sizeof data_size_raw;
715
716 data_size_raw = little_to_native(data_size_raw);
717
718 if (data_size_raw == 0)
719 {
720 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
721 "packet: The data area specifies empty size.");
722 return false;
723 }
724 // else
725
726 assert(cur_data == static_cast<const uint8_t*>(raw_buf->data()));
727
728 // The rest of the buffer = the data payload.
729 const size_t data_size = raw_buf->size();
730
731 if ((data_size > numeric_limits<data_size_raw_t>::max()) // Don't let overflow fools us or something like that.
732 || (data_size_raw_t(data_size) != data_size_raw))
733 {
734 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
735 "packet: The data area specifies size [" << data_size_raw << "] but has "
736 "actual size [" << data_size << "]. Did truncation occur somewhere?");
737 return false;
738 }
739 // else
740
741 /* Subtlety: m_data, to store the DATA payload itself, will consist of the entire raw packet data but with
742 * its logical [begin(), end) range starting past the header and other stuff, right where the payload begins.
743 * This allows us to MOVE instead of (slowly) copying (part of) raw_packet into m_data -- but then still treat m_data
744 * as if it's just the payload itself and not the entire packet. (In point of fact, as of this writing, m_data will
745 * be further moved into Socket_buffer Receive buffer, again via a constant-time move.) This way we sacrifice a small
746 * memory overhead for major eliminating of copying.
747 *
748 * Update: The caller may now specify to make a copy instead. Why this might be done is explained elsewhere, where
749 * it is decided. */
750
751 // First move over the entire raw packet.
752 if (prefer_no_move)
753 {
754 m_data.assign_copy(*raw_buf);
755 }
756 else
757 {
758 m_data = std::move(*raw_packet);
759 // Then shift begin() right to where the payload begins (size() adjusted down accordingly).
760 m_data.start_past_prefix(cur_data - m_data.const_data());
761 assert(m_data.const_begin() == cur_data);
762 }
763 // m_data.[begin, end()) range is now the right thing, regardless of how it got there.
764 assert(m_data.size() == data_size);
765
766 if (m_opt_rexmit_on)
767 {
768 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
769 "sequence number [" << m_seq_num << "] rexmit_id [" << int(m_rexmit_id) << "]; "
770 "user data size [" << data_size << "] (" << (prefer_no_move ? "copied" : "moved") << "); "
771 "serialized size beyond common header was [" << raw_buf_size << "].");
772 }
773 else
774 {
775 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
776 "sequence number [" << m_seq_num << "]; "
777 "user data size [" << data_size << "] (" << (prefer_no_move ? "copied" : "moved") << "); "
778 "serialized size beyond common header was [" << raw_buf_size << "].");
779 }
780
781 return true;
782} // Data_packet::deserialize_type_specific_data_from_raw_data_packet()
783
785 [[maybe_unused]] bool prefer_no_move,
786 [[maybe_unused]] util::Blob* raw_packet)
787 // Virtual.
788{
789 using boost::endian::little_to_native;
790 using std::numeric_limits;
791
792 using pkts_size_raw_t = decltype(m_rcv_acked_packets_rexmit_out_size);
793
794 // Structure: a few required fields; then 0 or more acknowledgments, each consisting of constant # of fields.
795
796 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
797
798 const size_t min_data_size = sizeof m_rcv_wnd + sizeof(pkts_size_raw_t);
799 const size_t raw_buf_size = raw_buf->size();
800 if (raw_buf_size < min_data_size)
801 {
802 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
803 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
804 return false;
805 }
806 // else
807
808 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
809 (*raw_buf) = ((*raw_buf) + min_data_size);
810
811 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
812 data += sizeof rcv_wnd_raw;
813 m_rcv_wnd = little_to_native(rcv_wnd_raw);
814
815 /* m_rcv_acked_packets.size() is encoded separately, even though we could figure it out by counting the bytes not yet
816 * deserialized to this point and dividing by size of each individual ack. The reason is explained in a similar
817 * comment in Data_packet::deserialize_type_specific_data_from_raw_data_packet() -- see that comment. */
818 auto pkts_size_raw = *reinterpret_cast<const pkts_size_raw_t*>(data);
819 data += sizeof pkts_size_raw;
820 pkts_size_raw = little_to_native(pkts_size_raw);
821
822 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
823
824 const size_t ack_size
825 = sizeof(Sequence_number::seq_num_t) + sizeof(ack_delay_t) + (m_opt_rexmit_on ? sizeof(rexmit_id_t) : 0);
826 const size_t n_acks = raw_buf->size() / ack_size; // Note: rounds down.
827 (*raw_buf) = ((*raw_buf) + (n_acks * ack_size));
828
829 if ((n_acks > numeric_limits<pkts_size_raw_t>::max()) // Don't let overflow fools us or something like that.
830 || (pkts_size_raw_t(n_acks) != pkts_size_raw))
831 {
832 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
833 "packet: The individual acks area specifies [" << pkts_size_raw << "] acks but has "
834 "actual ack count [" << n_acks << "]. Did truncation occur somewhere?");
835 return false;
836 }
837 // else
838
839 m_rcv_acked_packets.clear();
840 m_rcv_acked_packets.reserve(n_acks);
841
842 for (size_t ack_idx = 0; ack_idx != n_acks; ++ack_idx)
843 {
844 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
845 data += sizeof seq_num_raw;
846 Sequence_number seq_num;
847 seq_num.set_raw_num(little_to_native(seq_num_raw));
848 // Local seq. # line, but we don't (yet) know for which socket, so max-block-size and ISN are (for now) unknown.
849 seq_num.set_metadata('L');
850
851 const auto& ack_delay_raw = *reinterpret_cast<const ack_delay_t*>(data);
852 data += sizeof ack_delay_raw;
853 const Fine_duration ack_delay
854 = Ack_delay_time_unit(little_to_native(ack_delay_raw));
855
856 unsigned int rexmit_id;
857 if (m_opt_rexmit_on)
858 {
859 const auto& rexmit_id_raw = *reinterpret_cast<const rexmit_id_t*>(data);
860 data += sizeof rexmit_id_raw;
861 rexmit_id = static_cast<unsigned int>(little_to_native(rexmit_id_raw));
862 }
863 else
864 {
865 rexmit_id = 0;
866 }
867
868 m_rcv_acked_packets.push_back(Individual_ack::Ptr(new Individual_ack{ seq_num, ack_delay, rexmit_id }));
869 } // for (all acks)
870
871 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
872
873 // If the acks area was not an exact multiple of size of each ack, then bytes will be left over (bad).
874
875 const size_t remaining_buf_size = raw_buf->size();
876 if (remaining_buf_size != 0)
877 {
878 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] packet: "
879 "Unexpected trailing data: [" << remaining_buf_size << "] bytes.");
880 return false;
881 }
882 // else
883
884 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
885 "[" << m_rcv_acked_packets.size() << "] individual acks; "
886 "rcv_wnd [" << m_rcv_wnd << "]; "
887 "serialized size beyond common header was [" << raw_buf_size << "].");
888
889 return true;
890} // Ack_packet::deserialize_type_specific_data_from_raw_data_packet()
891
893 [[maybe_unused]] bool prefer_no_move,
894 [[maybe_unused]] util::Blob* raw_packet)
895 // Virtual.
896{
897 const size_t raw_buf_size = raw_buf->size();
898 if (raw_buf_size != 0)
899 {
900 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] packet: "
901 "Unexpected trailing data: [" << raw_buf_size << "] bytes.");
902 return false;
903 }
904 // else
905
906 FLOW_LOG_WARNING("Deserialized low-level [" << m_type_ostream_manip << "] packet.");
907
908 return true;
909}
910
911std::ostream& Low_lvl_packet::to_ostream(std::ostream& os, [[maybe_unused]] bool verbose) const // Virtual.
912{
913 constexpr char INDENTATION[] = " ";
914
915 // Reminder: This is just a part (the leading part) of the ultimate output for the entire object of the sub-type.
916
917 return os << "Low-level packet " << this << ":\n"
918 << INDENTATION << "type: " << m_type_ostream_manip << "\n"
919 << INDENTATION << "m_src_port: " << m_packed.m_src_port << "\n"
920 << INDENTATION << "m_dst_port: " << m_packed.m_dst_port << "\n"
921 << INDENTATION << "m_opt_rexmit_on: " << m_opt_rexmit_on << "\n";
922}
923
924std::ostream& Syn_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
925{
927 using boost::asio::buffer;
928
929 constexpr char INDENTATION[] = " ";
930 constexpr char INDENTATION2[] = " ";
931
932 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
933
934 os << INDENTATION << "m_init_seq_num: " << m_init_seq_num << "\n";
935 if (!m_serialized_metadata.empty())
936 {
937 os << INDENTATION << "m_serialized_metadata (" << m_serialized_metadata.size() << " bytes):\n";
939 buffer(m_serialized_metadata.const_data(), m_serialized_metadata.size()),
940 INDENTATION2);
941 }
942
943 return os;
944}
945
946std::ostream& Syn_ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
947{
948 constexpr char INDENTATION[] = " ";
949
950 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
951
952 return os << INDENTATION << "m_init_seq_num: " << m_init_seq_num << "\n"
953 << INDENTATION << "m_rcv_wnd: " << m_packed.m_rcv_wnd << "\n"
954 << INDENTATION << "m_security_token: " << m_packed.m_security_token << "\n";
955}
956
957std::ostream& Syn_ack_ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
958{
959 constexpr char INDENTATION[] = " ";
960
961 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
962
963 return os << INDENTATION << "m_rcv_wnd: " << m_packed.m_rcv_wnd << "\n"
964 << INDENTATION << "m_security_token: " << m_packed.m_security_token << "\n";
965}
966
967std::ostream& Data_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
968{
970 using boost::asio::buffer;
971
972 constexpr char INDENTATION[] = " ";
973 constexpr char INDENTATION2[] = " ";
974
975 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
976
977 os << INDENTATION << "m_seq_num: " << m_seq_num << "\n";
978 if (m_opt_rexmit_on)
979 {
980 os << INDENTATION << "m_rexmit_id: " << int(m_rexmit_id) << "\n";
981 }
982 if (!m_data.empty())
983 {
984 // Subtlety: m_data_size is ensured to equal m_data.size; and it may be meaningless; so don't output it per se.
985 os << INDENTATION << "m_data (m_data_size=" << m_data.size() << " bytes)" << (verbose ? ':' : '.') << "\n";
986 if (verbose)
987 {
988 buffers_to_ostream(os, buffer(m_data.const_data(), m_data.size()), INDENTATION2);
989 }
990 }
991
992 return os;
993}
994
995std::ostream& Ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
996{
997 using boost::asio::buffer;
998
999 constexpr char INDENTATION[] = " ";
1000
1001 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
1002
1003 os << INDENTATION << "m_rcv_wnd: " << m_rcv_wnd << "\n";
1004 if (!m_rcv_acked_packets.empty())
1005 {
1006 os << INDENTATION << "m_rcv_acked_packets [INCOMING] (" << m_rcv_acked_packets.size() << " items):\n";
1007 if (m_opt_rexmit_on)
1008 {
1009 for (auto ack : m_rcv_acked_packets)
1010 {
1011 os << INDENTATION << INDENTATION << ack->m_seq_num << '/' << ack->m_rexmit_id
1012 << " : [" << ack->m_delay << "]\n";
1013 }
1014 }
1015 else
1016 {
1017 for (auto ack : m_rcv_acked_packets)
1018 {
1019 os << INDENTATION << INDENTATION << ack->m_seq_num << " : [" << ack->m_delay << "]\n";
1020 }
1021 }
1022 }
1023 const Ack_delay_time_unit TIME_UNIT(1);
1024 if (!m_rcv_acked_packets_rexmit_on_out.empty())
1025 {
1026 os << INDENTATION << "m_rcv_acked_packets rexmit=[on] [OUTGOING] "
1027 "(m_rcv_acked_packets_rexmit_out_size="
1028 << m_rcv_acked_packets_rexmit_out_size << '='
1029 << m_rcv_acked_packets_rexmit_on_out.size() << " items):\n";
1030 for (const auto& ack : m_rcv_acked_packets_rexmit_on_out)
1031 {
1032 os << INDENTATION << INDENTATION << ack.m_basic_ack.m_seq_num_raw << '/' << int(ack.m_rexmit_id)
1033 << " : " << ack.m_basic_ack.m_delay << " x [" << TIME_UNIT << "]\n";
1034 }
1035 }
1036 else if (!m_rcv_acked_packets_rexmit_off_out.empty()) // @todo Consider code reuse here vs. the preceding snippet.
1037 {
1038 os << INDENTATION << "m_rcv_acked_packets rexmit=[off] [OUTGOING] "
1039 "(m_rcv_acked_packets_rexmit_out_size="
1040 << m_rcv_acked_packets_rexmit_out_size << '='
1041 << m_rcv_acked_packets_rexmit_off_out.size() << " items):\n";
1042 for (const auto& ack : m_rcv_acked_packets_rexmit_off_out)
1043 {
1044 os << INDENTATION << INDENTATION << ack.m_seq_num_raw
1045 << " : " << ack.m_delay << " x [" << TIME_UNIT << "]\n";
1046 }
1047 }
1048
1049 return os;
1050}
1051
1052std::ostream& Low_lvl_packet::type_to_ostream(std::ostream& os) const
1053{
1054 using std::type_index;
1055
1056 return os << type_id_to_str(type_index(typeid(*this)));
1057}
1058
1060 ack_delay_t delay) :
1061 m_seq_num_raw(seq_num.raw_num_ref()),
1062 m_delay(delay)
1063{
1064 // Nothing else.
1065}
1066
1068 unsigned int rexmit_id,
1069 ack_delay_t delay) :
1070 m_basic_ack(seq_num, delay),
1071 m_rexmit_id(Data_packet::rexmit_id_t(rexmit_id))
1072{
1073 // Nothing else.
1074}
1075
1076} // namespace flow::net_flow
const Component & get_log_component() const
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect.
Definition: log.cpp:222
Log_context(Logger *logger=0)
Constructs Log_context by storing the given pointer to a Logger and a null Component.
Definition: log.cpp:188
Logger * get_logger() const
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.
Definition: log.cpp:217
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1284
virtual bool should_log(Sev sev, const Component &component) const =0
Given attributes of a hypothetical message that would be logged, return true if that message should b...
An internal net_flow sequence number identifying a piece of data.
Definition: seq_num.hpp:126
void set_metadata(char num_line_id=0, const Sequence_number &zero_point=Sequence_number(), seq_num_delta_t multiple_size=0)
Updates the full set of metadata (used at least for convenient convention-based logging but not actua...
Definition: seq_num.cpp:268
void set_raw_num(seq_num_t num)
Sets the raw sequence number.
Definition: seq_num.cpp:263
uint64_t seq_num_t
Raw sequence number type.
Definition: seq_num.hpp:138
boost::shared_ptr< Low_lvl_packet > Ptr
Short-hand for ref-counted pointer to mutable values of type Target_type::element_type (a-la T*).
#define FLOW_LOG_DATA(ARG_stream_fragment)
Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(...
Definition: log.hpp:242
#define FLOW_LOG_INFO(ARG_stream_fragment)
Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:197
#define FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment)
Identical to FLOW_LOG_WITH_CHECKING() but foregoes the filter (Logger::should_log()) check.
Definition: log.hpp:532
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
Definition: log.hpp:152
#define FLOW_LOG_TRACE_WITHOUT_CHECKING(ARG_stream_fragment)
Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:354
#define FLOW_LOG_DATA_WITHOUT_CHECKING(ARG_stream_fragment)
Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(...
Definition: log.hpp:372
#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_....
Definition: log.hpp:405
#define FLOW_LOG_TRACE(ARG_stream_fragment)
Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:227
@ S_DATA
Message satisfies Sev::S_TRACE description AND contains variable-length structure (like packet,...
@ S_TRACE
Message indicates any condition that may occur with great frequency (thus verbose if logged).
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
uint16_t flow_port_t
Logical Flow port type (analogous to a UDP/TCP port in spirit but in no way relevant to UDP/TCP).
std::string buffers_dump_string(const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Identical to buffers_to_ostream() but returns an std::string instead of writing to a given ostream.
Definition: util.hpp:506
std::ostream & buffers_to_ostream(std::ostream &os, const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Writes a multi- or single-line string representation of the provided binary data to an output stream,...
Definition: util.hpp:413
Blob_with_log_context<> Blob
A concrete Blob_with_log_context that compile-time-disables Basic_blob::share() and the sharing API d...
Definition: blob_fwd.hpp:60
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Definition: common.hpp:638
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:416
unsigned char uint8_t
Byte. Best way to represent a byte of binary data. This is 8 bits on all modern systems.
Definition: common.hpp:391
Individual_ack_rexmit_off(const Sequence_number &seq_num, ack_delay_t delay)
Constructs object.
Individual_ack_rexmit_on(const Sequence_number &seq_num, unsigned int rexmit_id, ack_delay_t delay)
Constructs object.
Specifies the incoming (post-deserialization) acknowledgment of a single received Data_packet.
boost::shared_ptr< Individual_ack > Ptr
Short-hand for ref-counted pointer to mutable objects of this class.
Internal net_flow struct that encapsulates the Flow-protocol low-level ACK packet.
std::vector< boost::shared_ptr< Individual_ack > > m_rcv_acked_packets
List of incoming (post-deserialization of ACK) acknowledgments of DATA packets, each identified by it...
uint64_t ack_delay_t
Type used to store the ACK delay for a given individual acknowledged packet.
std::ostream & to_ostream(std::ostream &os, bool verbose) const override
Implements Low_lvl_packet API.
rcv_wnd_t m_rcv_wnd
Current receive window (remaining Receive buffer size) of the ACK sender.
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.
uint16_t m_rcv_acked_packets_rexmit_out_size
This is the serialized version of m_rcv_acked_packets_rexmit_{on|off}_out.size() and m_rcv_acked_pack...
Fine_duration Ack_delay_time_unit
Ack_delay_time_unit(1) is the duration corresponding to the ack_delay_t value 1; and proportionally f...
Ack_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
Internal net_flow struct that encapsulates the Flow-protocol low-level DATA packet.
uint16_t m_data_size_raw
This is the serialized version of m_data.size() (see m_data).
std::ostream & to_ostream(std::ostream &os, bool verbose) const override
Implements Low_lvl_packet API.
Data_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
Sequence_number m_seq_num
The sequence number of the first byte in the payload; i.e., of m_data.front(), a/k/a m_data[0].
rexmit_id_t m_rexmit_id
Retransmit counter of the DATA packet being sent.
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
util::Blob m_data
The payload.
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.
uint8_t m_opt_rexmit_on_raw
This is the serialized version of the multi-byte bool Low_lvl_packet::m_opt_rexmit_on.
const uint16_t m_reserved2
Unused space reserved for future use, ensuring correct alignment of other fields and headers.
Aux_raw_data()
Constructs a mostly-uninitialized object, except for the const member(s), if any.
Internal net_flow struct that encapsulates the Flow-protocol low-level packet structure and serves as...
uint32_t rcv_wnd_t
Type used to store the size of m_rcv_wnd member in a couple of different packet types.
uint8_t rexmit_id_t
Type used to store the retransmission count in DATA and ACK packets.
Aux_raw_data m_aux_raw_data
Auxilliary data area necessary for serialize_to_raw_data() to work.
static Ptr create_from_raw_data_packet(log::Logger *logger_ptr, util::Blob *raw_packet, bool prefer_no_move)
Constructs packet on the heap with values determined by the given raw binary data as presumably recei...
static const std::string & type_id_to_str(const std::type_index &type_id)
Returns a brief (a few characters) string description of the given packet type given as type_index(ty...
struct flow::net_flow::Low_lvl_packet::@7 m_packed
Packed group affected by #pragma pack.
virtual std::ostream & to_ostream(std::ostream &os, bool verbose=false) const
Writes a multi-line representation of *this to an output stream.
Low_lvl_packet(log::Logger *logger_ptr)
Constructs packet with uninitialized (essentially random) values.
static const boost::unordered_map< std::type_index, Packet_type_info > S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO
Mapping from native typeid(), a/k/a packet type (for all possible packet types), to the set of proper...
size_t serialize_to_raw_data_and_log(Const_buffer_sequence *raw_bufs) const
Identical to serialize_to_raw_data() but adds log-level-appropriate logging after the operation.
static const uint8_t & type_id_native_to_raw(const std::type_info &type_id)
Helper that looks up the Packet_type_info::m_raw_type_id value for the given typeid(p),...
std::vector< Const_buffer > Const_buffer_sequence
Short-hand for sequence of immutable buffers; i.e., a sequence of 1 or more scattered areas in memory...
std::ostream & type_to_ostream(std::ostream &os) const
Writes a brief representation of typeid(*this) – i.e., the packet type (ACK, RST, etc....
const Function< std::ostream &(std::ostream &)> m_type_ostream_manip
ostream manipulator (argument to ostream <<) that will output packet's type ("ACK",...
uint64_t security_token_t
Type used for m_security_token member of a couple different packet types.
virtual size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const =0
Serializes the current logical packet data from *this into the given Const_buffer_sequence,...
boost::asio::const_buffer Const_buffer
Short-hand for boost.asio immutable buffer, which essentially is a pointer to and length of a memory ...
size_t serialize_common_header_to_raw_data(Const_buffer_sequence *raw_bufs) const
Helper for serialize_to_raw_data() implementations in sub-types that encodes the header common to all...
bool m_opt_rexmit_on
Option indicating whether this connection is using retransmission or not.
Internal net_flow struct that encapsulates the Flow-protocol low-level RST packet.
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.
Rst_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
Internal net_flow struct that encapsulates the Flow-protocol low-level SYN_ACK_ACK packet.
std::ostream & to_ostream(std::ostream &os, bool verbose) const override
Implements Low_lvl_packet API.
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
struct flow::net_flow::Syn_ack_ack_packet::@9 m_packed
Packed group affected by #pragma pack.
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.
Syn_ack_ack_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
Internal net_flow struct that encapsulates the Flow-protocol low-level SYN_ACK packet.
Sequence_number m_init_seq_num
Same meaning as Syn_packet::m_init_seq_num but applied to the essentially independent opposite traffi...
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
Syn_ack_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.
std::ostream & to_ostream(std::ostream &os, bool verbose) const override
Implements Low_lvl_packet API.
struct flow::net_flow::Syn_ack_packet::@8 m_packed
Packed group affected by #pragma pack.
Internal net_flow struct that encapsulates the Flow-protocol low-level SYN packet.
std::ostream & to_ostream(std::ostream &os, bool verbose) const override
Implements Low_lvl_packet API.
Syn_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
util::Blob m_serialized_metadata
Arbitrary serialized user-supplied metadata to send in SYN, where it can be deserialized by the user ...
bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet) override
Implements Low_lvl_packet API.
Sequence_number m_init_seq_num
The Initial Sequence Number (ISN) of the sequence number line that the sender of this SYN will be usi...
size_t serialize_to_raw_data(Const_buffer_sequence *raw_bufs) const override
Implements Low_lvl_packet API.