Flow 3.0.0
Flow project: Full implementation reference.
low_lvl_packet.hpp
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
19#pragma once
20
24#include "flow/log/log.hpp"
25#include "flow/util/util.hpp"
27#include "flow/util/blob.hpp"
28#include <boost/endian.hpp>
29#include <boost/unordered/unordered_map.hpp>
30#include <limits>
31#include <type_traits>
32
33namespace flow::net_flow
34{
35
36/**
37 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level packet structure and serves as
38 * the super-type for all specific packet types, represented by derived `struct`s like Ack_packet, Rst_packet,
39 * etc.
40 *
41 * This `struct` and its sub-`struct` hierarchy are not too complex but nevertheless are somewhat unorthodox,
42 * combining a few different paradigms. So it's worth explaining these paradigms.
43 *
44 * ### Paradigm: Data store ###
45 * This is a `struct` holding the conceptual contents of a packet. Low_lvl_packet stores common values like
46 * #m_opt_rexmit_on, #m_src_port, and a few more. Each sub-`struct` stores further values specific to each
47 * packet type; for example, as of this writing, Data_packet::m_data contains the data payload of a DATA
48 * packet; this would not apply, for example, to another sub-`struct` like Rst_packet, because an RST stores
49 * no binary blob like that.
50 *
51 * Since it's a simple data store, the applicable data members (in this `struct` and the sub-types) are
52 * both public AND non-`const`. They can be read and written at will, thus changing or reading the
53 * logical contents of the packet.
54 *
55 * ### Paradigm: Polymorphic type ###
56 * While a simple data store, it also represents a hierarchy of possible packet types, and indeed a number
57 * of important polymorphic operations are included. Some are private/internal, and some are public.
58 * A public method may not appear polymorphic by its signature, but in that case usually its implementation
59 * uses non-public `virtual` methods to accomplish its tasks. Specifically, the key APIs are:
60 *
61 * - `create_uninit_packet<T>()`: This creates an uninitialized sub-object of Low_lvl_packet, of actual
62 * type `T`, where `T` derives from Low_lvl_packet. This returns a `shared_ptr<T>`, and any actual
63 * constructor used to implement this factory method is non-public, so the only way for a user to
64 * create a Low_lvl_packet is to get at a ref-counted pointer to it -- not a raw, unprotected pointer. If storing
65 * only `shared_ptr<T>` or `Ptr` values, deletion is not something to worry about, as it will happen
66 * automatically.
67 * - Same with the other factory methods described just below. Direct access to `Low_lvl_packet*` or
68 * `T*`, where `T` derives from Low_lvl_packet, is not allowed (but this is not enforced at compile time
69 * and, at best, via `assert()`s at runtime).
70 * - create_from_raw_data_packet(): Given a raw serialized packet, this factory method constructs
71 * a Low_lvl_packet of the appropriate polymorphic sub-type, filling it at all levels with the data
72 * deserialized for the input binary blob. Internally, it uses some private, `virtual` action to get this
73 * to work. At any rate, this method is used to crete a logical representation of a packet off the wire.
74 * - serialize_to_raw_data(): The opposite operation: convert existing object to raw data sendable over the wire.
75 * This uses a high-performance scatter-gather paradigm of producing a sequence of pointers and lengths to
76 * already existing data areas, avoiding copying. This thing is `virtual` and applies to any Low_lvl_packet
77 * sub-object.
78 *
79 * (Reminder: As with all polymorphism and `shared_ptr`, you may need `static_pointer_cast<>` to up- and down-cast
80 * between Low_lvl_packet and subclasses. Also `Low_lvl_packet::ptr_cast()` up-casts even syntactically-sugarier-ly.)
81 *
82 * The two basic flows are:
83 * - Call `create_uninit_packet<T>()` to construct a sub-`struct` of Low_lvl_packet, returned as a ref-counted
84 * pointer to `T`. Fill out all the fields manually, accessing object via aforemetioned smart pointer.
85 * Call serialize_to_raw_data(). Pass result of latter to a boost.asio network-sending routine
86 * to send over wire. Ensure you pass a `Ptr` to the completion handler passed to that routine, so that
87 * the Low_lvl_packet survives while being sent. The handler can let the `Ptr` go out of scope, likely
88 * `delete`ing the Low_lvl_packet.
89 * - Receive raw packet over wire. Call create_from_raw_data_packet() to yield a Low_lvl_packet::Ptr pointing
90 * to new Low_lvl_packet sub-object with all fields filled out. Read the fields as needed to process the
91 * packet; store the `Ptr` if necessary; eventually removing it from all data structures will drop ref-count
92 * to zero, and it will be auto-`delete`d.
93 *
94 * ### Other utlities ###
95 * A number of (typically polymorphic) facilities exist, mainly to log these objects to `ostream`s, including
96 * when logging with FLOW_LOG_TRACE() and FLOW_LOG_DATA().
97 *
98 * - #m_verbose_ostream_manip and #m_concise_ostream_manip are `const` data members that can be output
99 * via the usual `<<` operator to `ostream`s in order to output verbose and concise descriptions
100 * of any Low_lvl_packet (of any sub-`struct` type, polymorphically).
101 * - #m_type_ostream_manip can be similarly used to output just the packet type of any given
102 * Low_lvl_packet (producing strings like `"ACK"` or `"RST"`).
103 *
104 * The implementation of these is typically some polymorphic `virtual` magic, but the use is straightforward using
105 * these `ostream` manipulator data members.
106 *
107 * Implementation notes
108 * --------------------
109 *
110 * ### History of approaches ###
111 * Originally the implementation used the boost.serialization library for packet serialization, but
112 * it turned out to consume way too much CPU time which consequently limited the maximum
113 * throughput at high speeds. The next implementation used the traditional approach based on
114 * "packed" structures (structures without any padding), in one big `struct Low_lvl_packet`.
115 * However, I deemed the latter setup too C-like (yet simultaneously
116 * not C-like enough, in that no unions were used, hence RAM was wasted despite the C-like approach).
117 * Ultimately, the current version of the implementation came about, with its polymorphic `struct` hierarchy
118 * and abstract Low_lvl_packet `struct` (which, in the previous iteration, simply contained everything
119 * about every type, complete with an `enum Type` instead of using C++'s built-in `typeid`, as the current
120 * version uses).
121 *
122 * While the above evolution was more about coding style philosophy (from a single type and a type selector
123 * `enum` to a polymorphic hierarchy and `typeid`), the other evolution concerned the way serialization
124 * (for sending over the write) worked. At first, as mentioned, there were the logical values (which were
125 * public and non-`const`), and there were private packed `struct`s into which the logical values were
126 * placed (with transformation for endianness and other things) at serialization time; finally then assembling
127 * a newly allocated single binary buffer, those packed `struct`s copied into it. Not bad -- rather verbose
128 * having all those types defined, but not bad -- but it did involve a new buffer and linear-time copying into
129 * that buffer. This seemed like a shame.
130 *
131 * This led to the final improvement, which was to turn the serialization function into one that generates
132 * a `boost::asio::const_buffer_sequence`, basically a sequence of pointers and associated lengths of areas
133 * already present in memory. In most cases (with a couple small exceptions), the stored public data members
134 * (e.g., #m_src_port and Data_packet::m_data) could simply have their addresses and lengths taken and placed
135 * into the `const_buffer_sequence` -- no buffer copying involved. This should achieve a nice performance
136 * improvement. The removal of things like `struct Common_header` and `struct Ack_header` is a good bonus
137 * coding-wise, too.
138 *
139 * (There is a caveat there. While no issue for the true performance culprits, namely Data_packet::m_data,
140 * the various multi-byte integer values like #m_src_port technically have to undergo endianness conversion
141 * during serialization. So technically simply taking an address and size is not enough; the value needs
142 * to be flipped *potentially*. In reality, though, all relevant architectures are such that we chose
143 * identical network byte order as memory byte order, making no flipping necessary in practice. Of course,
144 * if we spread to an architecture where this is not true, everything will explode. However, a compile-time
145 * assertion would warn us of this, and a nearby comment will instruct on how to deal with the problem, in the
146 * unlikely case it were to appear. [Little-endian is rather universal these days.])
147 *
148 * ### Packed structures, stored integers, and alignment ###
149 * When 2 or more contiguous data members are used in serializing (serialize_to_raw_data() or overridden
150 * version), they are packed together via `"#pragma pack"`. (Note that this affect entire `struct`s at a time
151 * only; hence we need to use some anonymously-typed grouping `struct`s named `m_packed`.)
152 *
153 * Numeric values are stored as unsigned integers, which is the most portable choice for serializing.
154 * Booleans are serialized as bytes for compactness.
155 *
156 * Some effort is made to keep fields aligned along word edges when serializing. There is not too much
157 * of that as of this writing, but we should remain vigilant as packet formats become more complex over time.
158 *
159 * @todo With C++11, some lines of code could be eliminated by using `using` for Low_lvl_packet sub-types
160 * to inherit the constructor(s) of Low_lvl_packet. (For some of the sub-types an explicit constructor
161 * would still be necessary, but it would just shadow the inherited one, which is fine and still saves lines
162 * in the other sub-types.) However, for now I've left it as-is, partially to be friendly to the Doxygen
163 * documentation generator, and partially to make the interface easy to read. Still, it may be better the other
164 * way.
165 */
168 // Endow us with shared_ptr<>s ::Ptr and ::Const_ptr (syntactic sugar).
169 public util::Shared_ptr_alias_holder<boost::shared_ptr<Low_lvl_packet>>,
170 public log::Log_context,
171 private boost::noncopyable
172{
173 // Types.
174
175 /**
176 * Short-hand for boost.asio immutable buffer, which essentially is a pointer to and length of a memory area.
177 *
178 * @todo Consider moving alias Low_lvl_packet::Const_buffer to `util` namespace or even outside it, as it is
179 * used commonly (or `boost::asio::const_buffer` is used where `Const_buffer` could be used for readability).
180 */
181 using Const_buffer = boost::asio::const_buffer;
182
183 /**
184 * Short-hand for sequence of immutable buffers; i.e., a sequence of 1 or more scattered areas in memory.
185 * This is a model of the `ConstBufferSequence` model in boost.asio, which means a `const` reference to this
186 * can be passed to boost.asio scatter-gathering send functions such as `Udp_socket::async_send_to()`;
187 * the scattered buffers represented by an instance of this type will be, at high performance, gathered
188 * into a single UDP datagram and sent over the wire if possible.
189 */
190 using Const_buffer_sequence = std::vector<Const_buffer>;
191
192 /// Type used for `m_security_token` member of a couple different packet types.
193 using security_token_t = uint64_t;
194
195 /**
196 * Type used to store the retransmission count in DATA and ACK packets.
197 *
198 * Why 8 bits? This handles up 255 retransmissions, which is long after we'd kill the connection
199 * anyway.
200 */
202
203 /// Type used to store the size of `m_rcv_wnd` member in a couple of different packet types.
204 using rcv_wnd_t = uint32_t;
205
206 /* Data: These are actual Common Header payload.
207 *
208 * These are common to all packet types, since we are super-`struct` to all actual packet types.
209 *
210 * Note the implicit data field typeid(*this) which identifies the actual type of this packet.
211 * (C++ subtlety: typeid(this) will just yield typeid(Low_lvl_packet), which isn't that useful;
212 * but typeid(*this) will actually get you typeid(Data_packet), typeid(Ack_packet), etc. */
213
214 /**
215 * Option indicating whether this connection is using retransmission or not. This value must not
216 * change over the course of a connection and is provided in each packet for simpler
217 * deserialization (so that the latter can proceed completely without having to check the
218 * connection properties).
219 *
220 * For a given connection handshake, the SYN receiver should either disconnect/RST or respond with
221 * SYN_ACK. If it responds with SYN_ACK, it indicates agreement to abide by this option for the
222 * rest of the connection.
223 */
225
226#pragma pack(push, 1)
227 /// Packed group affected by `#pragma pack`.
228 struct
229 {
230 // Data.
231
232 /// Flow-protocol port # of socket in sending Node.
234 /// Flow-protocol port # of socket in receiving Node.
237#pragma pack(pop)
238
239 // Type checks.
240 static_assert(std::numeric_limits<flow_port_t>::is_integer
241 && (!std::numeric_limits<flow_port_t>::is_signed),
242 "Ports are non-negative integers.");
243
244 // Data: These are peripheral (not actual packet payload).
245
246 /// `ostream` manipulator (argument to `ostream <<`) that will output packet's type ("ACK", "RST", etc.).
247 const Function<std::ostream& (std::ostream&)> m_type_ostream_manip;
248
249 /// `ostream` manipulator (argument to `ostream <<`) that will output packet info suitable for DATA log level.
250 const Function<std::ostream& (std::ostream&)> m_verbose_ostream_manip;
251
252 /// `ostream` manipulator (argument to `ostream <<`) that will output packet info suitable for TRACE log level.
253 const Function<std::ostream& (std::ostream&)> m_concise_ostream_manip;
254
255 // Methods.
256
257 /**
258 * Constructs packet with uninitialized (essentially random) values, of the Low_lvl_packet sub-type specified
259 * as the template parameter (Ack_packet, Rst_packet, etc.). Since any constructor is not public, this is
260 * the only way to instantiate a blank Low_lvl_packet sub-object.
261 *
262 * Compiler template parameter inference should make the following work, so the template parameter can be omitted.:
263 *
264 * ~~~
265 * shared_ptr<Ack_packet> = create_uninit_packet(get_logger());
266 * // ^-- Low_lvl_packet_sub was inferred to be Ack_packet based on the left hand side of the assignment.
267 * ~~~
268 *
269 * @tparam Low_lvl_packet_sub
270 * Any type deriving from Low_lvl_packet.
271 * @param logger_ptr
272 * Logger to use subsequently in the new object.
273 * @return Ref-counted pointer to newly created object of the specified type.
274 * If you need an up-cast pointer, use create_uninit_packet_base().
275 */
276 template<typename Low_lvl_packet_sub>
277 static boost::shared_ptr<Low_lvl_packet_sub> create_uninit_packet(log::Logger* logger_ptr);
278
279 /**
280 * A simple convenience method that casts the result of create_uninit_packet() from `shared_ptr<T>`, where `T` is a
281 * sub-type of Low_lvl_packet, to `shared_ptr<Low_lvl_packet>` a/k/a Ptr.
282 *
283 * @param logger_ptr
284 * See create_uninit_packet().
285 * @return See create_uninit_packet() (but cast to a type compatible with the polymorphic base type).
286 */
287 template<typename Low_lvl_packet_sub>
288 static Ptr create_uninit_packet_base(log::Logger* logger_ptr);
289
290 /**
291 * Constructs packet on the heap with values determined by the given raw binary data as presumably
292 * received from the wire and originally serialized by a compatible serializing Node. The returned
293 * value is a reference-counted pointer with a reference count of 1 (i.e., no other references to
294 * underlying object have been saved anywhere by the time method returns).
295 *
296 * It is the opposite of serialize_to_raw_data() but not symmetrically efficient; where the latter
297 * produces a sequence of pointers/lengths of already present areas of memory (no copying), the present method
298 * copies the raw data into a new structure and is thus less efficient.
299 *
300 * Suppose `ptr` is returned. Then `*ptr` is of polymorphic type `Low_lvl_packet*` but actually is
301 * of some specific sub-type (like `Ack_packet*`). `typeid(*ptr)` can be used to determine the exact type.
302 * In particular one can write things like: `bool is_ack = typeid(*ptr) == typeid(Ack_packet)`.
303 * Of course, in many cases one may call one of a number of virtual methods of Low_lvl_packet to get
304 * type-specific polymorphic behavior.
305 *
306 * @see m_type_ostream_manip() for easy way to output human-readable version of `typeid(*ptr).name()`, where
307 * `ptr` is the value returned.
308 * @param raw_packet
309 * Pointer to entire packet raw buffer as received over the wire.
310 * Upon return, the state of `*raw_packet` is not known; and caller retains
311 * ownership of it (e.g., can read another datagram into it if desired). As of this writing it will either
312 * remain unchanged or be emptied (via a move elsewhere) -- but ideally code without relying on either specific
313 * outcome.
314 * @param prefer_no_move
315 * If `true`, the method should (if at all reasonable) not alter `raw_packet->capacity()` (in particular
316 * it should not use move semantics to send its contents to another data structure); otherwise
317 * it should be free to do so (i.e., if it considers doing so beneficial for performance reasons).
318 * @param logger_ptr
319 * Will be used to log within this method as well as be saved as the
320 * `Logger*` in the new Low_lvl_packet created and returned (if any).
321 * @return A null pointer on failure; otherwise pointer to an object of some sub-type of Low_lvl_packet.
322 */
323 static Ptr create_from_raw_data_packet(log::Logger* logger_ptr, util::Blob* raw_packet, bool prefer_no_move);
324
325 /**
326 * Serializes the current logical packet data from `*this` into the given `Const_buffer_sequence`,
327 * which is a sequence of pointers and lengths of existing scattered areas in memory, presumably
328 * for transmission over the wire to a compatible serializing Node.
329 *
330 * It is the opposite of create_from_raw_data_packet() but not symmetrically efficient; where the latter
331 * copies the raw data into a new structure, the present method produces a sequence of pointers/lengths
332 * of already present areas of memory (no copying) and is thus more efficient.
333 *
334 * The input `*raw_bufs` is appended to and is *not* cleared by this method. Thus one may use this
335 * method to produce a larger buffer sequence of which the serialization of `*this` is only a part
336 * (possibly in the middle somewhere).
337 *
338 * Behavior is undefined if one modifies `*this` after calling the present method. It is safer to
339 * run this on a `const Low_lvl_packet` rather than a mutable Low_lvl_packet.
340 *
341 * @warning This efficiency comes with an important caveat: the generated additions to `*raw_bufs` will
342 * remain valid *only* while `*this` exists. If its destructor runs, the buffers added here
343 * will become invalid, and accessing them will result in undefined behavior.
344 *
345 * @param raw_bufs
346 * Pointer to the sequence of `Const_buffer`s into which we will append pointers/lengths
347 * of serialized data.
348 * @return Size in bytes of the data references to which have been appended to `*raw_bufs`;
349 * Already present data are not included.
350 */
351 virtual size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const = 0;
352
353 /**
354 * Identical to serialize_to_raw_data() but adds log-level-appropriate logging after the operation.
355 *
356 * @param raw_bufs
357 * See serialize_to_raw_data().
358 * @return See serialize_to_raw_data().
359 */
361
362 /**
363 * Returns a brief (a few characters) string description of the given packet type given as
364 * `type_index(typeid(p))`, where `p` is a reference to an instance of a concrete Low_lvl_packet sub-type.
365 *
366 * @param type_id
367 * See above. If the `p` points to a value of some other type, behavior is undefined.
368 * @return Reference to a string without newlines or other whitespace: "DATA", "ACK", "SYN_ACK_ACK", etc.
369 */
370 static const std::string& type_id_to_str(const std::type_index& type_id);
371
372protected:
373 // Constructors/destructor.
374
375 /**
376 * Constructs packet with uninitialized (essentially random) values. This is not public, because
377 * a Low_lvl_packet is meaningless without being of some specific sub-type referring to an actual
378 * packet (e.g., Ack_packet, Rst_packet, etc.). (The presence of pure virtual methods would probably
379 * accomplish this too, but it's nice to be explicit.)
380 *
381 * @param logger_ptr
382 * Logger to use subsequently.
383 */
384 explicit Low_lvl_packet(log::Logger* logger_ptr);
385
386 // Methods.
387
388 /**
389 * Helper for serialize_to_raw_data() implementations in sub-types that encodes the header common to all
390 * packet types, starting with the packet type ID leading that header.
391 *
392 * @param raw_bufs
393 * See serialize_to_raw_data(). Header fields are encoded and appended to this.
394 * @return See serialize_to_raw_data(). The total # of bytes encoded and appended to `*raw_bufs` by the call.
395 */
397
398 /**
399 * Writes a multi-line representation of `*this` to an output stream.
400 *
401 * Unless the sub-type needs to add no information of its own (as of this writing, the case for Rst_packet),
402 * this implementation (of this virtual method) is only present as a utility for the sub-types.
403 * The sub-type is recommended to first call this implementation; then add type-specific lines
404 * afterwards, ending with a newline. Following this recommendation will result in uniform, decent-looking
405 * overall output.
406 *
407 * @note This is protected, because it is meant only to be used in the implementation of
408 * the `ostream` manipulators #m_verbose_ostream_manip and #m_concise_ostream_manip, which
409 * are public and to be used by users of this type.
410 * @param os
411 * The output stream to use. Normally I'd make this a pointer, but this non-constant reference is
412 * fairly typical in STL and the world in general, for `ostream` in particular.
413 * @param verbose
414 * If `false`, output suitable for TRACE level logging is produced; otherwise for DATA level logging.
415 * @return `os`.
416 */
417 virtual std::ostream& to_ostream(std::ostream& os, bool verbose = false) const;
418
419 /**
420 * Returns `true`, at compile time, if and only if the native memory representation is big-endian, meaning,
421 * for example, the value `uint32_t(1)` is stored as the bytes, in order, 0x00 0x00 0x00 0x01, and not the reverse.
422 * Can be used in a compile-time check such as `static_assert()`.
423 *
424 * @return See above.
425 */
426 static constexpr bool native_is_big_endian();
427
428private:
429 // Types.
430
431#pragma pack(push, 1)
432
433 /**
434 * Helper data store type for storing binary data needed by serialize_to_raw_data(), when certains bits
435 * are not already represented by the public data members present in `struct` Low_lvl_packet.
436 *
437 * The need for this is somewhat subtle and is explained fully inside Low_lvl_packet::serialize_to_raw_data(),
438 * so I won't go into it here. Also see each data member's doc header.
439 */
441 private boost::noncopyable
442 {
443 /**
444 * This is the serialized version of the multi-byte `bool` Low_lvl_packet::m_opt_rexmit_on.
445 * Since the latter is of a more civilized `bool` type, and we need a single byte version, this here
446 * is set to the obvious encoding of the `bool`, when Low_lvl_packet::serialize_to_raw_data() needs to
447 * serialize said `bool`.
448 */
450
451 /**
452 * Unused space reserved for future use, ensuring correct alignment of other fields and
453 * headers. Currently it must be always set to zero. Since Low_lvl_packet has no need of a public
454 * data member like this, we keep it in here, as needed for Low_lvl_packet::serialize_to_raw_data().
455 */
456 const uint16_t m_reserved2;
457
458 // Constructors/destructor.
459
460 /// Constructs a mostly-uninitialized object, except for the `const` member(s), if any.
461 explicit Aux_raw_data();
462 };
463
464#pragma pack(pop)
465
466 /**
467 * A simple, unmodifiable data store that contains the properties unique to each packet type a/k/a
468 * concrete sub-type of Low_lvl_packet.
469 */
470 struct Packet_type_info // Cannot use boost::noncopyable, as that disables direct member initialization.
471 {
472 /// The type ID value, in serialized order, to be used in each serialization of all packets of this type.
474
475 /// The brief string representation of this packet type, suitable for Low_lvl_packet::type_id_to_str().
476 const std::string m_type_id_str;
477 };
478
479 // Methods.
480
481 /**
482 * Writes a brief representation of `typeid(*this)` -- i.e., the packet type (ACK, RST, etc.) --
483 * to an output stream. See also type_id_to_str().
484 *
485 * @note This is private, because it is meant only to be used in the implementation of
486 * the `ostream` manipulator #m_type_ostream_manip, which is public and to be used by users of this type.
487 * @param os
488 * The output stream to use. Normally I'd make this a pointer, but this non-constant reference is
489 * fairly typical in STL and the world in general, for `ostream` in particular.
490 * @return `os`.
491 */
492 std::ostream& type_to_ostream(std::ostream& os) const;
493
494 /**
495 * Helper that looks up the Packet_type_info::m_raw_type_id value for the given `typeid(p)`, where `p` refers
496 * to an instance of a concrete sub-type of Low_lvl_packet. Note that is returns a reference, and indeed the referred
497 * to memory will remain valid and unmodified throughout the program's runtime. Therefore, it can be used
498 * for serialization without copying.
499 *
500 * ### Implementation note ###
501 * It would be nice to make this `constexpr`, as then it can be used in `switch()` statement
502 * conditionals. Unfortunately, at least as of C++17, this is not possible with our current implementation:
503 * #S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO is an `unordered_map` (as of this writing), and that is not a "literal"
504 * type (in other words, lookups in it are not done at compile time, even when for a human it would seem clearly
505 * possible... iterators and such are involved, and that goes beyond what `constexpr` evaluation can do).
506 *
507 * @param type_id
508 * See type_id_to_str().
509 * @return Reference to a constant area of memory.
510 */
511 static const uint8_t& type_id_native_to_raw(const std::type_info& type_id);
512
513 /**
514 * `virtual` helper for create_from_raw_data_packet() that fills out the fields of `*this` that are *not*
515 * in Low_lvl_packet but rather in the sub-type.
516 *
517 * `*raw_buf` must represent the area of create_from_raw_data_packet()'s `*raw_buf` argument immediately
518 * following the Common Header, which is the area deserialized into Low_lvl_packet proper. Hence
519 * `*raw_buf` must point to and contain the length of the rest of that input buffer. The present method
520 * must then deserialize it into the sub-object's own fields.
521 *
522 * @param raw_buf
523 * Pointer to immutable buffer just past the input raw packet data's Common Header area.
524 * Note that while the underlying area is immutable (hence the type #Const_buffer!),
525 * `*raw_buf` itself may be modified (i.e., the area to which it will refer on exit is undefined).
526 * @param prefer_no_move
527 * See create_from_raw_data_packet().
528 * @param raw_packet
529 * See create_from_raw_data_packet(). `raw_buf` must start somewhere within it and be
530 * sized to go exactly to its end.
531 * @return `false` if create_from_raw_data_packet() should return `Ptr{}` (error); `true` if
532 * deserialization successful.
533 */
535 bool prefer_no_move, util::Blob* raw_packet) = 0;
536
537 // Constants.
538
539 /**
540 * Mapping from native `typeid()`, a/k/a packet type (for all possible packet types), to the set of properties of
541 * that packet type. The keys are every possible value of `type_index(typeid(p))`, where `p` is a reference
542 * to an instance of any concrete Low_lvl_packet sub-type.
543 *
544 * ### Implementation note ###
545 * An alternative way to implement this mechanism (as of this writing, raw type IDs and brief
546 * string descriptions per packet type) is to use `virtual` liberally, combined with a `switch` if needed. (Note,
547 * also, that a way to index -- such as in an `unordered` container -- by
548 * packet type is necessary elsewhere. We use `type_index(typeid()))` now, but a [worse] alternative is to have
549 * `virtual` type IDs returned for each Low_lvl_packet sub-type.) I could explain
550 * at length all the reasons why the chosen way is superior, but let me just give you the conclusion: I originally
551 * tried it the `virtual/switch` way. Instead of the raw type IDs and
552 * string descriptions being conveniently encapsulated in the present map (where there's little to no chance of
553 * conflicting values), they were distributed across `virtual` implementations. This was less maintainable; nor did
554 * it improve OO style, since the raw type ID values (at least) were still inter-dependent (were not allowed to
555 * conflict) in any case. The present solution does not pretend the actual contents of these values are of no
556 * interest to Low_lvl_packet itself (as opposed to the sub-types), and in not having to pretend this, all related
557 * code is quite a bit more compact and a bit more maintainable as well.
558 *
559 * Update:
560 *
561 * @todo Many years after writing the NetFlow doc header where this to-do (being added now) resides, we've learned
562 * that despite appearances and docs, lookup by `type_index` is not all that fast but actually for certain
563 * subtle reasons *is* in practice lookup by `typeid(...).name()` -- yes, by string; so reconsider the
564 * design of the map #S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO. (Also consider using a `_flat_map` variant, if
565 * still applicable, as it is generally thought to be faster than plain `unordered_map`.) Otherwise unrelated,
566 * log::Config gives background about `type_index` lookup such as why/how it is usually implemented + what to
567 * do, potentially, when avoiding it.
568 */
569 static const boost::unordered_map<std::type_index, Packet_type_info> S_NATIVE_TYPE_ID_TO_PACKET_TYPE_INFO;
570
571 // Data.
572
573 /**
574 * Auxilliary data area necessary for serialize_to_raw_data() to work. This is explained in doc header
575 * for Aux_raw_data.
576 *
577 * It is declared `mutable`, because the conceptual state contained within a Low_lvl_packet is expressed
578 * via its public non-`const` data members. #m_aux_raw_data is merely a helper data store for
579 * the `const` method serialize_to_raw_data(). Since that method is `const`, this should be `mutable`,
580 * like a performance cache of sorts, only not exactly.
581 */
583}; // struct Low_lvl_packet
584
585/**
586 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level SYN packet.
587 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
588 *
589 * A SYN packet is sent by the actively connecting peer to a passively listening server socket.
590 * Thus a SYN arises from the Node that performs `Node::connect...()`. In response, a Syn_ack_packet
591 * is expected.
592 */
594{
595 // Data.
596
597 /**
598 * The Initial Sequence Number (ISN) of the sequence number line that the sender of this SYN will be
599 * using in `Data_packet`s over this connection, if it succeeds. All bytes actually sent by the
600 * SYN sender will start with this ISN + 1 and increment by 1 for each byte in the stream further.
601 * A retransmission of a given datum starting with sequence number S will still start with sequence number
602 * S.
603 */
605
606 /**
607 * Arbitrary serialized user-supplied metadata to send in SYN, where it can be deserialized by
608 * the user on the other side.
609 *
610 * @todo Possibly eliminate this, since NetFlow is reliable; the metadata can just be sent explicitly by the
611 * user once the connection is established. However, for now reliability is optional.
612 */
614
615 // Type checks.
616 static_assert(std::numeric_limits<Sequence_number::seq_num_t>::is_integer
617 && (!std::numeric_limits<Sequence_number::seq_num_t>::is_signed),
618 "Raw sequence numbers are non-negative integers.");
619
620 /// In serialized packet, the type ID byte identifying this as a SYN packet. Must not equal any other packet type's.
621 static const uint8_t S_RAW_TYPE_ID;
622
623 // Methods.
624
625 /**
626 * Implements Low_lvl_packet API. See that super-method's doc header.
627 *
628 * @param raw_bufs
629 * See Low_lvl_packet::serialize_to_raw_data().
630 * @return See Low_lvl_packet::serialize_to_raw_data().
631 */
632 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
633
634private:
635 // Friends.
636
637 /// Friend of Syn_packet: For access to private constructor `Syn_packet(Logger*)`.
638 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
639 friend boost::shared_ptr<Syn_packet> Low_lvl_packet::create_uninit_packet<Syn_packet>(log::Logger*);
640
641 // Constructors/destructor.
642
643 /**
644 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
645 *
646 * @param logger_ptr
647 * Logger to use subsequently.
648 */
649 explicit Syn_packet(log::Logger* logger_ptr);
650
651 // Methods.
652
653 /**
654 * Implements Low_lvl_packet API. See that super-method's doc header.
655 *
656 * @param os
657 * See Low_lvl_packet::to_ostream().
658 * @param verbose
659 * See Low_lvl_packet::to_ostream().
660 * @return `os`.
661 */
662 std::ostream& to_ostream(std::ostream& os, bool verbose) const override;
663
664 /**
665 * Implements Low_lvl_packet API. See that super-method's doc header.
666 *
667 * @param raw_buf
668 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
669 * @param prefer_no_move
670 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
671 * @param raw_packet
672 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
673 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
674 */
676 bool prefer_no_move, util::Blob* raw_packet) override;
677}; // struct Syn_packet
678
679/**
680 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level SYN_ACK packet.
681 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
682 *
683 * A SYN_ACK packet is sent by the passively listening server socket in response to a valid received SYN.
684 * Thus a SYN_ACK arises from the Node that performs Node::listen() and receives SYN. In response, a
685 * Syn_ack_ack_packet is expected to complete the 3-way handshake and establish a Peer_socket to Peer_socket
686 * connection.
687 */
689{
690 // Data.
691
692 /**
693 * Same meaning as Syn_packet::m_init_seq_num but applied to the essentially independent opposite
694 * traffic direction of the full-duplex connection being established.
695 */
697
698#pragma pack(push, 1)
699 /// Packed group affected by `#pragma pack`.
700 struct
701 {
702 /**
703 * Random security token used during SYN_ACK-SYN_ACK_ACK. For a given connection handshake, the SYN_ACK_ACK
704 * receiver ensures that `Syn_ack_ack_packet` `m_security_token` it receives is equal to the original
705 * one it had sent (this #m_security_token here).
706 */
708
709 /**
710 * Number of DATA payload bytes the sender of this packet would accept into its Receive buffer,
711 * without dropping, at the moment this packet was generated to send. This information is
712 * piggybacked into ACK (and SYN_ACK/SYN_ACK_ACK) packets.
713 *
714 * @todo We could be similar to TCP by opportunistically sending rcv_wnd in other packet types,
715 * namely Data_packet. However this would only help in connections with heavy 2-way traffic.
716 * Personally I would then prefer to create a new packet type instead, Rcv_wnd_packet, and also
717 * implement some generalized "packet combo" scheme which would allow to piggy-back arbitrary
718 * packet types together into a single packet; and then we'd dissociate
719 * ACK/SYN_ACK/SYN_ACK_ACK from rcv_wnd.
720 */
723#pragma pack(pop)
724
725 // Type checks.
726 static_assert(std::numeric_limits<Sequence_number::seq_num_t>::is_integer
727 && (!std::numeric_limits<Sequence_number::seq_num_t>::is_signed),
728 "Raw sequence numbers are non-negative integers.");
729 static_assert(std::numeric_limits<security_token_t>::is_integer
730 && (!std::numeric_limits<security_token_t>::is_signed),
731 "Security tokens are non-negative integers.");
732 static_assert(std::numeric_limits<rcv_wnd_t>::is_integer
733 && (!std::numeric_limits<rcv_wnd_t>::is_signed),
734 "rcv_wnd values are non-negative integers.");
735
736 /// In serialized packet, the type ID byte identifying this as a SYN_ACK. Must not equal any other packet type's.
737 static const uint8_t S_RAW_TYPE_ID;
738
739 // Methods.
740
741 /**
742 * Implements Low_lvl_packet API. See that super-method's doc header.
743 *
744 * @param raw_bufs
745 * See Low_lvl_packet::serialize_to_raw_data().
746 * @return See Low_lvl_packet::serialize_to_raw_data().
747 */
748 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
749
750private:
751 // Friends.
752
753 /// Friend of Syn_ack_packet: For access to private constructor `Syn_ack_packet(Logger*)`.
754 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
755 friend boost::shared_ptr<Syn_ack_packet> Low_lvl_packet::create_uninit_packet<Syn_ack_packet>(log::Logger*);
756
757 // Constructors/destructor.
758
759 /**
760 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
761 *
762 * @param logger_ptr
763 * Logger to use subsequently.
764 */
765 explicit Syn_ack_packet(log::Logger* logger_ptr);
766
767 // Methods.
768
769 /**
770 * Implements Low_lvl_packet API. See that super-method's doc header.
771 *
772 * @param os
773 * See Low_lvl_packet::to_ostream().
774 * @param verbose
775 * See Low_lvl_packet::to_ostream().
776 * @return `os`.
777 */
778 std::ostream& to_ostream(std::ostream& os, bool verbose) const override;
779
780 /**
781 * Implements Low_lvl_packet API. See that super-method's doc header.
782 *
783 * @param raw_buf
784 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
785 * @param prefer_no_move
786 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
787 * @param raw_packet
788 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
789 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
790 */
792 bool prefer_no_move, util::Blob* raw_packet) override;
793};
794
795/**
796 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level SYN_ACK_ACK packet.
797 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
798 *
799 * A SYN_ACK_ACK packet is sent by the original SYN sender in response to a valid received SYN_ACK,
800 * completing the 3-way handshake and establishing a Peer_socket to Peer_socket connection.
801 */
803{
804 // Data.
805
806#pragma pack(push, 1)
807 /// Packed group affected by `#pragma pack`.
808 struct
809 {
810 /**
811 * This must equal `Syn_ack_packet` `m_security_token` received in the packet to which `*this` is
812 * replying. The other side will only proceed with the connection if the two are equal.
813 */
815
816 /**
817 * Same meaning as in `Syn_ack_packet` but applied to the essentially independent opposite
818 * traffic direction of the full-duplex connection being established.
819 */
822#pragma pack(pop)
823
824 // Type checks.
825 static_assert(std::numeric_limits<security_token_t>::is_integer
826 && (!std::numeric_limits<security_token_t>::is_signed),
827 "Security tokens are non-negative integers.");
828 static_assert(std::numeric_limits<rcv_wnd_t>::is_integer
829 && (!std::numeric_limits<rcv_wnd_t>::is_signed),
830 "rcv_wnd values are non-negative integers.");
831
832 /// In serialized packet, the type ID byte identifying this as a SYN_ACK_ACK. Must not equal any other packet type's.
833 static const uint8_t S_RAW_TYPE_ID;
834
835 // Methods.
836
837 /**
838 * Implements Low_lvl_packet API. See that super-method's doc header.
839 *
840 * @param raw_bufs
841 * See Low_lvl_packet::serialize_to_raw_data().
842 * @return See Low_lvl_packet::serialize_to_raw_data().
843 */
844 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
845
846private:
847 // Friends.
848
849 /// Friend of Syn_ack_ack_packet: For access to private constructor `Syn_ack_ack_packet(Logger*)`.
850 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
851 friend boost::shared_ptr<Syn_ack_ack_packet> Low_lvl_packet::create_uninit_packet<Syn_ack_ack_packet>(log::Logger*);
852
853 // Constructors/destructor.
854
855 /**
856 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
857 *
858 * @param logger_ptr
859 * Logger to use subsequently.
860 */
861 explicit Syn_ack_ack_packet(log::Logger* logger_ptr);
862
863 // Methods.
864
865 /**
866 * Implements Low_lvl_packet API. See that super-method's doc header.
867 *
868 * @param os
869 * See Low_lvl_packet::to_ostream().
870 * @param verbose
871 * See Low_lvl_packet::to_ostream().
872 * @return `os`.
873 */
874 std::ostream& to_ostream(std::ostream& os, bool verbose) const override;
875
876 /**
877 * Implements Low_lvl_packet API. See that super-method's doc header.
878 *
879 * @param raw_buf
880 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
881 * @param prefer_no_move
882 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
883 * @param raw_packet
884 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
885 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
886 */
888 bool prefer_no_move, util::Blob* raw_packet) override;
889}; // struct Syn_ack_ack_packet
890
891/**
892 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level DATA packet.
893 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
894 *
895 * Each DATA packet contains actual data payload packetized from the application-provided stream
896 * of bytes. It is identified by the sequence number (encoded in this object) of the first
897 * byte of that payload. An individual acknowledgment inside an Ack_packet refers to the Data_packet
898 * by that first sequence number. If Low_lvl_packet::m_opt_rexmit_on is `true`, then #m_rexmit_id
899 * identifies which attempt at sending the payload with this sequence number and payload this
900 * packet represents: 0 is 1st attempt, 1 is 1st retry, 2 is 2nd retry, etc. If that option is off,
901 * then a lost packet is never retransmitted; and therefore #m_rexmit_id is always 0.
902 */
904{
905 // Types.
906
907 /**
908 * Type used to store the retransmission count in DATA and ACK packets.
909 *
910 * Why 8 bits? This handles up 255 retransmissions, which is long after we'd kill the connection
911 * anyway.
912 */
914
915 // Data.
916
917 /**
918 * The sequence number of the first byte in the payload; i.e., of `m_data.front()`, a/k/a `m_data[0]`.
919 * Note that #m_data cannot be empty, so #m_seq_num is always meaningful.
920 */
922
923 /**
924 * Retransmit counter of the DATA packet being sent. Identifies which attempt we are acknowledging
925 * (0 = initial, 1 = first retransmit, 2 = second retransmit, ...). Always 0 if `!m_opt_rexmit_on`.
926 */
928
929 /**
930 * This is the serialized version of `m_data.size()` (see #m_data). We send this value, even though it could
931 * be figured out from the overall serialized size, to ensure integrity (see the deserialization logic for details).
932 * This here is set to `m_data.size()`, when Low_lvl_packet::serialize_to_raw_data() needs to
933 * serialize that value. Outside serialization `m_data.size()` is used directly, and this
934 * value is meaningless.
935 */
936 mutable uint16_t m_data_size_raw;
937
938 /**
939 * The payload. Cannot be `empty()`.
940 *
941 * As of this writing there is an important (for performance) subtlety about how this is originally filled in
942 * when deserializing a wire-arrived packet. See Data_packet::deserialize_type_specific_data_from_raw_data_packet().
943 */
945
946 // Type checks.
947 static_assert(std::numeric_limits<Sequence_number::seq_num_t>::is_integer
948 && (!std::numeric_limits<Sequence_number::seq_num_t>::is_signed),
949 "Raw sequence numbers are non-negative integers.");
950 static_assert(std::numeric_limits<rexmit_id_t>::is_integer
951 && (!std::numeric_limits<rexmit_id_t>::is_signed),
952 "Retransmission IDs are non-negative integers.");
953
954 /// In serialized packet, the type ID byte identifying this as a DATA packet. Must not equal any other packet type's.
955 static const uint8_t S_RAW_TYPE_ID;
956
957 // Methods.
958
959 /**
960 * Implements Low_lvl_packet API. See that super-method's doc header.
961 *
962 * @param raw_bufs
963 * See Low_lvl_packet::serialize_to_raw_data().
964 * @return See Low_lvl_packet::serialize_to_raw_data().
965 */
966 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
967
968private:
969 // Friends.
970
971 /// Friend of Data_packet: For access to private constructor `Data_packet(Logger*)`.
972 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
973 friend boost::shared_ptr<Data_packet> Low_lvl_packet::create_uninit_packet<Data_packet>(log::Logger*);
974
975 // Constructors/destructor.
976
977 /**
978 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
979 *
980 * @param logger_ptr
981 * Logger to use subsequently.
982 */
983 explicit Data_packet(log::Logger* logger_ptr);
984
985 // Methods.
986
987 /**
988 * Implements Low_lvl_packet API. See that super-method's doc header.
989 *
990 * @param os
991 * See Low_lvl_packet::to_ostream().
992 * @param verbose
993 * See Low_lvl_packet::to_ostream().
994 * @return `os`.
995 */
996 std::ostream& to_ostream(std::ostream& os, bool verbose) const override;
997
998 /**
999 * Implements Low_lvl_packet API. See that super-method's doc header.
1000 *
1001 * @param raw_buf
1002 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1003 * @param prefer_no_move
1004 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1005 * @param raw_packet
1006 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1007 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1008 */
1010 bool prefer_no_move, util::Blob* raw_packet) override;
1011}; // struct Data_packet
1012
1013/**
1014 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level ACK packet.
1015 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
1016 *
1017 * Each ACK packet encapsulates 0 or more individual acknowledgments, each acknowledging receipt of
1018 * a specific, distinct Data_packaet; and the current rcv_wnd (receive window state) on the ACK sender's
1019 * side. The latter datum is always present. If individual acks are present, then the rcv_wnd advertising
1020 * is merely opportunistic. If NO individual acks are present, then the rcv_wnd advertising is intentional
1021 * for its own sake. The algorithm for the latter is discussed elsewhere.
1022 *
1023 * The mechanics of individual acks are further explored in the doc header for Ack_packet::Individual_ack
1024 * nested `struct`.
1025 *
1026 * @todo Conceivably, since Ack_packet actually stores 1+ acknowledgments, it should become Acks_packet, of
1027 * type ACKS (not ACK). Many comments and log messages would become clearer, as no one would assume an individual
1028 * packet's acknowledgment when reading "an ACK" or similar phrase.
1029 */
1031{
1032 // Types.
1033
1034 /**
1035 * Type used to store the ACK delay for a given individual acknowledged packet. The value
1036 * specifies the number of multiples of `Ack_delay_time_unit{1}` comprised by a packet's ACK delay.
1037 *
1038 * An earlier version of `net_flow` used the unit milliseconds and the encoding type `uint16_t`. The
1039 * reasoning was that this allowed a maximum ACK delay of ~65 sec which should be plenty; and that
1040 * the 1-millisecond finegrainedness was acceptable. However when implementing queue delay-based
1041 * congestion control (like FAST or Vegas) we realized it is important for RTTs (which use the ACK
1042 * delay value) to be quite precise (microsecond level or so). Therefore, to be totally safe, we
1043 * choose to use the same units as #Fine_duration, which is how we compute all time periods. As
1044 * for the encoding width, we use 64 bits just in case.
1045 *
1046 * @todo Reconsider the encoding width. If `Ack_delay_time_unit{1}` is a nanosecond, then 32 bits
1047 * would support a maximum delay of ~4.1 seconds which is likely fine for most real-world
1048 * scenarios. This would reduce the size of ACK packets quite a bit.
1049 */
1050 using ack_delay_t = uint64_t;
1051
1052 /// `Ack_delay_time_unit{1}` is the duration corresponding to the #ack_delay_t value 1; and proportionally further.
1054
1055 struct Individual_ack;
1058
1059 // Data.
1060
1061 /// Current receive window (remaining Receive buffer size) of the ACK sender.
1063
1064 /**
1065 * This is the serialized version of `m_rcv_acked_packets_rexmit_{on|off}_out.size()` and
1066 * `m_rcv_acked_packets.size()` (whichever is applicable in context).
1067 * We send this value, even though it could be figured out from the overall serialized
1068 * size, to ensure integrity (see the deserialization logic for details).
1069 * This here is set to `size()`, when Low_lvl_packet::serialize_to_raw_data() needs to
1070 * serialize that value. Outside serialization `size()` is used directly, and this
1071 * value is meaningless.
1072 */
1074
1075 // Type checks.
1076 static_assert(std::numeric_limits<rcv_wnd_t>::is_integer
1077 && (!std::numeric_limits<rcv_wnd_t>::is_signed),
1078 "rcv_wnd values are non-negative integers.");
1079
1080 /**
1081 * List of *incoming* (post-deserialization of ACK) acknowledgments of DATA packets,
1082 * each identified by its first datum's sequence number as
1083 * provided by the other side and ordered in the chronological order they were received.
1084 * This may also be empty, in which case the containing ACK acknowledges no DATA packets but only
1085 * advertises the current receive window size (#m_rcv_wnd). (Note that it advertises it if
1086 * #m_rcv_acked_packets is NOT empty as well.)
1087 *
1088 * This is used if and only if this Ack_packet is incoming. See #m_rcv_acked_packets_rexmit_on_out
1089 * and #m_rcv_acked_packets_rexmit_off_out for the outgoing scenario.
1090 *
1091 * Unlike vanilla TCP from RFC 793, which features cumulative acknowledgment (wherein only the
1092 * latest received segment BEFORE any unreceived gap is acknowledged, thus just one total number
1093 * in the ACK), and unlike later enhanced TCPs, which feature both cumulative acknowledgement
1094 * and individual ACKs (Selective ACKs), we use something similar to Selective ACKs only. That
1095 * is, we only acknowledge each packet individually (though we combine many such little
1096 * acknowledgments into one packet via delayed ACKs). Moreover, we do not piggy-back ACK info
1097 * onto DATA packets; ACK is its own type.
1098 *
1099 * Rationale for using SACKs only: Selective ACKs help greatly in giving accurate congestion
1100 * control data (e.g., ACK delay per packet, dropped packets) and remove complex ambiguities of
1101 * trying to interpret cumulative ACKs for that purpose. For retransmits, when enabled, Selective
1102 * ACKs also greatly simplify the design choices (since we know exactly what they don't have
1103 * [assuming no lost ACKs], we can send exactly what they want and no more).
1104 *
1105 * Rationale for keeping ACK and DATA separate: This is less clear-cut. It is easier to think
1106 * about, certainly, as the two types of traffic aren't really logically related in a full-duplex
1107 * connection. On the other hand it increases overhead. On the third hand that disadvantage is
1108 * not a big deal assuming mostly unidirectional traffic flow (which is typical), since most of
1109 * the time the ACKs would be data-less anyway in that situation. Delayed ACKs also help combat
1110 * overhead -- somewhat.
1111 *
1112 * Rationale for delayed ACKs a/k/a accumulating more than 1 acknowledgment into an ACK: Combat
1113 * overhead which can be a big deal for high bitrate streaming traffic for example (research
1114 * shows ACK flow can be 10% of data flow in the other direction). The cost is that the other
1115 * side gets somewhat delayed congestion control information, but the delay can be tuned. In
1116 * TCP implementations delayed ACKs appear to be universal since a long time ago.
1117 *
1118 * Any two packets represented by these `Individual_ack`s may be duplicates of each other (same
1119 * Sequence_number, possibly different delay values). It's up to the sender (receiver of ACK)
1120 * to sort it out. However, again, they MUST be ordered chronologicaly based on the time when
1121 * they were received; from earliest to latest.
1122 *
1123 * Storing shared pointers to avoid copying of `struct`s (however small) during internal
1124 * reshuffling; shared instead of raw pointers to not worry about `delete`.
1125 */
1126 std::vector<boost::shared_ptr<Individual_ack>> m_rcv_acked_packets;
1127
1128 /**
1129 * Equivalent of #m_rcv_acked_packets but used for *outgoing* (pre-serialization of ACK) acknowledgments
1130 * and only if retransmission is disabled. See notes in Individual_ack_rexmit_off doc header about how
1131 * this is used for efficient serialization of Ack_packet.
1132 *
1133 * This is used if and only if Ack_packet is outgoing, and retransmission is disabled.
1134 * See #m_rcv_acked_packets for the incoming scenario.
1135 */
1136 std::vector<Individual_ack_rexmit_off> m_rcv_acked_packets_rexmit_off_out;
1137
1138 /// Equivalent of #m_rcv_acked_packets_rexmit_off_out but for retransmission enabled.
1139 std::vector<Individual_ack_rexmit_on> m_rcv_acked_packets_rexmit_on_out;
1140
1141 /// In serialized packet, the type ID byte identifying this as an ACK packet. Must not equal any other packet type's.
1143
1144 // Methods.
1145
1146 /**
1147 * Implements Low_lvl_packet API. See that super-method's doc header.
1148 *
1149 * @param raw_bufs
1150 * See Low_lvl_packet::serialize_to_raw_data().
1151 * @return See Low_lvl_packet::serialize_to_raw_data().
1152 */
1153 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
1154
1155private:
1156 // Friends.
1157
1158 /// Friend of Ack_packet: For access to private constructor `Ack_packet(Logger*)`.
1159 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
1160 friend boost::shared_ptr<Ack_packet> Low_lvl_packet::create_uninit_packet<Ack_packet>(log::Logger*);
1161
1162 // Constructors/destructor.
1163
1164 /**
1165 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
1166 *
1167 * @param logger_ptr
1168 * Logger to use subsequently.
1169 */
1170 explicit Ack_packet(log::Logger* logger_ptr);
1171
1172 // Methods.
1173
1174 /**
1175 * Implements Low_lvl_packet API. See that super-method's doc header.
1176 *
1177 * @param os
1178 * See Low_lvl_packet::to_ostream().
1179 * @param verbose
1180 * See Low_lvl_packet::to_ostream().
1181 * @return `os`.
1182 */
1183 std::ostream& to_ostream(std::ostream& os, bool verbose) const override;
1184
1185 /**
1186 * Implements Low_lvl_packet API. See that super-method's doc header.
1187 *
1188 * @param raw_buf
1189 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1190 * @param prefer_no_move
1191 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1192 * @param raw_packet
1193 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1194 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1195 */
1197 bool prefer_no_move, util::Blob* raw_packet) override;
1198}; // struct Ack_packet
1199
1200/**
1201 * Specifies the *incoming* (post-deserialization) acknowledgment of a single received Data_packet.
1202 * It is not copyable, and moving them around by smart Individual_ack::Ptr is encouraged.
1203 * Construct this by direct member initialization.
1204 */
1206 // Cannot use boost::noncopyable or Shared_ptr_alias_holder, because that turns off direct initialization.
1207{
1208 // Types.
1209
1210 /// Short-hand for ref-counted pointer to mutable objects of this class.
1211 using Ptr = boost::shared_ptr<Individual_ack>;
1212
1213 /// Short-hand for ref-counted pointer to immutable objects of this class.
1214 using Const_ptr = boost::shared_ptr<const Individual_ack>;
1215
1216 // Data.
1217
1218 /**
1219 * Sequence number of first datum in packet that we acknowledge.
1220 * This is non-`const` for a technical reason: one must be able to use Sequence_number::set_metadata().
1221 */
1223
1224 /// The delay between when we received the acknowledged packet and when decided to send this ack.
1226
1227 /**
1228 * Retransmit counter of the acknowledged Data_packet. Identifies which attempt we are acknowledging
1229 * (0 = initial, 1 = first retransmit, 2 = second retransmit, ...). Literally this equals the acked
1230 * Data_packet::m_rexmit_id. Always 0 if retransmission is disabled for the given socket.
1231 */
1232 const unsigned int m_rexmit_id;
1233
1234 /// Make us noncopyable without breaking aggregateness (direct-init).
1235 [[no_unique_address]] util::Noncopyable m_nc{};
1236}; // struct Ack_packet::Individual_ack
1237
1238static_assert(std::is_aggregate_v<Ack_packet::Individual_ack>,
1239 "We want it to be direct-initializable.");
1240static_assert((!std::is_copy_constructible_v<Ack_packet::Individual_ack>)
1241 && (!std::is_copy_assignable_v<Ack_packet::Individual_ack>),
1242 "We want it to be noncopyable but rather passed-around via its ::Ptr.");
1243
1244#pragma pack(push, 1)
1245
1246/**
1247 * Specifies the *outgoing* (pre-serialization) acknowledgment of a single received Data_packet, when
1248 * retranmission is disabled on the socket. Assuming network byte order equals native byte order,
1249 * and given that tight `struct` field packing is enabled throughout this code, one can arrange a tight
1250 * array of these `struct`s and transmit that entire array over the network with no need for scatter/gather
1251 * or any additional transformation of data post-construction and pushing onto aforementioned array.
1252 * These are copy-constructible, for pushing onto containers and such, but not assignable to avoid unnecessary
1253 * copying. Update: A later version of clang does not like
1254 * this technique and warns about it; to avoid any such trouble just forget the non-assignability stuff;
1255 * it's internal code; we should be fine.
1256 *
1257 * @see Historical note in Ack_packet::serialize_to_raw_data() explains why this and
1258 * Individual_ack_rexmit_on both exist, instead of simply using Individual_ack in both directions.
1259 */
1261{
1262 // Data.
1263
1264 /// See Individual_ack::m_seq_num and Sequence_number::raw_num_ref().
1266
1267 /// See Individual_ack::m_delay; this is in `Ack_delay_time_unit{1}` multiples.
1269
1270 // Type checks.
1271 static_assert(std::numeric_limits<Sequence_number::seq_num_t>::is_integer
1272 && (!std::numeric_limits<Sequence_number::seq_num_t>::is_signed),
1273 "Raw sequence numbers are non-negative integers.");
1274 static_assert(std::numeric_limits<ack_delay_t>::is_integer
1275 && (!std::numeric_limits<ack_delay_t>::is_signed),
1276 "Time periods are non-negative integers.");
1277
1278 // Constructors/destructor.
1279
1280 /**
1281 * Constructs object.
1282 *
1283 * @param seq_num
1284 * `seq_num.raw_num_ref()` is copied to #m_seq_num_raw.
1285 * @param delay
1286 * #m_delay.
1287 */
1288 explicit Individual_ack_rexmit_off(const Sequence_number& seq_num, ack_delay_t delay);
1289};
1290
1291/// Equivalent of `Individual_ack_rexmit_off` but for sockets with retransmission enabled.
1293{
1294 // Data.
1295
1296 /// Stores the values applicable to both Individual_ack_rexmit_off and Individual_ack_rexmit_on.
1298
1299 /// See Individual_ack::m_rexmit_id but note the type difference.
1301
1302 // Type checks.
1303 static_assert(std::numeric_limits<rexmit_id_t>::is_integer
1304 && (!std::numeric_limits<rexmit_id_t>::is_signed),
1305 "Retransmission IDs are non-negative integers.");
1306
1307 // Constructors/destructor.
1308
1309 /**
1310 * Constructs object.
1311 *
1312 * @param seq_num
1313 * Individual_ack_rexmit_off::m_seq_num.
1314 * @param rexmit_id
1315 * #m_rexmit_id.
1316 * @param delay
1317 * Individual_ack_rexmit_off::m_delay.
1318 */
1319 explicit Individual_ack_rexmit_on(const Sequence_number& seq_num, unsigned int rexmit_id, ack_delay_t delay);
1320};
1321
1322#pragma pack(pop)
1323
1324/**
1325 * Internal `net_flow` `struct` that encapsulates the Flow-protocol low-level RST packet.
1326 * See Low_lvl_packet doc header for information common to all low-level packets including this one.
1327 *
1328 * An RST means the sender is immediately shutting down the connection without waiting for any
1329 * feedback from the receiver and is recommending that the latter do the same ASAP. This is sent in
1330 * a variety of error situations.
1331 *
1332 * Implemementation notes
1333 * ----------------------
1334 * The one peculiar thing about Rst_packet is it contains no data beyond the super-`struct` Low_lvl_packet,
1335 * other than the fact it *is* an Rst_packet (i.e., its `typeid()` identifies it as such). Thus its
1336 * various `virtual` methods are typically either simple or even don't exist and defer to the Low_lvl_packet
1337 * implementation.
1338 */
1340{
1341
1342 // Methods.
1343
1344 /**
1345 * Implements Low_lvl_packet API. See that super-method's doc header.
1346 *
1347 * @param raw_bufs
1348 * See Low_lvl_packet::serialize_to_raw_data().
1349 * @return See Low_lvl_packet::serialize_to_raw_data().
1350 */
1351 size_t serialize_to_raw_data(Const_buffer_sequence* raw_bufs) const override;
1352
1353 // Data.
1354
1355 /// In serialized packet, the type ID byte identifying this as an RST packet. Must not equal any other packet type's.
1357
1358private:
1359 // Friends.
1360
1361 /// Friend of Rst_packet: For access to private constructor `Rst_packet(Logger*)`.
1362 // @todo Doxygen complains unless I make the above a Doxygen comment. In other places it doesn't complain. Fix...?
1363 friend boost::shared_ptr<Rst_packet> Low_lvl_packet::create_uninit_packet<Rst_packet>(log::Logger*);
1364
1365 // Constructors/destructor.
1366
1367 /**
1368 * The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
1369 *
1370 * @param logger_ptr
1371 * Logger to use subsequently.
1372 */
1373 explicit Rst_packet(log::Logger* logger_ptr);
1374
1375 // Methods.
1376
1377 /**
1378 * Implements Low_lvl_packet API. See that super-method's doc header.
1379 *
1380 * @param raw_buf
1381 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1382 * @param prefer_no_move
1383 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1384 * @param raw_packet
1385 * See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1386 * @return See Low_lvl_packet::deserialize_type_specific_data_from_raw_data_packet().
1387 */
1389 bool prefer_no_move, util::Blob* raw_packet) override;
1390}; // struct Rst_packet
1391
1392// Template and constexpr implementations.
1393
1394template<typename Low_lvl_packet_sub>
1395boost::shared_ptr<Low_lvl_packet_sub> Low_lvl_packet::create_uninit_packet(log::Logger* logger) // Static.
1396{
1397 using boost::shared_ptr;
1398
1399 // Note: Low_lvl_packet_sub is not Low_lvl_packet. It is a sub-type: Syn_packet, Ack_packet, etc. We're a template.
1400
1401 // `friend` relation required to be able to call this private constructor.
1402 return shared_ptr<Low_lvl_packet_sub>(new Low_lvl_packet_sub{logger});
1403}
1404
1405template<typename Low_lvl_packet_sub>
1407{
1408 return Low_lvl_packet::ptr_cast(create_uninit_packet<Low_lvl_packet_sub>(logger));
1409}
1410
1411constexpr bool Low_lvl_packet::native_is_big_endian() // Static.
1412{
1413 using boost::endian::native_to_big;
1414
1415 constexpr uint16_t TEST_VAL = 0x0102;
1416 return native_to_big(TEST_VAL) == TEST_VAL;
1417}
1418
1419} // namespace flow::net_flow
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Definition: log.hpp:1786
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1392
An internal net_flow sequence number identifying a piece of data.
Definition: seq_num.hpp:126
uint64_t seq_num_t
Raw sequence number type.
Definition: seq_num.hpp:138
An empty interface, consisting of nothing but a default virtual destructor, intended as a boiler-plat...
Definition: util.hpp:50
Convenience class template that endows the given subclass T with nested aliases Ptr and Const_ptr ali...
static Ptr ptr_cast(const From_ptr &ptr_to_cast)
Provides syntactic-sugary way to perform a static_pointer_cast<> from a compatible smart pointer type...
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*).
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).
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
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
Specifies the outgoing (pre-serialization) acknowledgment of a single received Data_packet,...
const Sequence_number::seq_num_t m_seq_num_raw
See Individual_ack::m_seq_num and Sequence_number::raw_num_ref().
const ack_delay_t m_delay
See Individual_ack::m_delay; this is in Ack_delay_time_unit{1} multiples.
Individual_ack_rexmit_off(const Sequence_number &seq_num, ack_delay_t delay)
Constructs object.
Equivalent of Individual_ack_rexmit_off but for sockets with retransmission enabled.
Data_packet::rexmit_id_t m_rexmit_id
See Individual_ack::m_rexmit_id but note the type difference.
Individual_ack_rexmit_off m_basic_ack
Stores the values applicable to both Individual_ack_rexmit_off and Individual_ack_rexmit_on.
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.
Sequence_number m_seq_num
Sequence number of first datum in packet that we acknowledge.
boost::shared_ptr< const Individual_ack > Const_ptr
Short-hand for ref-counted pointer to immutable objects of this class.
util::Noncopyable m_nc
Make us noncopyable without breaking aggregateness (direct-init).
const Fine_duration m_delay
The delay between when we received the acknowledged packet and when decided to send this ack.
boost::shared_ptr< Individual_ack > Ptr
Short-hand for ref-counted pointer to mutable objects of this class.
const unsigned int m_rexmit_id
Retransmit counter of the acknowledged Data_packet.
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.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as an ACK packet. Must not equal any other pa...
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...
std::vector< Individual_ack_rexmit_on > m_rcv_acked_packets_rexmit_on_out
Equivalent of m_rcv_acked_packets_rexmit_off_out but for retransmission enabled.
Ack_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
std::vector< Individual_ack_rexmit_off > m_rcv_acked_packets_rexmit_off_out
Equivalent of m_rcv_acked_packets but used for outgoing (pre-serialization of ACK) acknowledgments an...
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.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as a DATA packet. Must not equal any other pa...
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].
uint8_t rexmit_id_t
Type used to store the retransmission count in DATA and ACK packets.
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.
Helper data store type for storing binary data needed by serialize_to_raw_data(), when certains bits ...
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.
A simple, unmodifiable data store that contains the properties unique to each packet type a/k/a concr...
const uint8_t m_raw_type_id
The type ID value, in serialized order, to be used in each serialization of all packets of this type.
const std::string m_type_id_str
The brief string representation of this packet type, suitable for Low_lvl_packet::type_id_to_str().
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.
static boost::shared_ptr< Low_lvl_packet_sub > create_uninit_packet(log::Logger *logger_ptr)
Constructs packet with uninitialized (essentially random) values, of the Low_lvl_packet sub-type spec...
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...
static constexpr bool native_is_big_endian()
Returns true, at compile time, if and only if the native memory representation is big-endian,...
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.
virtual bool deserialize_type_specific_data_from_raw_data_packet(Const_buffer *raw_buf, bool prefer_no_move, util::Blob *raw_packet)=0
virtual helper for create_from_raw_data_packet() that fills out the fields of *this that are not in L...
static Ptr create_uninit_packet_base(log::Logger *logger_ptr)
A simple convenience method that casts the result of create_uninit_packet() from shared_ptr<T>,...
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....
flow_port_t m_dst_port
Flow-protocol port # of socket in receiving Node.
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.
const Function< std::ostream &(std::ostream &)> m_concise_ostream_manip
ostream manipulator (argument to ostream <<) that will output packet info suitable for TRACE log leve...
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.
const Function< std::ostream &(std::ostream &)> m_verbose_ostream_manip
ostream manipulator (argument to ostream <<) that will output packet info suitable for DATA log level...
flow_port_t m_src_port
Flow-protocol port # of socket in sending Node.
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.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as an RST packet. Must not equal any other pa...
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.
rcv_wnd_t m_rcv_wnd
Same meaning as in Syn_ack_packet but applied to the essentially independent opposite traffic directi...
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.
security_token_t m_security_token
This must equal Syn_ack_packet m_security_token received in the packet to which *this is replying.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as a SYN_ACK_ACK. Must not equal any other pa...
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.
rcv_wnd_t m_rcv_wnd
Number of DATA payload bytes the sender of this packet would accept into its Receive buffer,...
Syn_ack_packet(log::Logger *logger_ptr)
The implementation of Low_lvl_packet::create_uninit_packet() for this sub-type of Low_lvl_packet.
security_token_t m_security_token
Random security token used during SYN_ACK-SYN_ACK_ACK.
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.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as a SYN_ACK. Must not equal any other packet...
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.
static const uint8_t S_RAW_TYPE_ID
In serialized packet, the type ID byte identifying this as a SYN packet. Must not equal any other pac...
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.
Useful as a no-unique-address private member to make a type noncopyable while keeping that type an ag...
Definition: util.hpp:79