Flow 1.0.1
Flow project: Full implementation reference.
socket_stats.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
23
24namespace flow::net_flow
25{
26// Types.
27
28/**
29 * A class that keeps a Peer_socket_receive_stats data store, includes methods to conveniently
30 * accumulate data in it, and provides output to `ostream`.
31 *
32 * Any object of this class is intended to have a 1-to-1 relationship with a Peer_socket. The
33 * interface is intentionally simple; the class keeps some counters and limited auxilliary state
34 * (such as creation time); the Node informs the class of events (like "DATA packet received"),
35 * counts of which are stored in the class and are accessible through the interface (at least
36 * through the `ostream` output operator).
37 *
38 * As usual, invoke the event handler methods of the class whenever the appropriate events occur.
39 * Failing to do so will obviously result in wrong statistics.
40 *
41 * The class intentionally does not take a reference to a Peer_socket and avoids logging; it is a
42 * simple accumulating data store.
43 *
44 * ### Thread safety ###
45 * Same as any `struct` with no locking done therein.
46 *
47 * @see Peer_socket_receive_stats
48 */
50 private Peer_socket_receive_stats, // HAS-A relationship.
51 private boost::noncopyable
52{
53public:
54 // Methods.
55
56 /**
57 * Returns reference to non-modifiable current set of accumulated stats.
58 *
59 * @return Ditto.
60 */
61 const Peer_socket_receive_stats& stats() const;
62
63 /**
64 * Indicates one DATA packet has been received on socket.
65 *
66 * @param data
67 * User data size.
68 */
69 void total_data_packet(size_t data);
70
71 /**
72 * Indicates total_data_packet(), and these data are new and acceptable into Receive buffer
73 * assuming there is space.
74 *
75 * @param data
76 * User data size.
77 */
78 void good_data_packet(size_t data);
79
80 /**
81 * Indicates good_data_packet(), but these data are dropped due to insufficient Receive buffer
82 * space.
83 *
84 * @param data
85 * User data size.
86 */
88
89 /**
90 * Indicates good_data_packet(), but these data are dropped due to insufficient Receive reassembly
91 * queue space (only possible when retransmission is enabled).
92 *
93 * @param data
94 * User data size.
95 */
97
98 /**
99 * Indicates good_data_packet(), and these data are not dropped (so either delivered into Receive
100 * buffer or queued for reassembly later).
101 *
102 * @param data
103 * User data size.
104 */
105 void good_data_accepted_packet(size_t data);
106
107 /**
108 * Indicates good_data_accepted_packet(), and these data are delivered into Receive buffer (either
109 * immediately upon receipt or upon later reassembly).
110 *
111 * @param data
112 * User data size.
113 */
114 void good_data_delivered_packet(size_t data);
115
116 /**
117 * Indicates good_data_accepted_packet(), and these data are, upon receipt, queued for reassembly
118 * (not immediately delivered into Receive buffer).
119 *
120 * @param data
121 * User data size.
122 */
123 void good_data_first_qd_packet(size_t data);
124
125 /**
126 * Indicates total_data_packet(), but the arrived data have either already been received before or
127 * (more likely) have been considered Dropped by now; therefore data not delivered to Receive
128 * buffer.
129 *
130 * @param data
131 * User data size.
132 */
133 void late_or_dupe_data_packet(size_t data);
134
135 /**
136 * Indicates total_data_packet(), but there is some error about the sequence numbers so that they
137 * are not acceptable, and the connection did/will close as a result.
138 *
139 * @param data
140 * User data size.
141 */
142 void error_data_packet(size_t data);
143
144 /**
145 * Indicates that one or more unreceived data packets have been considered Dropped due to the
146 * number of later packets that have been received. For each such packet that does arrive in the
147 * future (though unlikely), late_or_dupe_data_packet() will be called.
148 *
149 * @param data
150 * User data size.
151 */
152 void presumed_dropped_data(size_t data);
153
154 /**
155 * Indicates that an individual acknowledgment for one packet will be sent.
156 * @param data
157 * User data size.
158 */
159 void total_to_send_ack_packet(size_t data);
160
161 /**
162 * Indicates that good_data_delivered_packet() and therefore an individual acknowledgment for this
163 * packet will be sent. Note that good_data_packet() alone does not necessarily mean that an
164 * acknowledgment will be sent in response (namely if we have to drop the packet due to insufficient
165 * buffer space).
166 *
167 * @param data
168 * User data size.
169 */
170 void good_to_send_ack_packet(size_t data);
171
172 /**
173 * Indicates that late_or_dupe_data_packet() and therefore an individual acknowledgment for this
174 * packet will be sent.
175 * @param data
176 * User data size.
177 */
178 void late_or_dupe_to_send_ack_packet(size_t data);
179
180 /**
181 * Indicates that all incoming data in the current boost.asio handler have been scanned and any
182 * ACKs that may be sent in this handler have been sent, and that immediately after that fact, the
183 * number of individual acknowledgments (NOTE: not ACK packets but individual acknowledgments
184 * therein) is as given in the `count` argument. Note that unlike most methods in this class, this
185 * indicates the current state as opposed to an event. Internally this is necessary to maintain a
186 * total count of individual acks that have ever been delayed (without double-counting).
187 *
188 * The current mechanism is that, in a given boost.asio low-level receive handler, we will either flush all
189 * the acks that have built up over the last N (where N >= 1, including the current one) handlers, or we
190 * will queue up 0 or more to send in a later handler. (We do not add some more + flush some but not all,
191 * nor do we just flush some but not all.) Thus, in the 2 cases just described, we'd call this
192 * method with count = 0 or some value >= the value from the last time, respectively.
193 *
194 * @param count
195 * Number of packets. This should be either zero or >= the last value passed into
196 * the same call for this object. Otherwise assertion trips.
197 */
198 void current_pending_to_ack_packets(size_t count);
199
200 /**
201 * Indicates than one individual acknowledgment of a data packet has been packaged into an ACK
202 * packet that will be sent as soon as possible.
203 */
204 void sent_individual_ack();
205
206 /**
207 * Indicates than one low-level ACK packet will be sent as soon as possible.
208 *
209 * @param rcv_wnd_update_only
210 * `true` if and only if this ACK contains no individual acknowledgments; i.e., it is sent
211 * only with the purpose of advertising rcv_wnd.
212 */
213 void sent_low_lvl_ack_packet(bool rcv_wnd_update_only);
214
215 /**
216 * Indicates we seem to have detected that our rcv_wnd went from exhaustion to largely free, and
217 * therefore we will now inform the sender of this, so that it can resume sending data.
218 */
220
221 /**
222 * Indicates that the recovery indicated by last rcv_wnd_recovery_event_start() call has
223 * finished (we are no longer ACKing sender to advertise receive window).
224 *
225 * @param success
226 * `true` if recovery successful (sender has sent more DATA packets); `false` if recovery
227 * failed (we stopped due to exceeding long timeout).
228 */
229 void rcv_wnd_recovery_event_finish(bool success);
230
231 /**
232 * Indicates the Receive buffer was enqueued with data from network (so its `data_size()`
233 * increased).
234 *
235 * @param size
236 * The # of bytes in the buffer after the enqueueing.
237 */
238 void buffer_fed(size_t size);
239
240 /**
241 * Indicates a `Low_lvl_packet& p` was received with `typeid(p) == type`,
242 * deserialized from a buffer of length `size` bytes, targeted at the associated socket.
243 *
244 * Caveat: Some packets may not be targeted at any particular socket; probably malformed.
245 * They would not be counted here.
246 *
247 * Caveat: SYN counts; but note that the Peer_socket with which this call is associated would need
248 * to first be created before making the call.
249 *
250 * @param type
251 * `typeid(p)`, where p refers to an instance of a concrete Low_lvl_packet sub-type.
252 * @param size
253 * Datagram contents' size.
254 */
255 void low_lvl_packet(const std::type_info& type, size_t size);
256}; // class Peer_socket_receive_stats_accumulator
257
258/**
259 * A class that keeps a Peer_socket_send_stats data store, includes methods to conveniently
260 * accumulate data in it, and provides output to `ostream`.
261 *
262 * All other comments in Peer_socket_receive_stats_accumulator doc header apply equally to this
263 * class.
264 *
265 * @see Peer_socket_receive_stats_accumulator
266 * @see Peer_socket_send_stats
267 */
269 private Peer_socket_send_stats, // HAS-A relationship.
270 private boost::noncopyable
271{
272public:
273 // Methods.
274
275 /**
276 * Returns reference to non-modifiable current set of accumulated stats.
277 *
278 * @return Ditto.
279 */
280 const Peer_socket_send_stats& stats() const;
281
282 /**
283 * Indicates a DATA packet was sent.
284 *
285 * @param data
286 * User data size.
287 * @param rexmission
288 * `true` if it is a retransmission (`rexmit_id > 0`), `false` otherwise.
289 */
290 void data_sent(size_t data, bool rexmission);
291
292 /**
293 * Indicates that 1 or more packets have been converted from In-flight to Dropped.
294 *
295 * @param data
296 * User data size.
297 * @param count
298 * Packet count.
299 */
300 void dropped_data(size_t data, size_t count);
301
302 /**
303 * Indicates an ACK packet on this socket was received.
304 *
305 * @param rcv_wnd_update_only
306 * `true` if and only if the ACK contained no individual acks (rcv_wnd update only).
307 */
308 void received_low_lvl_ack_packet(bool rcv_wnd_update_only);
309
310 /**
311 * Indicates an ACK packet has advertised a rcv_wnd and whether this rcv_wnd would allow one to
312 * send one full-sized packet assuming no other barriers (availability of data to send, congestion
313 * control). In other words indicates whether the other side's Receive buffer is about full to
314 * the best of our knowledge.
315 *
316 * @param wnd_exhausted
317 * `true` if a packet would not be sent due to rcv_wnd; `false` otherwise.
318 */
319 void updated_rcv_wnd(bool wnd_exhausted);
320
321 /**
322 * Indicates one individual acknowledgment (of a DATA packet) inside an ACK has been received.
323 * (This ack is not necessarily valid.)
324 */
325 void received_ack();
326
327 /**
328 * Indicates received_ack(), and the arrived acknowledgment properly acknowledged a DATA packet,
329 * converting it from In-flight to Acknowledged.
330 *
331 * @param data
332 * User data size.
333 */
334 void good_ack(size_t data);
335
336 /**
337 * Indicates received_ack(), but the arrived acknowledgment is for a packet that has either
338 * already been convered from In-flight to Acknowledged or (more likely) already been converted
339 * from In-flight to Dropped.
340 */
341 void late_or_dupe_ack();
342
343 /**
344 * Indicates received_ack(), but there is some error about the sequence number so that it is not
345 * acceptable, and the connection did/will close as a result.
346 */
347 void error_ack();
348
349 /**
350 * Indicates a new loss event (not counting Drop Timeouts) has been reported to congestion control
351 * (Congestion_control_strategy::on_loss_event()). (Note again that multiple individual
352 * acknowledgments, and even multiple ACKs, can belong to one loss event and would only be counted
353 * once in thise case.)
354 */
355 void loss_event();
356
357 /// Indicates a Drop Timer fired once.
358 void drop_timeout();
359
360 /**
361 * Indicates an idle timeout (in the send direction) has been detected and indicated to congestion
362 * control module.
363 */
364 void idle_timeout();
365
366 /**
367 * Indicates the Send buffer was enqueued with data from a user `send*()` call (so its `data_size()`
368 * increased).
369 *
370 * @param size
371 * The # of bytes in the buffer after the enqueueing.
372 */
373 void buffer_fed(size_t size);
374
375 /**
376 * Indicates a packet was given to the sending module to send, possibly subject to pacing.
377 * We guess its serialized size is not yet known, because it has not been serialized yet.
378 *
379 * @todo It may make sense to serialize a packet as early as possible, so that the size is known at
380 * the stage of Peer_socket_send_stats_accumulator::low_lvl_packet_xfer_requested() call.
381 * Possibly knowing the serialized size this early can help the pacing module make smarter decisions.
382 *
383 * @param type
384 * `typeid(p)`, where p refers to an instance of a concrete Low_lvl_packet sub-type.
385 */
386 void low_lvl_packet_xfer_requested(const std::type_info& type);
387
388 /**
389 * Indicates low_lvl_packet_xfer_requested(), and that packet has now been given to OS UDP stack to actually send.
390 *
391 * @param type
392 * See low_lvl_packet_xfer_requested().
393 * @param delayed_by_pacing
394 * `true` if and only if there was a pacing-related delay since low_lvl_packet_xfer_requested()
395 * before this call.
396 * @param size
397 * Serialized size of the packet being sent.
398 */
399 void low_lvl_packet_xfer_called(const std::type_info& type, bool delayed_by_pacing, size_t size);
400
401 /**
402 * Indicates low_lvl_packet_xfer_called(), and that send operation has now reported its outcome by calling handler
403 * (or synchronously returning the result).
404 *
405 * @param type
406 * See low_lvl_packet_xfer_called().
407 * @param size_expected
408 * See low_lvl_packet_xfer_called().
409 * @param size_xferred
410 * Size reported as actually sent by OS. Use the default value to indicate OS indicated error (no bytes
411 * sent).
412 */
413 void low_lvl_packet_xfer_completed(const std::type_info& type,
414 size_t size_expected = std::numeric_limits<size_t>::max(),
415 size_t size_xferred = 0);
416}; // class Peer_socket_send_stats_accumulator
417
418} // namespace flow::net_flow
A class that keeps a Peer_socket_receive_stats data store, includes methods to conveniently accumulat...
void sent_low_lvl_ack_packet(bool rcv_wnd_update_only)
Indicates than one low-level ACK packet will be sent as soon as possible.
void good_data_accepted_packet(size_t data)
Indicates good_data_packet(), and these data are not dropped (so either delivered into Receive buffer...
void current_pending_to_ack_packets(size_t count)
Indicates that all incoming data in the current boost.asio handler have been scanned and any ACKs tha...
void good_data_dropped_reassembly_q_overflow_packet(size_t data)
Indicates good_data_packet(), but these data are dropped due to insufficient Receive reassembly queue...
void presumed_dropped_data(size_t data)
Indicates that one or more unreceived data packets have been considered Dropped due to the number of ...
void low_lvl_packet(const std::type_info &type, size_t size)
Indicates a Low_lvl_packet& p was received with typeid(p) == type, deserialized from a buffer of leng...
void good_data_delivered_packet(size_t data)
Indicates good_data_accepted_packet(), and these data are delivered into Receive buffer (either immed...
void late_or_dupe_to_send_ack_packet(size_t data)
Indicates that late_or_dupe_data_packet() and therefore an individual acknowledgment for this packet ...
void total_to_send_ack_packet(size_t data)
Indicates that an individual acknowledgment for one packet will be sent.
void total_data_packet(size_t data)
Indicates one DATA packet has been received on socket.
void rcv_wnd_recovery_event_finish(bool success)
Indicates that the recovery indicated by last rcv_wnd_recovery_event_start() call has finished (we ar...
void good_to_send_ack_packet(size_t data)
Indicates that good_data_delivered_packet() and therefore an individual acknowledgment for this packe...
void good_data_packet(size_t data)
Indicates total_data_packet(), and these data are new and acceptable into Receive buffer assuming the...
void sent_individual_ack()
Indicates than one individual acknowledgment of a data packet has been packaged into an ACK packet th...
void error_data_packet(size_t data)
Indicates total_data_packet(), but there is some error about the sequence numbers so that they are no...
const Peer_socket_receive_stats & stats() const
Returns reference to non-modifiable current set of accumulated stats.
void buffer_fed(size_t size)
Indicates the Receive buffer was enqueued with data from network (so its data_size() increased).
void good_data_first_qd_packet(size_t data)
Indicates good_data_accepted_packet(), and these data are, upon receipt, queued for reassembly (not i...
void good_data_dropped_buf_overflow_packet(size_t data)
Indicates good_data_packet(), but these data are dropped due to insufficient Receive buffer space.
void rcv_wnd_recovery_event_start()
Indicates we seem to have detected that our rcv_wnd went from exhaustion to largely free,...
void late_or_dupe_data_packet(size_t data)
Indicates total_data_packet(), but the arrived data have either already been received before or (more...
A class that keeps a Peer_socket_send_stats data store, includes methods to conveniently accumulate d...
void received_low_lvl_ack_packet(bool rcv_wnd_update_only)
Indicates an ACK packet on this socket was received.
void idle_timeout()
Indicates an idle timeout (in the send direction) has been detected and indicated to congestion contr...
void drop_timeout()
Indicates a Drop Timer fired once.
void low_lvl_packet_xfer_completed(const std::type_info &type, size_t size_expected=std::numeric_limits< size_t >::max(), size_t size_xferred=0)
Indicates low_lvl_packet_xfer_called(), and that send operation has now reported its outcome by calli...
void error_ack()
Indicates received_ack(), but there is some error about the sequence number so that it is not accepta...
void buffer_fed(size_t size)
Indicates the Send buffer was enqueued with data from a user send*() call (so its data_size() increas...
void updated_rcv_wnd(bool wnd_exhausted)
Indicates an ACK packet has advertised a rcv_wnd and whether this rcv_wnd would allow one to send one...
void received_ack()
Indicates one individual acknowledgment (of a DATA packet) inside an ACK has been received.
void low_lvl_packet_xfer_called(const std::type_info &type, bool delayed_by_pacing, size_t size)
Indicates low_lvl_packet_xfer_requested(), and that packet has now been given to OS UDP stack to actu...
void loss_event()
Indicates a new loss event (not counting Drop Timeouts) has been reported to congestion control (Cong...
void dropped_data(size_t data, size_t count)
Indicates that 1 or more packets have been converted from In-flight to Dropped.
void low_lvl_packet_xfer_requested(const std::type_info &type)
Indicates a packet was given to the sending module to send, possibly subject to pacing.
const Peer_socket_send_stats & stats() const
Returns reference to non-modifiable current set of accumulated stats.
void late_or_dupe_ack()
Indicates received_ack(), but the arrived acknowledgment is for a packet that has either already been...
void data_sent(size_t data, bool rexmission)
Indicates a DATA packet was sent.
void good_ack(size_t data)
Indicates received_ack(), and the arrived acknowledgment properly acknowledged a DATA packet,...
A data store that keeps stats about the outgoing direction of a Peer_socket connection to another Flo...
Definition: info.hpp:286
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
A data store that keeps stats about the incoming direction of a Peer_socket connection to another Flo...
Definition: info.hpp:54