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