Flow 3.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 /* @todo Minor and ~randomly placed: Convention these days seems to be to parenthesize sizeof(X) for any X, whether
198 * it's a type or variable or anything else. Codify in doc-coding_style.cpp and convert all of Flow at least;
199 * seems NetFlow does it for types but not otherwise. */
200}
201
203{
204 using boost::asio::const_buffer;
205
206 /* Important: We directly copy various integers from memory into packet. That is only OK if
207 * the chosen network encoding convention equals that of this machine's endianness.
208 * If not, we'll need to write considerably more complex code, since flipped versions of such
209 * integers would need to be stored as well as the real versions. (Performance-wise, using
210 * the "scatter" technique would still be worthwhile, since large areas like Data_packet::m_data
211 * are stored in exact order and need no flipping. @todo Revisit but only if this assertion actually trips.
212 *
213 * We've intentionally chosen little-endian as the network byte order, since most platforms natively use it
214 * in memory (x86, etc.).
215 *
216 * Note that this technique is the basis of various "zero-copy" [de]serializers such as Cap'n Proto. */
217 static_assert(!native_is_big_endian(),
218 "Byte ordering in this platform is not conducive to zero-copy serialization.");
219
220 // Common header = type ID + common fields.
221 size_t size = serialize_common_header_to_raw_data(raw_bufs);
222
223 // Then our own stuff.
224
225 const auto* raw_seq_num = &(m_init_seq_num.raw_num_ref());
226 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
227 size += sizeof *raw_seq_num;
228
229 if (!m_serialized_metadata.empty())
230 {
231 raw_bufs->push_back(const_buffer(m_serialized_metadata.const_data(), m_serialized_metadata.size()));
232 size += m_serialized_metadata.size();
233 }
234
235 return size;
236}
237
239{
240 using boost::asio::const_buffer;
241
242 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
243
244 static_assert(!native_is_big_endian(),
245 "Byte ordering in this platform is not conducive to zero-copy serialization.");
246
247 // Common header = type ID + common fields.
248 size_t size = serialize_common_header_to_raw_data(raw_bufs);
249
250 const Sequence_number::seq_num_t* raw_seq_num = &(m_init_seq_num.raw_num_ref());
251 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
252 size += sizeof *raw_seq_num;
253
254 // Subtlety: These are stored together in packed fashion, so refer to them in one buffer.
255 raw_bufs->push_back(const_buffer(&m_packed.m_security_token,
256 sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd));
257 size += raw_bufs->back().size();
258
259 return size;
260}
261
263{
264 using boost::asio::const_buffer;
265
266 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
267
268 static_assert(!native_is_big_endian(),
269 "Byte ordering in this platform is not conducive to zero-copy serialization.");
270
271 // Common header = type ID + common fields.
272 size_t size = serialize_common_header_to_raw_data(raw_bufs);
273
274 // Subtlety: These are stored together in packed fashion, so refer to them in one buffer.
275 raw_bufs->push_back(const_buffer(&m_packed.m_security_token,
276 sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd));
277 size += raw_bufs->back().size();
278
279 return size;
280}
281
283{
284 using boost::asio::const_buffer;
285 using std::numeric_limits;
286
287 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
288
289 // Reminder: Keep raw_bufs->size() low, as explained near UDP async_send_to() call!
290
291 static_assert(!native_is_big_endian(),
292 "Byte ordering in this platform is not conducive to zero-copy serialization.");
293
294 // Common header = type ID + common fields.
295 size_t size = serialize_common_header_to_raw_data(raw_bufs);
296
297 const Sequence_number::seq_num_t* raw_seq_num = &(m_seq_num.raw_num_ref());
298 raw_bufs->push_back(const_buffer(raw_seq_num, sizeof *raw_seq_num));
299 size += sizeof *raw_seq_num;
300
301 if (m_opt_rexmit_on)
302 {
303 raw_bufs->push_back(const_buffer(&m_rexmit_id, sizeof m_rexmit_id));
304 size += sizeof m_rexmit_id;
305 }
306
307 assert(!m_data.empty());
308
309 // Serialize this, even though it's not strictly required, for reasons explained near deserialization code.
310 const size_t data_size = m_data.size();
311 using data_size_raw_t = decltype(m_data_size_raw);
312 assert(data_size <= numeric_limits<data_size_raw_t>::max());
313
314 m_data_size_raw = data_size_raw_t(data_size);
315 raw_bufs->push_back(const_buffer(&m_data_size_raw, sizeof m_data_size_raw));
316 size += sizeof m_data_size_raw;
317
318 raw_bufs->push_back(const_buffer(m_data.const_data(), data_size));
319 size += m_data.size();
320
321 return size;
322}
323
325{
326 using boost::asio::const_buffer;
327 using std::numeric_limits;
328
329 // Using same techniques as in Syn_packet::serialize_to_raw_data(). Keeping comments light.
330
331 // Reminder: Keep raw_bufs->size() low, as explained near UDP async_send_to() call!
332
333 static_assert(!native_is_big_endian(),
334 "Byte ordering in this platform is not conducive to zero-copy serialization.");
335
336 // Common header = type ID + common fields.
337 size_t size = serialize_common_header_to_raw_data(raw_bufs);
338
339 raw_bufs->push_back(const_buffer(&m_rcv_wnd, sizeof m_rcv_wnd));
340 size += sizeof m_rcv_wnd;
341
342 // Serialize this, even though it's not strictly required, for reasons explained near deserialization code.
343 const size_t pkts_size = m_opt_rexmit_on
344 ? m_rcv_acked_packets_rexmit_on_out.size()
345 : m_rcv_acked_packets_rexmit_off_out.size();
346 using pkts_size_t = decltype(m_rcv_acked_packets_rexmit_out_size);
347 assert(pkts_size <= numeric_limits<pkts_size_t>::max());
348
349 m_rcv_acked_packets_rexmit_out_size = pkts_size_t(pkts_size);
350 raw_bufs->push_back(const_buffer(&m_rcv_acked_packets_rexmit_out_size, sizeof(pkts_size_t)));
351 size += sizeof(pkts_size_t);
352
353 /* The following reaps the benefits of arranging the individual acks in a packed array or packed structures
354 * that are pre-serialized. In the past, this instead used scatter-gather semantics to cherry-pick parts of
355 * each ack and, for example, simply omitting the inapplicable m_rexmit_id when rexmit_on was false.
356 * There was thus no need for m_rcv_acked_packets_rexmit_*_out -- m_rcv_acked_packets was used for both
357 * incoming and outgoing packets. However, we then ran into the aforementioned UDP async_send_to() limitation
358 * at least for some platforms. This encouraged the optimization you see now -- which has the benefit of
359 * being better-performing in any case. The code, however, is arguably more complex (not in this function
360 * but elsewhere, with 2 more structs being needed. */
361 if (m_opt_rexmit_on)
362 {
363 raw_bufs->push_back(const_buffer(m_rcv_acked_packets_rexmit_on_out.data(),
364 m_rcv_acked_packets_rexmit_on_out.size()
365 * sizeof(decltype(m_rcv_acked_packets_rexmit_on_out)::value_type)));
366 }
367 else
368 {
369 raw_bufs->push_back(const_buffer(m_rcv_acked_packets_rexmit_off_out.data(),
370 m_rcv_acked_packets_rexmit_off_out.size()
371 * sizeof(decltype(m_rcv_acked_packets_rexmit_off_out)::value_type)));
372 }
373 size += raw_bufs->back().size();
374
375 return size;
376}
377
379{
380 // Common header = type ID + common fields. We add nothing else.
381 return serialize_common_header_to_raw_data(raw_bufs);
382}
383
385 bool prefer_no_move) // Static.
386{
388 using boost::asio::buffer;
389 using boost::asio::const_buffer;
390 using boost::endian::little_to_native;
391 using std::ostream;
392
393 Const_buffer raw_buf{raw_packet->const_data(), raw_packet->size()};
394
395 // Make FLOW_LOG_...() calls below use these (we are static).
396 FLOW_LOG_SET_CONTEXT(logger_ptr, Flow_log_component::S_NET_FLOW);
397
398 const size_t raw_buf_size = raw_buf.size();
399
401 ("Deserializing Low_lvl_packet; "
402 "total raw buffer size [" << raw_buf_size << "] bytes; buffer contents: "
403 "[\n" << buffers_dump_string(raw_buf, " ") << "].");
404
405 /* The basic structure of raw_buf is as follows:
406 * - Common Header:
407 * - The raw type ID, which indicates what is after the Common Header.
408 * - We'll create the appropriate Low_lvl_packet sub-type object based on this.
409 * - Certain common fields that apply to all.
410 * - We'll fill those out in the Low_lvl_packet (super-type) area of the just-created object.
411 * - Type-specific data:
412 * - We hand off the partially filled object and the remaining buffer to a virtual method that
413 * will appropriately fill the rest of the object. */
414
415 // This is the expected size of the Common Header mentioned above.
416 const size_t common_data_size
417 = sizeof(uint8_t) + sizeof m_packed.m_src_port + sizeof m_packed.m_dst_port
419
420 if (raw_buf_size < common_data_size)
421 {
422 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet is too small: "
423 "[" << raw_buf_size << "] bytes.");
424 return {};
425 }
426
427 /* We'll advance this as we keep reading off values from raw buffer.
428 * Could also use += on *raw_buf, but I don't feel like cast<>ing all the time.
429 * Would rather reinterpret_cast<> due to it being the devil I know. Doesn't really matter. */
430
431 const uint8_t* common_data = static_cast<const uint8_t*>(raw_buf.data());
432 // Meanwhile, this guy can skip past the entire Common Header. We'll check that it matches common_data at the end.
433 raw_buf = raw_buf + common_data_size;
434
435 // Get the type specifier.
436 const auto& raw_type_id = *common_data;
437 common_data += sizeof raw_type_id;
438
439 /* The type specifier determines the polymorphic type we choose. It is not actually recorded.
440 * C++ keeps typeid() which performs that task for us without us having to do it explicitly. */
441 Ptr packet
442 = (raw_type_id == type_id_native_to_raw(typeid(Syn_packet)))
443 ? create_uninit_packet_base<Syn_packet>(logger_ptr)
444 : ((raw_type_id == type_id_native_to_raw(typeid(Syn_ack_packet)))
445 ? create_uninit_packet_base<Syn_ack_packet>(logger_ptr)
446 : ((raw_type_id == type_id_native_to_raw(typeid(Syn_ack_ack_packet)))
447 ? create_uninit_packet_base<Syn_ack_ack_packet>(logger_ptr)
448 : ((raw_type_id == type_id_native_to_raw(typeid(Data_packet)))
449 ? create_uninit_packet_base<Data_packet>(logger_ptr)
450 : ((raw_type_id == type_id_native_to_raw(typeid(Ack_packet)))
451 ? create_uninit_packet_base<Ack_packet>(logger_ptr)
452 : ((raw_type_id == type_id_native_to_raw(typeid(Rst_packet)))
453 ? create_uninit_packet_base<Rst_packet>(logger_ptr)
454 : Ptr{})))));
455 if (!packet)
456 {
457 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet type is invalid: "
458 "[" << int(raw_type_id) << "].");
459 return packet;
460 }
461
462 using opt_rexmit_on_raw_t = decltype(Aux_raw_data::m_opt_rexmit_on_raw);
463 const auto& opt_rexmit_on_raw
464 = *reinterpret_cast<const opt_rexmit_on_raw_t*>(common_data);
465 common_data += sizeof opt_rexmit_on_raw;
466 packet->m_opt_rexmit_on = (opt_rexmit_on_raw != 0);
467
468 using reserved2_t = decltype(Aux_raw_data::m_reserved2);
469 const auto& reserved2 = *reinterpret_cast<const reserved2_t*>(common_data);
470 common_data += sizeof reserved2;
471 if (reserved2 != 0)
472 {
473 FLOW_LOG_WARNING("Unable to deserialize low-level packet: The packet format is unknown.");
474 return {};
475 }
476 // else
477
478 const auto& src_port_raw = *reinterpret_cast<const flow_port_t*>(common_data);
479 common_data += sizeof src_port_raw;
480 packet->m_packed.m_src_port = little_to_native(src_port_raw);
481
482 const auto& dst_port_raw = *reinterpret_cast<const flow_port_t*>(common_data);
483 common_data += sizeof dst_port_raw;
484 packet->m_packed.m_dst_port = little_to_native(dst_port_raw);
485
486 // Did we claculate the total size of Common Header correctly at the start?
487 assert(common_data == static_cast<const uint8_t*>(raw_buf.data()));
488
489 FLOW_LOG_TRACE("Deserialized packet [" << packet << "] common info: "
490 "NetFlow ports [" << packet->m_packed.m_src_port << "] -> [" << packet->m_packed.m_dst_port << "]; "
491 "opt_rexmit_on = [" << packet->m_opt_rexmit_on << "]; "
492 "common serialized size was [" << common_data_size << "].");
493
494 // Low_lvl_packet part is filled out. The sub-type part has junk. This will fill that part out.
495 if (!packet->deserialize_type_specific_data_from_raw_data_packet(&raw_buf, prefer_no_move, raw_packet))
496 {
497 return {}; // Error. It logged.
498 }
499 // else
500
501 // raw_packet is not in valid but unknown state. Do not use.
502
503 if (logger_ptr && logger_ptr->should_log(log::Sev::S_TRACE, get_log_component()))
504 {
505 const bool data_sev = logger_ptr->should_log(log::Sev::S_DATA, get_log_component());
507 "Deserialized packet: Final version: "
508 "[\n"
509 << (data_sev ? packet->m_verbose_ostream_manip : packet->m_concise_ostream_manip)
510 << "].");
511 }
512
513 return packet;
514} // Low_lvl_packet::create_from_raw_data_packet()
515
517 [[maybe_unused]] bool prefer_no_move,
518 [[maybe_unused]] util::Blob* raw_packet)
519 // Virtual.
520{
521 using boost::asio::buffer;
522 using boost::endian::little_to_native;
523
524 // Structure: a few required fields; then arbitrary-length metadata buffer.
525
526 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
527
528 const size_t min_data_size = sizeof(Sequence_number::seq_num_t);
529 const size_t raw_buf_size = raw_buf->size();
530 if (raw_buf_size < min_data_size)
531 {
532 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
533 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
534 return false;
535 }
536 // else
537
538 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
539 (*raw_buf) = ((*raw_buf) + min_data_size);
540
541 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
542 data += sizeof seq_num_raw;
543 m_init_seq_num.set_raw_num(little_to_native(seq_num_raw));
544 /* Set some metadata. Subleties:
545 * The 'type' we know and can set sans controversy. It's the number line for remote-originated data.
546 * The multiple is, if anything, max-block-size, which we don't know, since we don't yet know socket for this,
547 * (if it's even legal at all).
548 * The zero point is the ISN + 1, and since we *are* the ISN, we could actually set it here. Pragmatically,
549 * however, it's nice to log the absolute raw number at this point and turn everything to nice relative values
550 * after that; so leave the applying of ISN to this until `sock` is detected. Note, also, that this is consistent
551 * with what's done for Data_packet and Ack_packet (though, to be fair, for those there is no choice, as ISN is
552 * not known without socket). */
554
555 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
556
557 const size_t n_copied = m_serialized_metadata.assign_copy(*raw_buf);
558 assert(n_copied == m_serialized_metadata.size());
559
560 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
561 "ISN [" << m_init_seq_num << "]; "
562 "metadata size ["<< n_copied << "] bytes; "
563 "serialized size beyond common header was [" << raw_buf_size << "].");
564
565 return true;
566} // Syn_packet::deserialize_type_specific_data_from_raw_data_packet()
567
569 [[maybe_unused]] bool prefer_no_move,
570 [[maybe_unused]] util::Blob* raw_packet)
571 // Virtual.
572{
573 using boost::endian::little_to_native;
574
575 // Structure: a few required fields; and that's it.
576
577 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
578
579 const size_t exp_data_size = sizeof(Sequence_number::seq_num_t)
580 + sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd;
581 const size_t raw_buf_size = raw_buf->size();
582 if (raw_buf_size != exp_data_size)
583 {
584 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
585 "packet: The packet is of wrong size: ["<< raw_buf_size << "] bytes.");
586 return false;
587 }
588 // else
589
590 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
591 (*raw_buf) = ((*raw_buf) + exp_data_size);
592
593 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
594 data += sizeof seq_num_raw;
595 m_init_seq_num.set_raw_num(little_to_native(seq_num_raw));
596 // See comment in same place for Syn_packet.
598
599 const auto& security_token_raw = *reinterpret_cast<const security_token_t*>(data);
600 data += sizeof security_token_raw;
601 m_packed.m_security_token = little_to_native(security_token_raw);
602
603 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
604 data += sizeof rcv_wnd_raw;
605 m_packed.m_rcv_wnd = little_to_native(rcv_wnd_raw);
606
607 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
608
609 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
610 "ISN [" << m_init_seq_num << "]; "
611 "rcv_wnd ["<< m_packed.m_rcv_wnd << "] bytes; "
612 "serialized size beyond common header was [" << raw_buf_size << "].");
613
614 return true;
615} // Syn_ack_packet::deserialize_type_specific_data_from_raw_data_packet()
616
618 [[maybe_unused]] bool prefer_no_move,
619 [[maybe_unused]] util::Blob* raw_packet)
620 // Virtual.
621{
622 using boost::endian::little_to_native;
623
624 // Structure: a few required fields; and that's it.
625
626 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
627
628 const size_t exp_data_size = sizeof m_packed.m_security_token + sizeof m_packed.m_rcv_wnd;
629 const size_t raw_buf_size = raw_buf->size();
630 if (raw_buf_size != exp_data_size)
631 {
632 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
633 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
634 return false;
635 }
636 // else
637
638 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
639 (*raw_buf) = ((*raw_buf) + exp_data_size);
640
641 const auto& security_token_raw = *reinterpret_cast<const security_token_t*>(data);
642 data += sizeof security_token_raw;
643 m_packed.m_security_token = little_to_native(security_token_raw);
644
645 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
646 data += sizeof rcv_wnd_raw;
647 m_packed.m_rcv_wnd = little_to_native(rcv_wnd_raw);
648
649 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
650
651 FLOW_LOG_INFO("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
652 "rcv_wnd ["<< m_packed.m_rcv_wnd << "] bytes; "
653 "serialized size beyond common header was [" << raw_buf_size << "].");
654
655 return true;
656} // Syn_ack_ack_packet::deserialize_type_specific_data_from_raw_data_packet()
657
659 bool prefer_no_move,
660 util::Blob* raw_packet) // Virtual.
661{
662 using boost::asio::buffer;
663 using boost::endian::little_to_native;
664 using std::numeric_limits;
665 using std::memcpy;
666
667 using data_size_raw_t = decltype(m_data_size_raw);
668
669 // Structure: a few required fields; then the arbitrarily-long (but not 0-length) data payload.
670
671 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
672
673 const size_t min_data_size
674 = sizeof(Sequence_number::seq_num_t) + (m_opt_rexmit_on ? sizeof m_rexmit_id : 0) + sizeof(data_size_raw_t);
675 const size_t raw_buf_size = raw_buf->size();
676 if (raw_buf_size < min_data_size)
677 {
678 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
679 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
680 return false;
681 }
682 // else
683
684 const uint8_t* cur_data = static_cast<const uint8_t*>(raw_buf->data());
685 (*raw_buf) = ((*raw_buf) + min_data_size);
686
687 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(cur_data);
688 cur_data += sizeof seq_num_raw;
689 m_seq_num.set_raw_num(little_to_native(seq_num_raw));
690 // Remote seq. # line, but we don't (yet) know for which socket, so max-block-size and ISN are (for now) unknown.
692
693 if (m_opt_rexmit_on)
694 {
695 const auto& rexmit_id_raw = *reinterpret_cast<const rexmit_id_t*>(cur_data);
696 cur_data += sizeof rexmit_id_raw;
697 m_rexmit_id = little_to_native(rexmit_id_raw);
698 }
699
700 /* m_data.size() is encoded separately, even though we could figure it out simply by counting the bytes not yet
701 * deserialized to this point. The reason is that I've seen, in practice, silent truncation occur; for example
702 * with Boost 1.63 on Mac, at least, using more than ~64 scatter/gather buffers when invoking UDP sendto() caused
703 * the over-that-silent-limit buffers to simply be ignored. (Another reason is the existing socket options
704 * mechanism in this library makes it very difficult to ensure Node_options::m_dyn_low_lvl_max_packet_size is
705 * sufficiently larger than Peer_socket_options::m_st_max_block_size (because they are not both per-Node or
706 * both per-socket -- trust me, I tried, but thread considerations made checking this at all appropriate times
707 * either extremely hard or even impossible). So it has to be checked outside option checking time, but it can't
708 * be done at receipt time, because at that point the Peer_socket from which to obtain m_st_max_block_size is not
709 * yet known; one has to deserialize packet to get at that... but at that point it's kind of too late.) So all
710 * these issues can be sanity-checked away by encoding the expected size up-front and then ensuring the actual
711 * data area matches this exactly. To be clear, there are certainly ways to avoid it -- but then one must constantly
712 * be aware of it; whereas using a couple of bytes to do this eliminates that problem at a fairly low cost.
713 * @todo Revisit this sometime. */
714
715 data_size_raw_t data_size_raw;
716 // Using `= *reinterpret_cast<...*>` makes UBSAN complain; so humor it by using explicit memcpy().
717 memcpy(&data_size_raw, cur_data, sizeof data_size_raw);
718 cur_data += sizeof data_size_raw;
719
720 data_size_raw = little_to_native(data_size_raw);
721
722 if (data_size_raw == 0)
723 {
724 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
725 "packet: The data area specifies empty size.");
726 return false;
727 }
728 // else
729
730 assert(cur_data == static_cast<const uint8_t*>(raw_buf->data()));
731
732 // The rest of the buffer = the data payload.
733 const size_t data_size = raw_buf->size();
734
735 if ((data_size > numeric_limits<data_size_raw_t>::max()) // Don't let overflow fools us or something like that.
736 || (data_size_raw_t(data_size) != data_size_raw))
737 {
738 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
739 "packet: The data area specifies size [" << data_size_raw << "] but has "
740 "actual size [" << data_size << "]. Did truncation occur somewhere?");
741 return false;
742 }
743 // else
744
745 /* Subtlety: m_data, to store the DATA payload itself, will consist of the entire raw packet data but with
746 * its logical [begin(), end) range starting past the header and other stuff, right where the payload begins.
747 * This allows us to MOVE instead of (slowly) copying (part of) raw_packet into m_data -- but then still treat m_data
748 * as if it's just the payload itself and not the entire packet. (In point of fact, as of this writing, m_data will
749 * be further moved into Socket_buffer Receive buffer, again via a constant-time move.) This way we sacrifice a small
750 * memory overhead for major eliminating of copying.
751 *
752 * Update: The caller may now specify to make a copy instead. Why this might be done is explained elsewhere, where
753 * it is decided. */
754
755 // First move over the entire raw packet.
756 if (prefer_no_move)
757 {
758 m_data.assign_copy(*raw_buf);
759 }
760 else
761 {
762 m_data = std::move(*raw_packet);
763 // Then shift begin() right to where the payload begins (size() adjusted down accordingly).
764 m_data.start_past_prefix(cur_data - m_data.const_data());
765 assert(m_data.const_begin() == cur_data);
766 }
767 // m_data.[begin, end()) range is now the right thing, regardless of how it got there.
768 assert(m_data.size() == data_size);
769
770 if (m_opt_rexmit_on)
771 {
772 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
773 "sequence number [" << m_seq_num << "] rexmit_id [" << int(m_rexmit_id) << "]; "
774 "user data size [" << data_size << "] (" << (prefer_no_move ? "copied" : "moved") << "); "
775 "serialized size beyond common header was [" << raw_buf_size << "].");
776 }
777 else
778 {
779 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
780 "sequence number [" << m_seq_num << "]; "
781 "user data size [" << data_size << "] (" << (prefer_no_move ? "copied" : "moved") << "); "
782 "serialized size beyond common header was [" << raw_buf_size << "].");
783 }
784
785 return true;
786} // Data_packet::deserialize_type_specific_data_from_raw_data_packet()
787
789 [[maybe_unused]] bool prefer_no_move,
790 [[maybe_unused]] util::Blob* raw_packet)
791 // Virtual.
792{
793 using boost::endian::little_to_native;
794 using std::numeric_limits;
795
796 using pkts_size_raw_t = decltype(m_rcv_acked_packets_rexmit_out_size);
797
798 // Structure: a few required fields; then 0 or more acknowledgments, each consisting of constant # of fields.
799
800 // Use same techniques as in Low_lvl_packet::create_from_raw_data_packet(). Keeping comments light.
801
802 const size_t min_data_size = sizeof m_rcv_wnd + sizeof(pkts_size_raw_t);
803 const size_t raw_buf_size = raw_buf->size();
804 if (raw_buf_size < min_data_size)
805 {
806 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
807 "packet: The packet is too small: ["<< raw_buf_size << "] bytes.");
808 return false;
809 }
810 // else
811
812 const uint8_t* data = static_cast<const uint8_t*>(raw_buf->data());
813 (*raw_buf) = ((*raw_buf) + min_data_size);
814
815 const auto& rcv_wnd_raw = *reinterpret_cast<const rcv_wnd_t*>(data);
816 data += sizeof rcv_wnd_raw;
817 m_rcv_wnd = little_to_native(rcv_wnd_raw);
818
819 /* m_rcv_acked_packets.size() is encoded separately, even though we could figure it out by counting the bytes not yet
820 * deserialized to this point and dividing by size of each individual ack. The reason is explained in a similar
821 * comment in Data_packet::deserialize_type_specific_data_from_raw_data_packet() -- see that comment. */
822 auto pkts_size_raw = *reinterpret_cast<const pkts_size_raw_t*>(data);
823 data += sizeof pkts_size_raw;
824 pkts_size_raw = little_to_native(pkts_size_raw);
825
826 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
827
828 const size_t ack_size
829 = sizeof(Sequence_number::seq_num_t) + sizeof(ack_delay_t) + (m_opt_rexmit_on ? sizeof(rexmit_id_t) : 0);
830 const size_t n_acks = raw_buf->size() / ack_size; // Note: rounds down.
831 (*raw_buf) = ((*raw_buf) + (n_acks * ack_size));
832
833 if ((n_acks > numeric_limits<pkts_size_raw_t>::max()) // Don't let overflow fools us or something like that.
834 || (pkts_size_raw_t(n_acks) != pkts_size_raw))
835 {
836 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] "
837 "packet: The individual acks area specifies [" << pkts_size_raw << "] acks but has "
838 "actual ack count [" << n_acks << "]. Did truncation occur somewhere?");
839 return false;
840 }
841 // else
842
843 m_rcv_acked_packets.clear();
844 m_rcv_acked_packets.reserve(n_acks);
845
846 for (size_t ack_idx = 0; ack_idx != n_acks; ++ack_idx)
847 {
848 const auto& seq_num_raw = *reinterpret_cast<const Sequence_number::seq_num_t*>(data);
849 data += sizeof seq_num_raw;
850 Sequence_number seq_num;
851 seq_num.set_raw_num(little_to_native(seq_num_raw));
852 // Local seq. # line, but we don't (yet) know for which socket, so max-block-size and ISN are (for now) unknown.
853 seq_num.set_metadata('L');
854
855 const auto& ack_delay_raw = *reinterpret_cast<const ack_delay_t*>(data);
856 data += sizeof ack_delay_raw;
857 const Fine_duration ack_delay
858 = Ack_delay_time_unit{little_to_native(ack_delay_raw)};
859
860 unsigned int rexmit_id;
861 if (m_opt_rexmit_on)
862 {
863 const auto& rexmit_id_raw = *reinterpret_cast<const rexmit_id_t*>(data);
864 data += sizeof rexmit_id_raw;
865 rexmit_id = static_cast<unsigned int>(little_to_native(rexmit_id_raw));
866 }
867 else
868 {
869 rexmit_id = 0;
870 }
871
872 m_rcv_acked_packets.push_back(Individual_ack::Ptr{new Individual_ack{ seq_num, ack_delay, rexmit_id }});
873 } // for (all acks)
874
875 assert(data == static_cast<const uint8_t*>(raw_buf->data()));
876
877 // If the acks area was not an exact multiple of size of each ack, then bytes will be left over (bad).
878
879 const size_t remaining_buf_size = raw_buf->size();
880 if (remaining_buf_size != 0)
881 {
882 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] packet: "
883 "Unexpected trailing data: [" << remaining_buf_size << "] bytes.");
884 return false;
885 }
886 // else
887
888 FLOW_LOG_TRACE("Deserialized low-level [" << m_type_ostream_manip << "] packet with "
889 "[" << m_rcv_acked_packets.size() << "] individual acks; "
890 "rcv_wnd [" << m_rcv_wnd << "]; "
891 "serialized size beyond common header was [" << raw_buf_size << "].");
892
893 return true;
894} // Ack_packet::deserialize_type_specific_data_from_raw_data_packet()
895
897 [[maybe_unused]] bool prefer_no_move,
898 [[maybe_unused]] util::Blob* raw_packet)
899 // Virtual.
900{
901 const size_t raw_buf_size = raw_buf->size();
902 if (raw_buf_size != 0)
903 {
904 FLOW_LOG_WARNING("Unable to deserialize low-level [" << m_type_ostream_manip << "] packet: "
905 "Unexpected trailing data: [" << raw_buf_size << "] bytes.");
906 return false;
907 }
908 // else
909
910 FLOW_LOG_WARNING("Deserialized low-level [" << m_type_ostream_manip << "] packet.");
911
912 return true;
913}
914
915std::ostream& Low_lvl_packet::to_ostream(std::ostream& os, [[maybe_unused]] bool verbose) const // Virtual.
916{
917 constexpr char INDENTATION[] = " ";
918
919 // Reminder: This is just a part (the leading part) of the ultimate output for the entire object of the sub-type.
920
921 return os << "Low-level packet " << this << ":\n"
922 << INDENTATION << "type: " << m_type_ostream_manip << "\n"
923 << INDENTATION << "m_src_port: " << m_packed.m_src_port << "\n"
924 << INDENTATION << "m_dst_port: " << m_packed.m_dst_port << "\n"
925 << INDENTATION << "m_opt_rexmit_on: " << m_opt_rexmit_on << "\n";
926}
927
928std::ostream& Syn_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
929{
931 using boost::asio::buffer;
932
933 constexpr char INDENTATION[] = " ";
934 constexpr char INDENTATION2[] = " ";
935
936 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
937
938 os << INDENTATION << "m_init_seq_num: " << m_init_seq_num << "\n";
939 if (!m_serialized_metadata.empty())
940 {
941 os << INDENTATION << "m_serialized_metadata (" << m_serialized_metadata.size() << " bytes):\n";
943 buffer(m_serialized_metadata.const_data(), m_serialized_metadata.size()),
944 INDENTATION2);
945 }
946
947 return os;
948}
949
950std::ostream& Syn_ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
951{
952 constexpr char INDENTATION[] = " ";
953
954 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
955
956 return os << INDENTATION << "m_init_seq_num: " << m_init_seq_num << "\n"
957 << INDENTATION << "m_rcv_wnd: " << m_packed.m_rcv_wnd << "\n"
958 << INDENTATION << "m_security_token: " << m_packed.m_security_token << "\n";
959}
960
961std::ostream& Syn_ack_ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
962{
963 constexpr char INDENTATION[] = " ";
964
965 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
966
967 return os << INDENTATION << "m_rcv_wnd: " << m_packed.m_rcv_wnd << "\n"
968 << INDENTATION << "m_security_token: " << m_packed.m_security_token << "\n";
969}
970
971std::ostream& Data_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
972{
974 using boost::asio::buffer;
975
976 constexpr char INDENTATION[] = " ";
977 constexpr char INDENTATION2[] = " ";
978
979 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
980
981 os << INDENTATION << "m_seq_num: " << m_seq_num << "\n";
982 if (m_opt_rexmit_on)
983 {
984 os << INDENTATION << "m_rexmit_id: " << int(m_rexmit_id) << "\n";
985 }
986 if (!m_data.empty())
987 {
988 // Subtlety: m_data_size is ensured to equal m_data.size; and it may be meaningless; so don't output it per se.
989 os << INDENTATION << "m_data (m_data_size=" << m_data.size() << " bytes)" << (verbose ? ':' : '.') << "\n";
990 if (verbose)
991 {
992 buffers_to_ostream(os, buffer(m_data.const_data(), m_data.size()), INDENTATION2);
993 }
994 }
995
996 return os;
997}
998
999std::ostream& Ack_packet::to_ostream(std::ostream& os, bool verbose) const // Virtual.
1000{
1001 using boost::asio::buffer;
1002
1003 constexpr char INDENTATION[] = " ";
1004
1005 this->Low_lvl_packet::to_ostream(os, verbose); // Super-method.
1006
1007 os << INDENTATION << "m_rcv_wnd: " << m_rcv_wnd << "\n";
1008 if (!m_rcv_acked_packets.empty())
1009 {
1010 os << INDENTATION << "m_rcv_acked_packets [INCOMING] (" << m_rcv_acked_packets.size() << " items):\n";
1011 if (m_opt_rexmit_on)
1012 {
1013 for (auto ack : m_rcv_acked_packets)
1014 {
1015 os << INDENTATION << INDENTATION << ack->m_seq_num << '/' << ack->m_rexmit_id
1016 << " : [" << ack->m_delay << "]\n";
1017 }
1018 }
1019 else
1020 {
1021 for (auto ack : m_rcv_acked_packets)
1022 {
1023 os << INDENTATION << INDENTATION << ack->m_seq_num << " : [" << ack->m_delay << "]\n";
1024 }
1025 }
1026 }
1027 const Ack_delay_time_unit TIME_UNIT(1);
1028 if (!m_rcv_acked_packets_rexmit_on_out.empty())
1029 {
1030 os << INDENTATION << "m_rcv_acked_packets rexmit=[on] [OUTGOING] "
1031 "(m_rcv_acked_packets_rexmit_out_size="
1032 << m_rcv_acked_packets_rexmit_out_size << '='
1033 << m_rcv_acked_packets_rexmit_on_out.size() << " items):\n";
1034 for (const auto& ack : m_rcv_acked_packets_rexmit_on_out)
1035 {
1036 os << INDENTATION << INDENTATION << ack.m_basic_ack.m_seq_num_raw << '/' << int(ack.m_rexmit_id)
1037 << " : " << ack.m_basic_ack.m_delay << " x [" << TIME_UNIT << "]\n";
1038 }
1039 }
1040 else if (!m_rcv_acked_packets_rexmit_off_out.empty()) // @todo Consider code reuse here vs. the preceding snippet.
1041 {
1042 os << INDENTATION << "m_rcv_acked_packets rexmit=[off] [OUTGOING] "
1043 "(m_rcv_acked_packets_rexmit_out_size="
1044 << m_rcv_acked_packets_rexmit_out_size << '='
1045 << m_rcv_acked_packets_rexmit_off_out.size() << " items):\n";
1046 for (const auto& ack : m_rcv_acked_packets_rexmit_off_out)
1047 {
1048 os << INDENTATION << INDENTATION << ack.m_seq_num_raw
1049 << " : " << ack.m_delay << " x [" << TIME_UNIT << "]\n";
1050 }
1051 }
1052
1053 return os;
1054}
1055
1056std::ostream& Low_lvl_packet::type_to_ostream(std::ostream& os) const
1057{
1058 using std::type_index;
1059
1060 return os << type_id_to_str(type_index(typeid(*this)));
1061}
1062
1064 ack_delay_t delay) :
1065 m_seq_num_raw(seq_num.raw_num_ref()),
1066 m_delay(delay)
1067{
1068 // Nothing else.
1069}
1070
1072 unsigned int rexmit_id,
1073 ack_delay_t delay) :
1074 m_basic_ack(seq_num, delay),
1075 m_rexmit_id(Data_packet::rexmit_id_t(rexmit_id))
1076{
1077 // Nothing else.
1078}
1079
1080} // 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:272
Log_context(Logger *logger=nullptr)
Constructs Log_context by storing the given pointer to a Logger and a null Component.
Definition: log.cpp:234
Logger * get_logger() const
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.
Definition: log.cpp:260
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1392
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_raw_num(seq_num_t num)
Sets the raw sequence number.
Definition: seq_num.cpp:240
uint64_t seq_num_t
Raw sequence number type.
Definition: seq_num.hpp:138
void set_metadata(char num_line_id=0, const Sequence_number &zero_point={}, 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:245
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:245
#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:200
#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:617
#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:155
#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:422
#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:440
#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:473
#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:230
@ 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:699
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:607
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:62
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Definition: common.hpp:627
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:405
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:380
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.