1 //====== Copyright Valve Corporation, All rights reserved. ====================
2 //
3 // Some public types for communicating detailed connection stats
4 //
5 //=============================================================================
6 
7 #ifndef STEAMNETWORKING_STATS_H
8 #define STEAMNETWORKING_STATS_H
9 #ifdef _WIN32
10 #pragma once
11 #endif
12 
13 #include <steam/steamnetworkingtypes.h>
14 #include "steamnetworkingsockets_internal.h"
15 
16 #pragma pack(push)
17 #pragma pack(8)
18 
19 namespace SteamNetworkingSocketsLib {
20 
21 struct SteamDatagramLinkStats;
22 struct SteamDatagramLinkLifetimeStats;
23 struct SteamDatagramLinkInstantaneousStats;
24 struct SteamNetworkingDetailedConnectionStatus;
25 
26 /// Instantaneous statistics for a link between two hosts.
27 struct SteamDatagramLinkInstantaneousStats
28 {
29 
30 	/// Data rates
31 	float m_flOutPacketsPerSec;
32 	float m_flOutBytesPerSec;
33 	float m_flInPacketsPerSec;
34 	float m_flInBytesPerSec;
35 
36 	/// Smoothed ping.  This will be -1 if we don't have any idea!
37 	int m_nPingMS;
38 
39 	/// 0...1, estimated number of packets that were sent to us, but we failed to receive.
40 	/// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this.
41 	float m_flPacketsDroppedPct;
42 
43 	/// Packets received with a sequence number abnormality, other than basic packet loss.  (Duplicated, out of order, lurch.)
44 	/// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this.
45 	float m_flPacketsWeirdSequenceNumberPct;
46 
47 	/// Peak jitter
48 	int m_usecMaxJitter;
49 
50 	/// Current sending rate, this can be low at connection start until the slow start
51 	/// ramps it up.  It's adjusted as packets are lost and congestion is encountered during
52 	/// the connection
53 	int m_nSendRate;
54 
55 	/// How many pending bytes are waiting to be sent.  This is data that is currently waiting
56 	/// to be sent and in outgoing buffers.  If this is zero, then the connection is idle
57 	/// and all pending data has been sent.  Note that in case of packet loss any pending
58 	/// reliable data might be re-sent.  This does not include data that has been sent and is
59 	/// waiting for acknowledgment.
60 	int m_nPendingBytes;
61 
62 	/// Reset all values to zero / unknown status
63 	void Clear();
64 };
65 
66 /// Counts of ping times by bucket
67 struct PingHistogram
68 {
69 	int m_n25, m_n50, m_n75, m_n100, m_n125, m_n150, m_n200, m_n300, m_nMax;
70 
ResetPingHistogram71 	void Reset() { memset( this, 0, sizeof(*this) ); }
72 
AddSamplePingHistogram73 	void AddSample( int nPingMS )
74 	{
75 
76 		// Update histogram using hand-rolled sort-of-binary-search, optimized
77 		// for the expectation that most pings will be reasonable
78 		if ( nPingMS <= 100 )
79 		{
80 			if ( nPingMS <= 50 )
81 			{
82 				if ( nPingMS <= 25 )
83 					++m_n25;
84 				else
85 					++m_n50;
86 			}
87 			else
88 			{
89 				if ( nPingMS <= 75 )
90 					++m_n75;
91 				else
92 					++m_n100;
93 			}
94 		}
95 		else
96 		{
97 			if ( nPingMS <= 150 )
98 			{
99 				if ( nPingMS <= 125 )
100 					++m_n125;
101 				else
102 					++m_n150;
103 			}
104 			else
105 			{
106 				if ( nPingMS <= 200 )
107 					++m_n200;
108 				else if ( nPingMS <= 300 )
109 					++m_n300;
110 				else
111 					++m_nMax;
112 			}
113 		}
114 	}
115 
TotalCountPingHistogram116 	inline int TotalCount() const
117 	{
118 		return m_n25 + m_n50 + m_n75 + m_n100 + m_n125 + m_n150 + m_n200 + m_n300 + m_nMax;
119 	}
120 };
121 
122 /// Count of quality measurement intervals by bucket
123 struct QualityHistogram
124 {
125 	int m_n100, m_n99, m_n97, m_n95, m_n90, m_n75, m_n50, m_n1, m_nDead;
126 
ResetQualityHistogram127 	void Reset() { memset( this, 0, sizeof(*this) ); }
128 
TotalCountQualityHistogram129 	inline int TotalCount() const
130 	{
131 		return m_n100 + m_n99 + m_n97 + m_n95 + m_n90 + m_n75 + m_n50 + m_n1 + m_nDead;
132 	}
133 };
134 
135 /// Counts of jitter values by bucket
136 struct JitterHistogram
137 {
ResetJitterHistogram138 	void Reset() { memset( this, 0, sizeof(*this) ); }
139 
140 	int m_nNegligible; // <1ms
141 	int m_n1; // 1--2ms
142 	int m_n2; // 2--5ms
143 	int m_n5; // 5--10ms
144 	int m_n10; // 10--20ms
145 	int m_n20; // 20ms or more
146 
AddSampleJitterHistogram147 	void AddSample( SteamNetworkingMicroseconds usecJitter )
148 	{
149 
150 		// Add to histogram
151 		if ( usecJitter < 1000 )
152 			++m_nNegligible;
153 		else if ( usecJitter < 2000 )
154 			++m_n1;
155 		else if ( usecJitter < 5000 )
156 			++m_n2;
157 		else if ( usecJitter < 10000 )
158 			++m_n5;
159 		else if ( usecJitter < 20000 )
160 			++m_n10;
161 		else
162 			++m_n20;
163 	}
164 
TotalCountJitterHistogram165 	inline int TotalCount() const
166 	{
167 		return m_nNegligible + m_n1 + m_n2 + m_n5 + m_n10 + m_n20;
168 	}
169 };
170 
171 /// Stats for the lifetime of a connection.
172 /// Should match CMsgSteamDatagramLinkLifetimeStats
173 struct SteamDatagramLinkLifetimeStats
174 {
175 	/// Reset all values to zero / unknown status
176 	void Clear();
177 
178 	int m_nConnectedSeconds; // -1 if we don't track it
179 
180 	//
181 	// Lifetime counters.
182 	// NOTE: Average packet loss, etc can be deduced from this.
183 	//
184 	int64 m_nPacketsSent;
185 	int64 m_nBytesSent;
186 	int64 m_nPacketsRecv; // total number of packets received, some of which might not have had a sequence number.  Don't use this number to try to estimate lifetime packet loss, use m_nPacketsRecvSequenced
187 	int64 m_nBytesRecv;
188 	int64 m_nPktsRecvSequenced; // packets that we received that had a sequence number.
189 	int64 m_nPktsRecvDropped;
190 	int64 m_nPktsRecvOutOfOrder;
191 	int64 m_nPktsRecvDuplicate;
192 	int64 m_nPktsRecvSequenceNumberLurch;
193 
194 	// SNP message counters
195 	int64 m_nMessagesSentReliable;
196 	int64 m_nMessagesSentUnreliable;
197 	int64 m_nMessagesRecvReliable;
198 	int64 m_nMessagesRecvUnreliable;
199 
200 	// Ping distribution
201 	PingHistogram m_pingHistogram;
202 
203 	// Distribution.
204 	// NOTE: Some of these might be -1 if we didn't have enough data to make a meaningful estimate!
205 	// It takes fewer samples to make an estimate of the median than the 98th percentile!
206 	short m_nPingNtile5th; // 5% of ping samples were <= Nms
207 	short m_nPingNtile50th; // 50% of ping samples were <= Nms
208 	short m_nPingNtile75th; // 70% of ping samples were <= Nms
209 	short m_nPingNtile95th; // 95% of ping samples were <= Nms
210 	short m_nPingNtile98th; // 98% of ping samples were <= Nms
211 	short m__pad1;
212 
213 
214 	//
215 	// Connection quality distribution
216 	//
217 	QualityHistogram m_qualityHistogram;
218 
219 	// Distribution.  Some might be -1, see above for why.
220 	short m_nQualityNtile2nd; // 2% of measurement intervals had quality <= N%
221 	short m_nQualityNtile5th; // 5% of measurement intervals had quality <= N%
222 	short m_nQualityNtile25th; // 25% of measurement intervals had quality <= N%
223 	short m_nQualityNtile50th; // 50% of measurement intervals had quality <= N%
224 
225 	// Jitter histogram
226 	JitterHistogram m_jitterHistogram;
227 
228 	//
229 	// Connection transmit speed histogram
230 	//
231 	int m_nTXSpeedMax; // Max speed we hit
232 
233 	int m_nTXSpeedHistogram16; // Speed at kb/s
234 	int m_nTXSpeedHistogram32;
235 	int m_nTXSpeedHistogram64;
236 	int m_nTXSpeedHistogram128;
237 	int m_nTXSpeedHistogram256;
238 	int m_nTXSpeedHistogram512;
239 	int m_nTXSpeedHistogram1024;
240 	int m_nTXSpeedHistogramMax;
TXSpeedHistogramTotalCountSteamDatagramLinkLifetimeStats241 	inline int TXSpeedHistogramTotalCount() const
242 	{
243 		return m_nTXSpeedHistogram16
244 			+ m_nTXSpeedHistogram32
245 			+ m_nTXSpeedHistogram64
246 			+ m_nTXSpeedHistogram128
247 			+ m_nTXSpeedHistogram256
248 			+ m_nTXSpeedHistogram512
249 			+ m_nTXSpeedHistogram1024
250 			+ m_nTXSpeedHistogramMax;
251 	}
252 
253 	// Distribution.  Some might be -1, see above for why.
254 	int m_nTXSpeedNtile5th; // 5% of transmit samples were <= N kb/s
255 	int m_nTXSpeedNtile50th; // 50% of transmit samples were <= N kb/s
256 	int m_nTXSpeedNtile75th; // 75% of transmit samples were <= N kb/s
257 	int m_nTXSpeedNtile95th; // 95% of transmit samples were <= N kb/s
258 	int m_nTXSpeedNtile98th; // 98% of transmit samples were <= N kb/s
259 
260 	//
261 	// Connection receive speed histogram
262 	//
263 	int m_nRXSpeedMax; // Max speed we hit that formed the histogram
264 
265 	int m_nRXSpeedHistogram16; // Speed at kb/s
266 	int m_nRXSpeedHistogram32;
267 	int m_nRXSpeedHistogram64;
268 	int m_nRXSpeedHistogram128;
269 	int m_nRXSpeedHistogram256;
270 	int m_nRXSpeedHistogram512;
271 	int m_nRXSpeedHistogram1024;
272 	int m_nRXSpeedHistogramMax;
RXSpeedHistogramTotalCountSteamDatagramLinkLifetimeStats273 	inline int RXSpeedHistogramTotalCount() const
274 	{
275 		return m_nRXSpeedHistogram16
276 			+ m_nRXSpeedHistogram32
277 			+ m_nRXSpeedHistogram64
278 			+ m_nRXSpeedHistogram128
279 			+ m_nRXSpeedHistogram256
280 			+ m_nRXSpeedHistogram512
281 			+ m_nRXSpeedHistogram1024
282 			+ m_nRXSpeedHistogramMax;
283 	}
284 
285 	// Distribution.  Some might be -1, see above for why.
286 	int m_nRXSpeedNtile5th; // 5% of transmit samples were <= N kb/s
287 	int m_nRXSpeedNtile50th; // 50% of transmit samples were <= N kb/s
288 	int m_nRXSpeedNtile75th; // 75% of transmit samples were <= N kb/s
289 	int m_nRXSpeedNtile95th; // 95% of transmit samples were <= N kb/s
290 	int m_nRXSpeedNtile98th; // 98% of transmit samples were <= N kb/s
291 
292 };
293 
294 /// Link stats.  Pretty much everything you might possibly want to know about the connection
295 struct SteamDatagramLinkStats
296 {
297 
298 	/// Latest instantaneous stats, calculated locally
299 	SteamDatagramLinkInstantaneousStats m_latest;
300 
301 	/// Peak values for each instantaneous stat
302 	//SteamDatagramLinkInstantaneousStats m_peak;
303 
304 	/// Lifetime stats, calculated locally
305 	SteamDatagramLinkLifetimeStats m_lifetime;
306 
307 	/// Latest instantaneous stats received from remote host.
308 	/// (E.g. "sent" means they are reporting what they sent.)
309 	SteamDatagramLinkInstantaneousStats m_latestRemote;
310 
311 	/// How many seconds ago did we receive m_latestRemote?
312 	/// This will be <0 if the data is not valid!
313 	float m_flAgeLatestRemote;
314 
315 	/// Latest lifetime stats received from remote host.
316 	SteamDatagramLinkLifetimeStats m_lifetimeRemote;
317 
318 	/// How many seconds ago did we receive the lifetime stats?
319 	/// This will be <0 if the data is not valid!
320 	float m_flAgeLifetimeRemote;
321 
322 	/// Reset everything to unknown/initial state.
323 	void Clear();
324 };
325 
326 /// Describe detailed state of current connection
327 struct SteamNetworkingDetailedConnectionStatus
328 {
329 	/// Basic connection info
330 	SteamNetConnectionInfo_t m_info;
331 
332 	/// What kind of transport us being used?
333 	ESteamNetTransportKind m_eTransportKind;
334 
335 	/// Do we have a valid network configuration?  We cannot do anything without this.
336 	ESteamNetworkingAvailability m_eAvailNetworkConfig;
337 
338 //		/// Does it look like we have a connection to the Internet at all?
339 //		EAvailability m_eAvailInternet;
340 
341 	/// Successful communication with a box on the routing network.
342 	/// This will be marked as failed if there is a general internet
343 	/// connection.
344 	ESteamNetworkingAvailability m_eAvailAnyRouterCommunication;
345 
346 	/// End-to-end communication with the remote host.
347 	//ESteamNetworkingAvailability m_eAvailEndToEnd;
348 
349 	/// Stats for end-to-end link to the gameserver
350 	SteamDatagramLinkStats m_statsEndToEnd;
351 
352 	/// Currently selected front router, if any.
353 	/// Note that PoP ID can be found in the SteamNetConnectionInfo_t
354 	char m_szPrimaryRouterName[64];
355 	SteamNetworkingIPAddr m_addrPrimaryRouter;
356 
357 	/// Stats for "front" link to current router
358 	SteamDatagramLinkStats m_statsPrimaryRouter;
359 
360 	/// Back ping time as reported by primary.
361 	/// (The front ping is in m_statsPrimaryRouter,
362 	/// and usually the front ping plus the back ping should
363 	/// approximately equal the end-to-end ping)
364 	int m_nPrimaryRouterBackPing;
365 
366 	/// Currently selected back router, if any
367 	SteamNetworkingPOPID m_idBackupRouterCluster;
368 	char m_szBackupRouterName[64];
369 	SteamNetworkingIPAddr m_addrBackupRouter;
370 
371 	/// Ping times to backup router, if any
372 	int m_nBackupRouterFrontPing, m_nBackupRouterBackPing;
373 
374 	/// Clear everything to an unknown state
375 	void Clear();
376 
377 	/// Print into a buffer.
378 	/// 0 = OK
379 	/// >1 = buffer was null or too small (in which case truncation happened).
380 	/// Pass a buffer of at least N bytes.
381 	int Print( char *pszBuf, int cbBuf );
382 };
383 
384 #pragma pack(pop)
385 
386 } // namespace SteamNetworkingSocketsLib
387 
388 #endif // STEAMNETWORKING_STATS_H
389