Flow 1.0.0
Flow project: Full implementation reference.
seq_num.cpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
20#include "flow/util/random.hpp"
21#include <boost/functional/hash/hash.hpp>
22#include <limits>
23#include <cmath>
24
25namespace flow::net_flow
26{
27
28// Static initializations.
29
30/* Pick max ISN to be in the first half of the numeric range of sequence numbers (NOTE: not
31 * half the bits, but half the numeric range); i.e., about (2^64) / 2. This is a huge range of
32 * possible ISN, and if the ISN = <this value>, then at gigabit speeds and 1 sequence number per
33 * byte it would take many centuries for the sequence numbers to overflow seq_num_t. */
35 = std::numeric_limits<seq_num_t>::max() / 2;
36const Fine_duration Sequence_number::Generator::S_TIME_PER_SEQ_NUM = boost::chrono::microseconds(4); // From RFC 793.
38 = boost::chrono::milliseconds(500); // From TCP/IP Illustrated Vol. 2: The Implementation (BSD Net/3).
39
40// Implementations.
41
43 log::Log_context(logger_ptr, Flow_log_component::S_NET_FLOW)
44{
45 // Nothing.
46}
47
49{
50 using std::abs;
52
53 const Fine_time_pt& now = Fine_clock::now();
54
55 if (m_last_init_seq_num.m_num == 0)
56 {
57 /* First call to this. Just pick a random-ish ISN from the entire allowed range. Seed on current time.
58 * We only generate one random number ever (for this `this`), so it's fine to just seed it here and use once.
59 * @todo Could use a `static` data member RNG. Good randomness across multiple `this`s isn't required, so the
60 * various considerations this would introduce -- multi-threadedness, for instance -- might be too much to worry
61 * about given our modest, non-cryptographic needs here. */
62
63 Rnd_gen_uniform_range<seq_num_t> rnd_single_use(1, S_MAX_INIT_SEQ_NUM); // 0 is a reserved number; do not use.
64 m_last_init_seq_num.m_num = rnd_single_use();
65 }
66 else
67 {
68 // All subsequent calls.
69
70 /* For now basically follow RFC 793 (original TCP spec): new sequence number every N
71 * microseconds, with N defined by the RFC. Additionally, add a large constant M, as if another
72 * 0.5 seconds had passed (as BSD did at least in 1995, as documented in TCP/IP Illustrated:
73 * Vol. 2). abs() should not be necessary with Fine_clock, but just in case.... */
74
75 m_last_init_seq_num.m_num +=
76 seq_num_t((now - m_last_isn_generation + S_MIN_DELAY_BETWEEN_ISN) / S_TIME_PER_SEQ_NUM);
77
78 /* It's incredibly unlikely that overflowed seq_num_t given the times involved, but even if it
79 * did, so be it. In that case pretty much any random ISN is still OK. So just assume no
80 * overflow.... */
81
82 // Wrap ISN if needed. (It's perfectly possible, e.g., if original ISN was right near the end of allowed range.)
83 if (m_last_init_seq_num.m_num > S_MAX_INIT_SEQ_NUM)
84 {
85 // 0 is a reserved number; do not use.
86 m_last_init_seq_num.m_num = m_last_init_seq_num.m_num - S_MAX_INIT_SEQ_NUM;
87 }
88 }
89
90 FLOW_LOG_TRACE("Generated ISN [" << m_last_init_seq_num << "].");
91
92 m_last_isn_generation = now;
93 return m_last_init_seq_num;
94} // Sequence_number::Generator::generate_init_seq_num()
95
98{
99 // Nothing.
100}
101
103
105
107{
108 return m_num != 0;
109}
110
112{
113 /* This can technically overflow (since seq_num_delta_t is a signed int64_t, while the raw #s are
114 * unsigned). This is advertised in the method comment and should not usually be a concern. */
115 return seq_num_delta_t(m_num - rhs.m_num);
116}
117
119{
120 m_num += delta; // Can be negative.
121 return *this;
122}
123
125{
126 return operator+=(-delta);
127}
128
130{
131 return Sequence_number(*this) += delta;
132}
133
135{
136 return operator+(-delta);
137}
138
140{
141 return m_num == rhs.m_num;
142}
143
145{
146 return !(*this == rhs);
147}
148
150{
151 return m_num < rhs.m_num;
152}
153
155{
156 return rhs < *this;
157}
158
160{
161 return !(*this < rhs);
162}
163
165{
166 return rhs >= *this;
167}
168
169std::ostream& operator<<(std::ostream& os, const Sequence_number& seq_num)
170{
171 // First the number line ID if any; 0 means unknown so just omit it.
172 if (seq_num.m_num_line_id != 0)
173 {
174 os << seq_num.m_num_line_id;
175 }
176
177 const bool use_multiple = seq_num.m_multiple_size != 0; // Multiples (segmentation) is in use.
178 const bool non_zero_offset = seq_num.m_zero_point_num != 0; // Magnitude is non-zero.
179
180 /* First assume the magnitude is non-zero. Then we show the sign, - or +. However, if the zero point is itself 0
181 * then any non-zero magnitude is positive; so simply omit the sign. Next, show the magnitude (m_num offset by
182 * m_zero_point). If `use_multiple`, then much as we omitted the zero point value itself and just showed the sign
183 * in its place, show the 'x' multiplication sign here; then show the multiple count, then "%R"; where R is the
184 * remainder beyond the multiples, omitted if R = 0. Finally, if `use_multiple`, then simply show the magnitude
185 * (can think it of it as a multiple of 1, for which R = 0 always, and the 'x' is omitted). Examples:
186 * -x3 (3B to left of zero), +x2%5 (2B+5 to right of zero), x454324123 (454324123B absolute),
187 * 454324123123 (454324123 absolute).
188 *
189 * Finally, what if magnitude IS zero? For convenience to help interpret other numbers on the same line we use
190 * this opportunity to print out the metadata set; and a simple indication that THIS value has magnitude 0.
191 * Think of the format as a non-zero-magnitude value, with the "implied" (omitted) values in the previous paragraph
192 * explicitly written out. So, first is the sign, written as the zero point followed by the sign.
193 * Next is the multiple, as the multiple followed by 'x'. The coup de grace, is, simply '0', since that's what this
194 * value is. Finally, each of the two segments mentioned is omitted in the degenerate cases (zero point = 0,
195 * no multiple used). Examples: 0 (!use_multiple, !non_zero_offset), 342342342+1024x0 (use_multiple, non_zero_offset),
196 * 342342342+0 (!use_multiple, !non_zero_offset).
197 *
198 * The above is hair/formal, but try to correlate the examples in the 2 paragraphs to see how the practical output
199 * makes some sense. */
200
201 Sequence_number::seq_num_t magnitude = seq_num.m_num;
202 if (magnitude == seq_num.m_zero_point_num)
203 {
204 // No sign => show reference values and the constant 0.
205 if (non_zero_offset)
206 {
207 os << seq_num.m_zero_point_num << '+';
208 }
209 if (use_multiple)
210 {
211 os << seq_num.m_multiple_size << 'x';
212 }
213 os << '0';
214 }
215 else
216 {
217 // Yes sign => show NO reference values; show the offset vs. zero pt., possibly as a count of multiples + remainder.
218 if (non_zero_offset)
219 {
220 // (Subtlety: avoid any underflow situation by only performing (A - B) when A > B.)
221 if (magnitude > seq_num.m_zero_point_num)
222 {
223 os << '+';
224 magnitude -= seq_num.m_zero_point_num;
225 }
226 else
227 {
228 assert(magnitude < seq_num.m_zero_point_num);
229 os << '-';
230 magnitude = seq_num.m_zero_point_num - magnitude;
231 }
232 }
233
234 if (use_multiple)
235 {
236 os << 'x' << (magnitude / seq_num.m_multiple_size);
237 const auto rem = magnitude % seq_num.m_multiple_size;
238 if (rem != 0)
239 {
240 os << '%' << rem;
241 }
242 }
243 else
244 {
245 os << magnitude;
246 }
247 }
248
249 return os;
250}
251
253{
254 using boost::hash_value;
255 return hash_value(m_num);
256}
257
259{
260 return m_num;
261}
262
264{
265 m_num = num;
266}
267
268void Sequence_number::set_metadata(char num_line_id, const Sequence_number& zero_point, seq_num_delta_t multiple_size)
269{
270 m_num_line_id = num_line_id;
271 m_zero_point_num = zero_point.m_num;
272 m_multiple_size = multiple_size;
273}
274
275size_t hash_value(const Sequence_number& seq_num)
276{
277 return seq_num.hash();
278}
279
280} // namespace flow::net_flow
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1291
Sequence_number generate_init_seq_num()
Returns an initial sequence number (ISN) for use in a new connection.
Definition: seq_num.cpp:48
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
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
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_value(const Sequence_number &seq_num)
Free function that returns seq_num.hash(); has to be a free function named hash_value for boost....
Definition: seq_num.cpp:275
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()
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
Simple, non-thread-safe uniform-range random number generator.
Definition: random.hpp:104
#define FLOW_LOG_TRACE(ARG_stream_fragment)
Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:227
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
size_t hash_value(const Sequence_number &seq_num)
Free function that returns seq_num.hash(); has to be a free function named hash_value for boost....
Definition: seq_num.cpp:275
std::ostream & operator<<(std::ostream &os, const Congestion_control_selector::Strategy_choice &strategy_choice)
Serializes a Peer_socket_options::Congestion_control_strategy_choice enum to a standard ostream – the...
Definition: cong_ctl.cpp:146
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Definition: common.hpp:632
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:410
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:407