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