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