Flow 1.0.2
Flow project: Full implementation reference.
seq_num.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
22#include "flow/log/log.hpp"
23
24namespace flow::net_flow
25{
26
27/**
28 * An internal `net_flow` sequence number identifying a piece of data. While it would not be
29 * hard to just deal with raw sequence numbers everywhere, it seemed prudent to wrap the raw number
30 * in a light-weight object in order to make the interface abstract and be able to change the
31 * implementation later. For example, we may change the size of the number and how wrapping works
32 * (and even whether there is wrapping), at which point we'd rather only change this class's
33 * internals as opposed to code all over the place. For example, operator+() may change from not
34 * worrying about wrapping to worrying about it (and similarly for operator-()).
35 *
36 * The companion nested class Generator is used to generate the initial sequence number (ISN) for a
37 * connection.
38 *
39 * What does one Sequence_number represent? A byte or a packet? This class is intentionally
40 * ignorant of this. It just deals with a number on the number line. The user of the class is
41 * responsible for such matters.
42 *
43 * ### Metadata ###
44 *
45 * Sequence numbers being used for a given purpose always have certain features to make them useful.
46 * The following is a (n arguably overfly formal and detailed) discussion of those features and how
47 * we support them via "metadata."
48 *
49 * - Each sequence number line has a "zero" point Z, which is a sequence number such that it is more
50 * useful to specify a given absolute sequence number as (S - Z) with the corresponding explicit sign.
51 * So S = Z is written as =0, S > Z (most typical) is +M, S < Z (typically invalid)
52 * is -M, where M means magnitude, with M > 0.
53 * - Sometimes, in particular when individual sequence numbers represent individual sequential bytes in
54 * non-stop traffic (i.e., where user has more bytes than bandwidth can pass at any time, so there are
55 * always more bytes), and when the traffic is packetized into blocks of size B, it is convenient to
56 * specify the magnitude M as a multiple of B. This can be written as xN%R -- or just xN when R = 0 --
57 * where N = M / B, R = M % B. If one chooses zero point Z just right (so that S = 0 represents the very
58 * first byte in the entire sequence), and there is so much traffic that there are no incomplete
59 * packets (i.e., of length < B) formed, then edge sequence numbers and packet (and multi-packet) ranges
60 * become extremely simple, small, convenient.
61 * - Consider Flow DATA/ACK sequence numbers in particular. The ISN is the value Si chosen for SYN message;
62 * therefore the very first byte has absolute number (Si + 1). So let's set Z = (Si + 1). If only full
63 * packets are ever sent (which would be true if the Send buffer is always kept full by user, i.e.,
64 * pipe < user data supply, quite typical in test applications), then every single packet will have
65 * sequence number range [+x`N`, +x`(N + 1)`) (where `N` >= 0); and every single contiguous-packet range
66 * of I = 1 or more packets will thus have form [+x`N`, +x`(N + I)`). Of course, B = max-block-size.
67 * - If one were to use absolute numbers instead, they would be incredibly far from zero and also multiples
68 * of many bytes (often that number, B, being something annoying like 8192 or even some odd number).
69 * That's a far cry from literally 0, 1, 2, ... (with %remainder kicking in, if an incomplete packet
70 * of DATA is generated for some reason).
71 * - CAUTION! It's tempting -- for this particular application (or in TCP sequence numbers, as well) --
72 * to set Z = ISN. However, the ISN, by convention, equals *1 less* than the first actual DATA
73 * byte's sequence number. Always remember to set Z = ISN + 1 -- *even inside the ISN itself*!
74 * - Every sequence number line has some qualitative purpose; e.g., "Remote DATA-received sequence numbers" or
75 * "Local ACK-received sequence numbers." This can be identified by a single letter prefix places in front
76 * of a number on the line. E.g., a full number might look like: L-x23%1, which means S = Z - (23 x B + 1).
77 * The prefix is called "number line ID."
78 * - Note that Z and B themselves are hidden. If computing S is ever necessary, one might have to hunt for
79 * it (or Z, B) in prior logs. This is a cost that would be paid for the conciseness of L+x2 (for example)
80 * instead of 1285561384998534.
81 *
82 * Sequence_number has optional support for the above conventions. While #m_num stores the basic absolute value S,
83 * we also store the following, called *metadata*:
84 *
85 * - Zero point, Z (#m_zero_point_num).
86 * - Z = 0 = default, is allowed.
87 * - However, by convention sign will be omitted from `ostream`-serialization -- since raw number is unsigned,
88 * and no non-zero numbers less than 0 exist.
89 * - Recall, also, that S = 0 itself is reserved/illegal by convention.
90 * - Multiple size, B (#m_multiple_size)
91 * - 0 = default, "none chosen".
92 * - `ostream`-serialization will avoid mentioning multiples/remainders.
93 * - Number line ID (#m_num_line_id).
94 * - `char(0)` = default, "none chosen".
95 * - `ostream`-serialization will simply feature no prefix.
96 *
97 * Use set_metadata() to set the full set of metadata. For maximum effectiveness, consider these tips -- especially
98 * vis-a-vis DATA/ACK-pertinent sequence numbers.
99 *
100 * - Consider not calling set_metadata() on an incoming packet's various sequence number members until it has been
101 * logged (if appropriate) once. Thus the raw number is available *if* necessary (hopefully never).
102 * - Remember that, by Flow-protocol (and, arguably, TCP) convention, Z = ISN + 1. Z =/= ISN. See above for details.
103 * - Even for the Sequence_number storing the ISN; actually, *especially* that one (see below re. copying)!
104 * - Importantly, every copy (`operator=()`, copy constructor),
105 * including many implicit invocations thereof (`operator+()`, associative storage, etc.), will always copy
106 * the metadata too. Be sure to rely on this strongly! If you set an ISN with its Z = ISN + 1 and B = socket's
107 * max-block-size; and then all other Sequence_number objects are copies (direct or otherwise) thereof, then
108 * they should have the proper metadata and will be beautifully logged as a result. So just set the induction
109 * base and let the machinery work.
110 * - Metadata are not the actual data (#m_num = actual data) and absolutely do not participate in any
111 * comparison, arithmetic, or hash operations (which means they're also 100% ignored in associative lookups).
112 * So algorithms will work even if there's some bug with metadata.
113 *
114 * ### Thread safety ###
115 * Equally thread-safe as built-in types (not safe to read/write or write/write one
116 * object simultaneously).
117 *
118 * Implementation notes
119 * --------------------
120 *
121 * Generator and Sequence_number work based on the same assumptions (like the
122 * structure of the sequence number space), and thus their implementations may be related. So if
123 * one is changed the other may also need to be changed (internally).
124 */
126{
127public:
128 // Types.
129
130 // See below.
131 class Generator;
132
133 /**
134 * Raw sequence number type. 64 bits used because sequence number wrap-around would take many
135 * centuries at high network speeds to occur if the initial sequence number is picked to be
136 * sufficiently small. See also Generator::S_MAX_INIT_SEQ_NUM.
137 */
138 using seq_num_t = uint64_t;
139
140 /**
141 * Integer type used to express differences (distances) between Sequence_numbers.
142 *
143 * @note This type can overflow for extremely large sequence number differences (those spanning
144 * over half of the range). This should not usually be a concern in practice.
145 *
146 * @todo Allowing overflow by using this definition of #seq_num_delta_t is somewhat unlike the rest
147 * of the implementation of Sequence_number which avoids overflow like the plague. Should we do something
148 * like use `double` or a big-integer type from boost.multiprecision?
149 */
150 using seq_num_delta_t = int64_t;
151
152 // Constructors/destructor.
153
154 /// Constructs sequence number that is zero (not a valid sequence number; less than all others).
155 explicit Sequence_number();
156
157 /**
158 * Copy constructor. Identical to calling: `operator=(source);`.
159 *
160 * Implementation detail: Default implementation used. This is basically here for documentation purposes.
161 *
162 * @param source
163 * Source object.
164 */
166
167 // Methods.
168
169 /**
170 * Copy operator. Copies both the data (the essential absolute value) and all the metadata.
171 *
172 * Implementation detail: Default implementation used. This is basically here for documentation purposes.
173 *
174 * @param source
175 * Source object. `*this` is allowed but pointless.
176 * @return `*this`.
177 */
179
180 /**
181 * Returns true if and only if `*this != Sequence_number()` (i.e., is non-zero).
182 *
183 * @return Ditto.
184 */
185 bool valid() const;
186
187 /**
188 * Returns the distance from `*this` to `rhs`. This may be negative, meaning `rhs > *this`.
189 *
190 * @note This will overflow if the difference is extremely large (over half of the sequence number
191 * range). This should not usually be a concern in practice... but see to-do on #seq_num_delta_t.
192 * @param rhs
193 * Object to compare.
194 * @return See above.
195 */
196 seq_num_delta_t operator-(const Sequence_number& rhs) const;
197
198 /**
199 * Returns new sequence number that is `*this` advanced (or reversed) by the given distance.
200 *
201 * @param delta
202 * How much to advance (or reverse, if negative) the result.
203 * @return See above.
204 */
206
207 /**
208 * Equivalent to `operator+(-delta)`.
209 *
210 * @param delta
211 * How much to reverse (or advance, if negative) the result.
212 * @return See above.
213 */
215
216 /**
217 * Advances (or reverses) this sequence number by the given distance.
218 *
219 * @param delta
220 * How much to advance (or reverse, if negative) `*this`.
221 * @return `*this`.
222 */
224
225 /**
226 * Equivalent to: `operator+=(-delta)`.
227 *
228 * @param delta
229 * How much to reverse (or advance, if negative) *this.
230 * @return *this.
231 */
233
234 /**
235 * Whether `*this` is the same sequence number as `rhs`.
236 *
237 * @param rhs
238 * Object to compare.
239 * @return See above.
240 */
241 bool operator==(const Sequence_number& rhs) const;
242
243 /**
244 * Return `!(*this == rhs)`.
245 *
246 * @param rhs
247 * Object to compare.
248 * @return See above.
249 */
250 bool operator!=(const Sequence_number& rhs) const;
251
252 /**
253 * Whether `*this` is less than `rhs`.
254 *
255 * @param rhs
256 * Object to compare.
257 * @return See above.
258 */
259 bool operator<(const Sequence_number& rhs) const;
260
261 /**
262 * Return `rhs < *this`.
263 *
264 * @param rhs
265 * Object to compare.
266 * @return See above.
267 */
268 bool operator>(const Sequence_number& rhs) const;
269
270 /**
271 * Return `!(*this > rhs)`.
272 *
273 * @param rhs
274 * Object to compare.
275 * @return See above.
276 */
277 bool operator<=(const Sequence_number& rhs) const;
278
279 /**
280 * Return `rhs <= *this`.
281 *
282 * @param rhs
283 * Object to compare.
284 * @return See above.
285 */
286 bool operator>=(const Sequence_number& rhs) const;
287
288 /**
289 * Hash value of this Sequence_number for `unordered_*<>`.
290 *
291 * @return Ditto.
292 */
293 size_t hash() const;
294
295 /**
296 * Provides the raw sequence number. This method is primarily intended for serialization.
297 *
298 * @return The raw sequence number.
299 */
300 const seq_num_t& raw_num_ref() const;
301
302 /**
303 * Sets the raw sequence number. This method is primarily intended for deserialization.
304 *
305 * @param num
306 * The raw sequence number.
307 */
308 void set_raw_num(seq_num_t num);
309
310 /**
311 * Updates the full set of metadata (used at least for convenient convention-based logging but not actual algorihtms)
312 * for this number.
313 *
314 * See class Sequence_number doc header for important tips and even more detail before using this
315 * surprisingly powerful utility. It's all quite intuitive, but there are various nuances one might not expect.
316 *
317 * @note Metadata propagate via copy (copy construction, `operator=()`, and many implicit calls thereto), so it
318 * is important to call this method with final values before the propagating begins. See class Sequence_number
319 * doc header for discussion.
320 * @param num_line_id
321 * A 1-character descriptive identifier (conventionally, an upper-case letter such as L for Local) for
322 * the number line of which this Sequence_number is a part. `char(0)` means "none" or "unknown" and is
323 * default at construction.
324 * @param zero_point
325 * The Sequence_number `Z` such that the relative sequence number is expressed depending on
326 * `this->m_num` versus `Z.m_num`; its sign is +, -, or = if the latter is less than, greater than, or equal
327 * to the former, respectively; its magnitude is the absolute value of their difference.
328 * 0 is legal, but see class Sequence_number for nuance(s). 0 is default at construction.
329 * @param multiple_size
330 * The block size, or multiple size, which is a positive value given when data are generally expected to be
331 * segmented in whole multiples of this many contiguous Sequence_numbers. 0 means "data are not expected to
332 * be such multiples" or "unknown"; this is the default at construction.
333 */
334 void set_metadata(char num_line_id = 0,
335 const Sequence_number& zero_point = Sequence_number(),
336 seq_num_delta_t multiple_size = 0);
337
338private:
339 // Friends.
340
341 // Friend of Sequence_number: For access to our internals.
342 friend std::ostream& operator<<(std::ostream& os, const Sequence_number& seq_num);
343
344 // Data.
345
346 /// The raw sequence number. This is the only datum used in algorithms. The others are only for logging and similar.
348
349 /// Identifies the owner number line; `char(0)` = unknown/none. See set_metadata().
351
352 /// Value for `m_num` such that the magnitude is zero. See set_metadata().
354
355 /// Expected size of a full contiguous "block" of these numbers; 0 = unknown/blocks not expected. See set_metadata().
357}; // class Sequence_number
358
359/**
360 * An object of this type generates a series of initial sequence numbers (ISN) that are meant to be
361 * sufficiently secure to protect against ISN attacks and confusion among different connections
362 * between the same endpoints occurring in series.
363 *
364 * The basic use case is to construct a Generator at the beginning of a Node's operation to
365 * initialize its state and then call generate_init_seq_num() whenever an ISN is needed.
366 *
367 * ### Thread safety ###
368 * Not safe to read/write or write/write one object simultaneously.
369 */
371 public log::Log_context,
372 private boost::noncopyable
373{
374public:
375 // Constructors/destructor.
376
377 /**
378 * Constructs Generator.
379 *
380 * @param logger
381 * Logger to use subsequently.
382 */
383 explicit Generator(log::Logger* logger);
384
385 // Methods.
386
387 /**
388 * Returns an initial sequence number (ISN) for use in a new connection.
389 *
390 * @return Ditto.
391 */
393
394private:
395 // Constants.
396
397 /**
398 * The maximum allowed value for the initial sequence number (ISN) for a given Flow-protocol connection
399 * (Peer_socket). This should be high enough to allow a huge range of possible initial sequence
400 * numbers (to guard against ISN attacks, for example); but low enough to ensure that sequence
401 * numbers following the ISN within the given connection would take an extremely huge amount of
402 * time to wrap (i.e., overflow Sequence_numer::seq_num_t). If such a value is chosen, the ISN can be secure and
403 * remove the need to worry about wrapping as well.
404 */
406
407 /// The ISN given out at a given time should increment every N; this is the value of N.
409
410 /**
411 * In addition to the actual time passed between two ISN generations, pretend this much additional
412 * time has also passed.
413 */
415
416 // Data.
417
418 /// The last initial sequence number returned by generate_init_seq_num() (or zero if never called).
420
421 /// #Fine_clock time of the last invocation of generate_init_seq_num() (or default if never called).
423}; // class Sequence_number::Generator
424
425// Free functions: in *_fwd.hpp.
426
427} // 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 object of this type generates a series of initial sequence numbers (ISN) that are meant to be suff...
Definition: seq_num.hpp:373
Sequence_number generate_init_seq_num()
Returns an initial sequence number (ISN) for use in a new connection.
Definition: seq_num.cpp:48
Sequence_number m_last_init_seq_num
The last initial sequence number returned by generate_init_seq_num() (or zero if never called).
Definition: seq_num.hpp:419
static const Fine_duration S_MIN_DELAY_BETWEEN_ISN
In addition to the actual time passed between two ISN generations, pretend this much additional time ...
Definition: seq_num.hpp:414
Fine_time_pt m_last_isn_generation
Fine_clock time of the last invocation of generate_init_seq_num() (or default if never called).
Definition: seq_num.hpp:422
Generator(log::Logger *logger)
Constructs Generator.
Definition: seq_num.cpp:42
static const seq_num_t S_MAX_INIT_SEQ_NUM
The maximum allowed value for the initial sequence number (ISN) for a given Flow-protocol connection ...
Definition: seq_num.hpp:405
static const Fine_duration S_TIME_PER_SEQ_NUM
The ISN given out at a given time should increment every N; this is the value of N.
Definition: seq_num.hpp:408
An internal net_flow sequence number identifying a piece of data.
Definition: seq_num.hpp:126
seq_num_delta_t m_multiple_size
Expected size of a full contiguous "block" of these numbers; 0 = unknown/blocks not expected....
Definition: seq_num.hpp:356
friend std::ostream & operator<<(std::ostream &os, const Sequence_number &seq_num)
Prints given sequence number to given ostream.
Definition: seq_num.cpp:169
bool valid() const
Returns true if and only if *this != Sequence_number() (i.e., is non-zero).
Definition: seq_num.cpp:106
bool operator==(const Sequence_number &rhs) const
Whether *this is the same sequence number as rhs.
Definition: seq_num.cpp:139
Sequence_number operator+(seq_num_delta_t delta) const
Returns new sequence number that is *this advanced (or reversed) by the given distance.
Definition: seq_num.cpp:129
seq_num_delta_t operator-(const Sequence_number &rhs) const
Returns the distance from *this to rhs.
Definition: seq_num.cpp:111
bool operator<(const Sequence_number &rhs) const
Whether *this is less than rhs.
Definition: seq_num.cpp:149
bool operator<=(const Sequence_number &rhs) const
Return !(*this > rhs).
Definition: seq_num.cpp:164
void set_metadata(char num_line_id=0, const Sequence_number &zero_point=Sequence_number(), seq_num_delta_t multiple_size=0)
Updates the full set of metadata (used at least for convenient convention-based logging but not actua...
Definition: seq_num.cpp:268
Sequence_number & operator+=(seq_num_delta_t delta)
Advances (or reverses) this sequence number by the given distance.
Definition: seq_num.cpp:118
size_t hash() const
Hash value of this Sequence_number for unordered_*<>.
Definition: seq_num.cpp:252
void set_raw_num(seq_num_t num)
Sets the raw sequence number.
Definition: seq_num.cpp:263
Sequence_number & operator-=(seq_num_delta_t delta)
Equivalent to: operator+=(-delta).
Definition: seq_num.cpp:124
Sequence_number & operator=(const Sequence_number &source)
Copy operator.
uint64_t seq_num_t
Raw sequence number type.
Definition: seq_num.hpp:138
int64_t seq_num_delta_t
Integer type used to express differences (distances) between Sequence_numbers.
Definition: seq_num.hpp:150
const seq_num_t & raw_num_ref() const
Provides the raw sequence number.
Definition: seq_num.cpp:258
seq_num_t m_num
The raw sequence number. This is the only datum used in algorithms. The others are only for logging a...
Definition: seq_num.hpp:347
Sequence_number(const Sequence_number &source)
Copy constructor.
Sequence_number()
Constructs sequence number that is zero (not a valid sequence number; less than all others).
Definition: seq_num.cpp:96
seq_num_t m_zero_point_num
Value for m_num such that the magnitude is zero. See set_metadata().
Definition: seq_num.hpp:353
char m_num_line_id
Identifies the owner number line; char(0) = unknown/none. See set_metadata().
Definition: seq_num.hpp:350
bool operator>(const Sequence_number &rhs) const
Return rhs < *this.
Definition: seq_num.cpp:154
bool operator!=(const Sequence_number &rhs) const
Return !(*this == rhs).
Definition: seq_num.cpp:144
bool operator>=(const Sequence_number &rhs) const
Return rhs <= *this.
Definition: seq_num.cpp:159
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:411
Fine_clock::time_point Fine_time_pt
A high-res time point as returned by Fine_clock::now() and suitable for precise time math in general.
Definition: common.hpp:408