Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
Network.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#if qStroika_Foundation_Common_Platform_Windows
7#include <WinSock2.h>
8
9#include <Iphlpapi.h>
10#endif
11
12#include "Stroika/Foundation/Characters/FloatConversion.h"
13#include "Stroika/Foundation/Characters/String2Int.h"
14#include "Stroika/Foundation/Containers/Mapping.h"
15#include "Stroika/Foundation/Containers/Sequence.h"
16#include "Stroika/Foundation/Containers/Set.h"
22#include "Stroika/Foundation/Execution/ProcessRunner.h"
28#include "Stroika/Foundation/Streams/MemoryStream.h"
30
31#if qStroika_Foundation_Common_Platform_Windows
32#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
33#endif
34
35#include "Network.h"
36
37using namespace Stroika::Foundation;
41using namespace Stroika::Foundation::Execution;
43using namespace Stroika::Foundation::Memory;
44
45using namespace Stroika::Frameworks;
46using namespace Stroika::Frameworks::SystemPerformance;
47
51using Containers::Set;
54
58
59// Comment this in to turn on aggressive noisy DbgTrace in this module
60//#define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
61
62#ifndef qUseWMICollectionSupport_
63#define qUseWMICollectionSupport_ qStroika_Foundation_Common_Platform_Windows
64#endif
65
66#ifndef qSupportProcNet_
67#define qSupportProcNet_ qStroika_Foundation_Common_Platform_Linux
68#endif
69
70#if qUseWMICollectionSupport_
72
74#endif
75
76#if qUseWMICollectionSupport_
77namespace {
78 const String kBytesReceivedPerSecond_{"Bytes Received/sec"sv};
79 const String kBytesSentPerSecond_{"Bytes Sent/sec"sv};
80 const String kPacketsReceivedPerSecond_{"Packets Received/sec"sv};
81 const String kPacketsSentPerSecond_{"Packets Sent/sec"sv};
82 const String kTCPSegmentsPerSecond_{"Segments/sec"sv};
83 const String kSegmentsRetransmittedPerSecond_{"Segments Retransmitted/sec"sv};
84}
85#endif
86
87#if qStroika_Foundation_Common_Platform_Windows
88#pragma comment(lib, "iphlpapi.lib")
89#endif
90
91/*
92 ********************************************************************************
93 *********************** Instruments::Network::IOStatistics *********************
94 ********************************************************************************
95 */
97{
98 Memory::AccumulateIf (&fTotalBytesSent, rhs.fTotalBytesSent);
99 Memory::AccumulateIf (&fTotalBytesReceived, rhs.fTotalBytesReceived);
100 Memory::AccumulateIf (&fBytesPerSecondSent, rhs.fBytesPerSecondSent);
101 Memory::AccumulateIf (&fBytesPerSecondReceived, rhs.fBytesPerSecondReceived);
102 Memory::AccumulateIf (&fTotalTCPSegments, rhs.fTotalTCPSegments);
103 Memory::AccumulateIf (&fTCPSegmentsPerSecond, rhs.fTCPSegmentsPerSecond);
105 Memory::AccumulateIf (&fTCPRetransmittedSegmentsPerSecond, rhs.fTCPRetransmittedSegmentsPerSecond);
106 Memory::AccumulateIf (&fTotalPacketsSent, rhs.fTotalPacketsSent);
107 Memory::AccumulateIf (&fTotalPacketsReceived, rhs.fTotalPacketsReceived);
108 Memory::AccumulateIf (&fPacketsPerSecondSent, rhs.fPacketsPerSecondSent);
109 Memory::AccumulateIf (&fPacketsPerSecondReceived, rhs.fPacketsPerSecondReceived);
110 Memory::AccumulateIf (&fTotalErrors, rhs.fTotalErrors);
111 Memory::AccumulateIf (&fTotalPacketsDropped, rhs.fTotalPacketsDropped);
112 return *this;
113}
114
115/*
116 ********************************************************************************
117 ******************* Instruments::Network::IOStatistics *************************
118 ********************************************************************************
119 */
124
125/*
126********************************************************************************
127********************** Instruments::Network::Info ******************************
128********************************************************************************
129*/
134
135/*
136********************************************************************************
137********************** Instruments::Network::InterfaceInfo *********************
138********************************************************************************
139*/
140String Instruments::Network::InterfaceInfo::ToString () const
141{
143}
144
145namespace {
146 template <typename CONTEXT>
148}
149
150#if qStroika_Foundation_Common_Platform_POSIX
151namespace {
152 struct Last {
153 uint64_t fTotalBytesReceived;
154 uint64_t fTotalBytesSent;
155 uint64_t fTotalPacketsReceived;
156 uint64_t fTotalPacketsSent;
157 TimePointSeconds fAt;
158 };
159 struct LastSum {
160 uint64_t fTotalTCPSegments;
161 uint64_t fTotalTCPRetransmittedSegments;
162 TimePointSeconds fAt;
163 };
164
165 struct _Context : SystemPerformance::Support::Context {
167 optional<LastSum> fLastSum;
168 };
169
170 struct InstrumentRep_POSIX_ : InstrumentRepBase_<_Context> {
171
172 using InstrumentRepBase_<_Context>::InstrumentRepBase_;
173
174 Instruments::Network::Info _InternalCapture ()
175 {
177 using Instruments::Network::InterfaceInfo;
178
179 Collection<InterfaceInfo> interfaceResults;
180 IOStatistics accumSummary;
181#if qSupportProcNet_
182 // Some Linux builds may not have all (any) of the /proc stuff mounted (e.g. WSL 1)
183 IgnoreExceptionsExceptThreadAbortForCall (Read_proc_net_dev_ (&interfaceResults, &accumSummary));
184 IgnoreExceptionsExceptThreadAbortForCall (Read_proc_net_snmp_ (&accumSummary));
185#endif
186
187 TimePointSeconds now = Time::GetTickCount ();
188 auto contextLock = scoped_lock{_fContext};
189 shared_ptr<_Context> context = _fContext.rwget ().rwref ();
190 if (context->fLastSum and accumSummary.fTotalTCPSegments) {
191 Time::DurationSeconds timespan{now - context->fLastSum->fAt};
192 if (timespan >= _fOptions.fMinimumAveragingInterval) {
193 accumSummary.fTCPSegmentsPerSecond =
194 (NullCoalesce (accumSummary.fTotalTCPSegments) - context->fLastSum->fTotalTCPSegments) / timespan.count ();
195 }
196 }
197 if (context->fLastSum and accumSummary.fTotalTCPRetransmittedSegments) {
198 Time::DurationSeconds timespan{now - context->fLastSum->fAt};
199 if (timespan >= _fOptions.fMinimumAveragingInterval) {
200 accumSummary.fTCPRetransmittedSegmentsPerSecond =
201 (NullCoalesce (accumSummary.fTotalTCPRetransmittedSegments) - context->fLastSum->fTotalTCPRetransmittedSegments) /
202 timespan.count ();
203 }
204 }
205 if (accumSummary.fTotalTCPSegments and accumSummary.fTotalTCPRetransmittedSegments) {
206 context->fLastSum = LastSum{*accumSummary.fTotalTCPSegments, *accumSummary.fTotalTCPRetransmittedSegments, now};
207 }
208 _NoteCompletedCapture ();
209 return Info{interfaceResults, accumSummary};
210 }
211#if qSupportProcNet_
212 void Read_proc_net_dev_ (Collection<Instruments::Network::InterfaceInfo>* interfaceResults, IOStatistics* accumSummary)
213 {
214 SystemInterfacesMgr systemInterfacesMgr;
215 using Instruments::Network::InterfaceInfo;
216 RequireNotNull (interfaceResults);
217 RequireNotNull (accumSummary);
219 static const filesystem::path kProcFileName_{"/proc/net/dev"};
220 //static const String kProcFileName_ { L"c:\\Sandbox\\VMSharedFolder\\proc-net-dev"sv };
221 // Note - /procfs files always unseekable
222#if qStroika_Foundation_Debug_DefaultTracingOn
223 unsigned int nLine = 0;
224#endif
225 unsigned int n2Skip = 2;
226 for (const Sequence<String>& line :
227 reader.ReadMatrix (IO::FileSystem::FileInputStream::New (kProcFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
228#if USE_NOISY_TRACE_IN_THIS_MODULE_
229 DbgTrace ("in Instruments::Network::Info capture_ linesize={}, line[0]={}"_f, line.size (), line.empty () ? ""_k : line[0]);
230#endif
231#if qStroika_Foundation_Debug_DefaultTracingOn
232 ++nLine;
233#endif
234 if (n2Skip > 0) {
235 --n2Skip;
236 continue;
237 }
238 if (line.size () >= 17) {
239 constexpr int kOffset2XMit_ = 8;
240 InterfaceInfo ii;
241 if (auto info = systemInterfacesMgr.GetById (line[0])) {
242 ii.fInterface = *info;
243 }
244 else {
245 ii.fInterface.fInternalInterfaceID = line[0];
246 ii.fInterface.fFriendlyName = line[0];
247 }
248 ii.fIOStatistics.fTotalBytesReceived = Characters::String2Int<uint64_t> (line[1]);
249 ii.fIOStatistics.fTotalBytesSent = Characters::String2Int<uint64_t> (line[kOffset2XMit_ + 1]);
250 ii.fIOStatistics.fTotalPacketsReceived = Characters::String2Int<uint64_t> (line[kOffset2XMit_ + 2]);
251 ii.fIOStatistics.fTotalPacketsSent = Characters::String2Int<uint64_t> (line[2]);
252 ii.fIOStatistics.fTotalErrors =
253 Characters::String2Int<uint64_t> (line[3]) + Characters::String2Int<uint64_t> (line[kOffset2XMit_ + 3]);
254 ii.fIOStatistics.fTotalPacketsDropped =
255 Characters::String2Int<uint64_t> (line[4]) + Characters::String2Int<uint64_t> (line[kOffset2XMit_ + 4]);
256
257 TimePointSeconds now = Time::GetTickCount ();
258 if (auto o = _fContext.cget ().cref ()->fLast.Lookup (ii.fInterface.fInternalInterfaceID)) {
259 DurationSeconds scanTime = now - o->fAt;
260 if (scanTime > _fOptions.fMinimumAveragingInterval) {
261 ii.fIOStatistics.fBytesPerSecondReceived =
262 (*ii.fIOStatistics.fTotalBytesReceived - o->fTotalBytesReceived) / scanTime.count ();
263 ii.fIOStatistics.fBytesPerSecondSent = (*ii.fIOStatistics.fTotalBytesSent - o->fTotalBytesSent) / scanTime.count ();
264 ii.fIOStatistics.fPacketsPerSecondReceived =
265 (*ii.fIOStatistics.fTotalPacketsReceived - o->fTotalPacketsReceived) / scanTime.count ();
266 ii.fIOStatistics.fPacketsPerSecondSent =
267 (*ii.fIOStatistics.fTotalPacketsReceived - o->fTotalPacketsReceived) / scanTime.count ();
268 }
269 }
270 (*accumSummary) += ii.fIOStatistics;
271 interfaceResults->Add (ii);
272 _fContext.rwget ().rwref ()->fLast.Add (ii.fInterface.fInternalInterfaceID,
273 Last{*ii.fIOStatistics.fTotalBytesReceived, *ii.fIOStatistics.fTotalBytesSent,
274 *ii.fIOStatistics.fTotalPacketsReceived, *ii.fIOStatistics.fTotalPacketsSent, now});
275 }
276 else {
277 DbgTrace ("Line {} bad in file {}"_f, nLine, kProcFileName_);
278 }
279 }
280 }
281 void Read_proc_net_netstat_ (IOStatistics* accumSummary)
282 {
283 AssertNotReached (); // don't use this for now
284 RequireNotNull (accumSummary);
286 static const filesystem::path kProcFileName_{"/proc/net/netstat"};
287 // Note - /procfs files always unseekable
288 bool firstTime = true;
290 for (const Sequence<String>& line :
291 reader.ReadMatrix (IO::FileSystem::FileInputStream::New (kProcFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
292#if USE_NOISY_TRACE_IN_THIS_MODULE_
293 DbgTrace ("in Instruments::Network::Info Read_proc_net_netstat_ linesize={}, line[0]={}"_f, line.size (),
294 line.empty () ? ""_k : line[0]);
295#endif
296 if (line.size () >= 2 and line[0].Trim () == "TcpExt:"sv) {
297 if (firstTime) {
298 size_t idx = 0;
299 for (const String& i : line) {
300 labelMap.Add (i.Trim (), idx++);
301 }
302 firstTime = false;
303 }
304 else {
305 // @todo must sum several fields - NYI
306 if (auto oTCPSynRetransIdx = labelMap.Lookup ("TCPSynRetrans"sv)) {
307 if (*oTCPSynRetransIdx < line.length ()) {
308 uint64_t TCPSynRetrans = Characters::String2Int<uint64_t> (line[*oTCPSynRetransIdx]);
309 accumSummary->fTotalTCPRetransmittedSegments = TCPSynRetrans;
310 }
311 }
312 }
313 }
314 }
315 }
316 void Read_proc_net_snmp_ (IOStatistics* accumSummary)
317 {
318 RequireNotNull (accumSummary);
320 static const filesystem::path kProcFileName_{"/proc/net/snmp"sv};
321 // Note - /procfs files always unseekable
322 bool firstTime = true;
324 optional<uint64_t> totalTCPSegments;
325 for (const Sequence<String>& line :
326 reader.ReadMatrix (IO::FileSystem::FileInputStream::New (kProcFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
327#if USE_NOISY_TRACE_IN_THIS_MODULE_
328 DbgTrace ("in Instruments::Network::Info Read_proc_net_snmp_ linesize={}, line[0]={}"_f, line.size (), line.empty () ? ""_k : line[0]);
329#endif
330 if (line.size () >= 2 and line[0].Trim () == "Tcp:"sv) {
331 if (firstTime) {
332 size_t idx = 0;
333 for (const String& i : line) {
334 labelMap.Add (i.Trim (), idx++);
335 }
336 firstTime = false;
337 }
338 else {
339 static const String kInSegs_{"InSegs"sv};
340 static const String kOutSegs_{"OutSegs"sv};
341 static const String kRetransSegs_{"RetransSegs"sv};
342 if (auto idx = labelMap.Lookup (kInSegs_)) {
343 if (*idx < line.length ()) {
344 Memory::AccumulateIf (&totalTCPSegments, Characters::String2Int<uint64_t> (line[*idx]));
345 }
346 }
347 if (auto idx = labelMap.Lookup (kOutSegs_)) {
348 if (*idx < line.length ()) {
349 Memory::AccumulateIf (&totalTCPSegments, Characters::String2Int<uint64_t> (line[*idx]));
350 }
351 }
352 if (auto idx = labelMap.Lookup (kRetransSegs_)) {
353 if (*idx < line.length ()) {
354 accumSummary->fTotalTCPRetransmittedSegments = Characters::String2Int<uint64_t> (line[*idx]);
355 }
356 }
357 }
358 }
359 }
360 Memory::CopyToIf (&accumSummary->fTotalTCPSegments, totalTCPSegments);
361 }
362#endif
363 };
364}
365#endif
366
367#if qStroika_Foundation_Common_Platform_Windows
368namespace {
369 struct _Context : SystemPerformance::Support::Context {
370#if qUseWMICollectionSupport_
371 WMICollector fNetworkWMICollector_{
372 "Network Interface"sv, {}, {kBytesReceivedPerSecond_, kBytesSentPerSecond_, kPacketsReceivedPerSecond_, kPacketsSentPerSecond_}};
373 WMICollector fTCPv4WMICollector_{"TCPv4"sv, {}, {kTCPSegmentsPerSecond_, kSegmentsRetransmittedPerSecond_}};
374 WMICollector fTCPv6WMICollector_{"TCPv6"sv, {}, {kTCPSegmentsPerSecond_, kSegmentsRetransmittedPerSecond_}};
375 Set<String> fAvailableInstances_{fNetworkWMICollector_.GetAvailableInstances ()};
376#endif
377 };
378
379 struct InstrumentRep_Windows_ : InstrumentRepBase_<_Context> {
380
381 InstrumentRep_Windows_ (const Options& options, const shared_ptr<_Context>& context)
382 : InstrumentRepBase_<_Context>{options, context}
383 {
384#if qUseWMICollectionSupport_
385#if USE_NOISY_TRACE_IN_THIS_MODULE_
386 {
387 Debug::TraceContextBumper ctx{"ALL WMI Network Avialable instances"};
388 for (const String& i : fAvailableInstances_) {
389 DbgTrace (L"wmiInstanceName='{}'", i);
390 }
391 }
392#endif
393#endif
394 }
395
396 Instruments::Network::Info _InternalCapture ()
397 {
399 using Instruments::Network::InterfaceInfo;
401
402 Info result;
403 Collection<InterfaceInfo> interfaceResults;
404 IOStatistics accumSummary;
405 SystemInterfacesMgr systemInterfacesMgr;
406 Iterable<Interface> networkInterfacs{systemInterfacesMgr.GetAll ()};
407#if qUseWMICollectionSupport_
408 _fContext.rwget ().rwref ()->fNetworkWMICollector_.Collect ();
409 _fContext.rwget ().rwref ()->fTCPv4WMICollector_.Collect ();
410 _fContext.rwget ().rwref ()->fTCPv6WMICollector_.Collect ();
411#endif
412 {
413 for (const IO::Network::Interface& networkInterface : networkInterfacs) {
414 InterfaceInfo ii;
415#if 0
416 ii.fInternalInterfaceID = networkInterface.fInternalInterfaceID;
417 ii.fDisplayName = networkInterface.fFriendlyName;
418 ii.fInterfaceType = networkInterface.fType;
419 ii.fInterfaceStatus = networkInterface.fStatus;
420#endif
421 ii.fInterface = networkInterface;
422#if qUseWMICollectionSupport_
423 Read_WMI_ (networkInterface, &ii);
424#endif
425 accumSummary += ii.fIOStatistics;
426 interfaceResults.Add (move (ii));
427 }
428 }
429 result.fInterfaces = interfaceResults;
430 {
431 MIB_IPSTATS stats{}; // maybe more useful stats we could pull out of this?
432 Execution::Platform::Windows::ThrowIfNot_NO_ERROR (::GetIpStatistics (&stats));
433 accumSummary.fTotalPacketsReceived = stats.dwInReceives;
434 accumSummary.fTotalPacketsSent = stats.dwOutRequests;
435 }
436 result.fSummaryIOStatistics = accumSummary;
437 _NoteCompletedCapture ();
438 return result;
439 }
440#if qUseWMICollectionSupport_
441 void Read_WMI_ (const IO::Network::Interface& iFace, Instruments::Network::InterfaceInfo* updateResult)
442 {
443#if USE_NOISY_TRACE_IN_THIS_MODULE_
444 Debug::TraceContextBumper ctx{"Instruments::Network::....Read_WMI_"};
445#endif
446 /*
447 * @todo - this mapping of descriptions to WMI instance names is an INCREDIBLE KLUDGE. Not sure how to do this properly.
448 * a research question.
449 * --LGP 2015-04-16
450 */
451 String wmiInstanceName = NullCoalesce (iFace.fDescription).ReplaceAll ("("sv, "["sv).ReplaceAll (")"sv, "]"sv).ReplaceAll ("#"sv, "_"sv);
452
453#if USE_NOISY_TRACE_IN_THIS_MODULE_
454 DbgTrace ("iFace.fDescription='{}'"_f, iFace.fDescription.Value ());
455 DbgTrace ("wmiInstanceName='{}'"_f, wmiInstanceName);
456#endif
457
458 /*
459 * @todo this fAvailableInstances_.Contains code all over the place is a horrible kludge prevent WMI crashes. Not sure
460 * what the best solution is. COULD just pre-add all interfaces. BUt that might monitor/collect too much?
461 *
462 * And it might miss if new interfaces are added dynamically.
463 * --LGP 2015-04-16
464 */
465 if (_fContext.cget ().cref ()->fAvailableInstances_.Contains (wmiInstanceName)) {
466 auto lock = scoped_lock{_fContext};
467 auto context = _fContext.cget ().cref ();
468 context->fNetworkWMICollector_.AddInstancesIf (wmiInstanceName);
469 context->fTCPv4WMICollector_.AddInstancesIf (wmiInstanceName);
470 context->fTCPv6WMICollector_.AddInstancesIf (wmiInstanceName);
471 }
472
473 if (_fContext.cget ().cref ()->fAvailableInstances_.Contains (wmiInstanceName)) {
474 auto lock = scoped_lock{_fContext};
475 auto context = _fContext.rwget ().rwref ();
476 /*
477 * Note because WMI maintains these per/second numbers, its not clear there is a need for me to strip them out if
478 * lastCapture time since now < = _fOptions.fMinimumAveragingInterval
479 */
480 Memory::CopyToIf (&updateResult->fIOStatistics.fBytesPerSecondReceived,
481 context->fNetworkWMICollector_.PeekCurrentValue (wmiInstanceName, kBytesReceivedPerSecond_));
482 Memory::CopyToIf (&updateResult->fIOStatistics.fBytesPerSecondSent,
483 context->fNetworkWMICollector_.PeekCurrentValue (wmiInstanceName, kBytesSentPerSecond_));
484 Memory::CopyToIf (&updateResult->fIOStatistics.fPacketsPerSecondReceived,
485 context->fNetworkWMICollector_.PeekCurrentValue (wmiInstanceName, kPacketsReceivedPerSecond_));
486 Memory::CopyToIf (&updateResult->fIOStatistics.fPacketsPerSecondSent,
487 context->fNetworkWMICollector_.PeekCurrentValue (wmiInstanceName, kPacketsSentPerSecond_));
488
489 Memory::AccumulateIf (&updateResult->fIOStatistics.fTCPSegmentsPerSecond,
490 context->fTCPv4WMICollector_.PeekCurrentValue (wmiInstanceName, kTCPSegmentsPerSecond_));
491 Memory::AccumulateIf (&updateResult->fIOStatistics.fTCPSegmentsPerSecond,
492 context->fTCPv6WMICollector_.PeekCurrentValue (wmiInstanceName, kTCPSegmentsPerSecond_));
493
494 Memory::AccumulateIf (&updateResult->fIOStatistics.fTCPRetransmittedSegmentsPerSecond,
495 context->fTCPv4WMICollector_.PeekCurrentValue (wmiInstanceName, kSegmentsRetransmittedPerSecond_));
496 Memory::AccumulateIf (&updateResult->fIOStatistics.fTCPRetransmittedSegmentsPerSecond,
497 context->fTCPv6WMICollector_.PeekCurrentValue (wmiInstanceName, kSegmentsRetransmittedPerSecond_));
498 }
499 }
500#endif
501 };
502}
503#endif
504
505namespace {
506 const MeasurementType kNetworkInterfacesMeasurement_ = MeasurementType{L"Network-Interfaces"sv};
507}
508
509namespace {
510 struct NetworkInstrumentRep_
511#if qStroika_Foundation_Common_Platform_POSIX
512 : InstrumentRep_POSIX_
513#elif qStroika_Foundation_Common_Platform_Windows
514 : InstrumentRep_Windows_
515#else
516 : InstrumentRepBase_<SystemPerformance::Support::Context>
517#endif
518 {
519#if qStroika_Foundation_Common_Platform_POSIX
520 using inherited = InstrumentRep_POSIX_;
521#elif qStroika_Foundation_Common_Platform_Windows
522 using inherited = InstrumentRep_Windows_;
523#else
524 using inherited = InstrumentRepBase_<SystemPerformance::Support::Context>;
525#endif
526 NetworkInstrumentRep_ (const Options& options, const shared_ptr<_Context>& context = MakeSharedPtr<_Context> ())
527 : inherited{options, context}
528 {
529 Require (_fOptions.fMinimumAveragingInterval > 0s);
530 }
531 virtual MeasurementSet Capture () override
532 {
533 Debug::TraceContextBumper ctx{"SystemPerformance::Instrument...Network...NetworkInstrumentRep_::Capture ()"};
534 MeasurementSet results;
535 Measurement m{kNetworkInterfacesMeasurement_,
536 Instruments::Network::Instrument::kObjectVariantMapper.FromObject (Capture_Raw (&results.fMeasuredAt))};
537 results.fMeasurements.Add (m);
538 return results;
539 }
540 nonvirtual Info Capture_Raw (Range<TimePointSeconds>* outMeasuredAt)
541 {
542 auto before = _GetCaptureContextTime ();
543 Info rawMeasurement = _InternalCapture ();
544 if (outMeasuredAt != nullptr) {
546 *outMeasuredAt = Range<TimePointSeconds> (before, _GetCaptureContextTime (), Openness::eClosed, Openness::eClosed);
547 }
548 return rawMeasurement;
549 }
550 virtual unique_ptr<IRep> Clone () const override
551 {
552 return make_unique<NetworkInstrumentRep_> (_fOptions, _fContext.load ());
553 }
554 Instruments::Network::Info _InternalCapture ()
555 {
556 AssertExternallySynchronizedMutex::WriteContext declareContext{*this};
557#if USE_NOISY_TRACE_IN_THIS_MODULE_
558 Debug::TraceContextBumper ctx{"Instruments::Network::capture_"};
559#endif
560 return inherited::_InternalCapture ();
561 }
562 };
563}
564
565/*
566 ********************************************************************************
567 ********************** Instruments::Network::Instrument ************************
568 ********************************************************************************
569 */
571 ObjectVariantMapper mapper;
572 mapper.Add (mapper.MakeCommonSerializer_NamedEnumerations<Interface::Type> ());
573 mapper.AddCommonType<optional<Interface::Type>> ();
574 mapper.Add (mapper.MakeCommonSerializer_NamedEnumerations<Interface::Status> ());
576 mapper.AddCommonType<optional<Set<Interface::Status>>> ();
577 mapper.AddClass<InterfaceInfo::Interface> ({
578 {"Interface-Internal-ID"sv, &InterfaceInfo::Interface::fInternalInterfaceID},
579 {"Friendly-Name"sv, &InterfaceInfo::Interface::fFriendlyName},
580 {"Description"sv, &InterfaceInfo::Interface::fDescription},
581 {"Interface-Type"sv, &InterfaceInfo::Interface::fType},
582 {"Hardware-Address"sv, &InterfaceInfo::Interface::fHardwareAddress},
583 {"Interface-Status"sv, &InterfaceInfo::Interface::fStatus},
584 {"Transmit-Speed-Baud"sv, &InterfaceInfo::Interface::fTransmitSpeedBaud},
585 {"Receive-Link-Speed-Baud"sv, &InterfaceInfo::Interface::fReceiveLinkSpeedBaud},
586 // TODO ADD:
587 //Containers::Set<InternetAddress> fBindings;
588 });
589 mapper.AddClass<IOStatistics> ({
590 {"Total-Bytes-Sent"sv, &IOStatistics::fTotalBytesSent},
591 {"Total-Bytes-Received"sv, &IOStatistics::fTotalBytesReceived},
592 {"Bytes-Per-Second-Sent"sv, &IOStatistics::fBytesPerSecondSent},
593 {"Bytes-Per-Second-Received"sv, &IOStatistics::fBytesPerSecondReceived},
594 {"Total-TCP-Segments"sv, &IOStatistics::fTotalTCPSegments},
595 {"TCP-Segments-Per-Second"sv, &IOStatistics::fTCPSegmentsPerSecond},
596 {"Total-TCP-Retransmitted-Segments"sv, &IOStatistics::fTotalTCPRetransmittedSegments},
597 {"TCP-Retransmitted-Segments-Per-Second"sv, &IOStatistics::fTCPRetransmittedSegmentsPerSecond},
598 {"Total-Packets-Sent"sv, &IOStatistics::fTotalPacketsSent},
599 {"Total-Packets-Received"sv, &IOStatistics::fTotalPacketsReceived},
600 {"Packets-Per-Second-Sent"sv, &IOStatistics::fPacketsPerSecondSent},
601 {"Packets-Per-Second-Received"sv, &IOStatistics::fPacketsPerSecondReceived},
602 {"Total-Errors"sv, &IOStatistics::fTotalErrors},
603 {"Total-Packets-Dropped"sv, &IOStatistics::fTotalPacketsDropped},
604 });
605 mapper.AddClass<InterfaceInfo> ({
606 {"Interface"sv, &InterfaceInfo::fInterface},
607 {"IO-Statistics"sv, &InterfaceInfo::fIOStatistics},
608 });
610 mapper.AddCommonType<optional<Collection<InterfaceInfo>>> ();
611 mapper.AddCommonType<optional<IOStatistics>> ();
612 mapper.AddClass<Info> ({
613 {"Interfaces"sv, &Info::fInterfaces},
614 {"Summary-IO-Statistics"sv, &Info::fSummaryIOStatistics},
615 });
616 return mapper;
617}();
618
619Instruments::Network::Instrument::Instrument (const Options& options)
620 : SystemPerformance::Instrument{InstrumentNameType{"Network"sv},
621 make_unique<NetworkInstrumentRep_> (options),
622 {kNetworkInterfacesMeasurement_},
623 {KeyValuePair<type_index, MeasurementType>{typeid (Info), kNetworkInterfacesMeasurement_}},
624 kObjectVariantMapper}
625{
626}
627
628/*
629 ********************************************************************************
630 ********* SystemPerformance::Instrument::CaptureOneMeasurement *****************
631 ********************************************************************************
632 */
633template <>
635{
636 Debug::TraceContextBumper ctx{"SystemPerformance::Instrument::CaptureOneMeasurement<Network::Info>"};
637 NetworkInstrumentRep_* myCap = dynamic_cast<NetworkInstrumentRep_*> (fCaptureRep_.get ());
638 AssertNotNull (myCap);
639 return myCap->Capture_Raw (measurementTimeOut);
640}
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347
#define AssertNotReached()
Definition Assertions.h:355
wstring Capture(const Options &options={})
Definition BackTrace.cpp:46
const OT & NullCoalesce(const OT &l, const OT &r)
return one of l, or r, with first preference for which is engaged, and second preference for left-to-...
Definition Optional.inl:134
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
#define DbgTrace
Definition Trace.h:309
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
nonvirtual void Add(ArgByValueType< value_type > item)
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Definition Mapping.inl:188
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Definition Mapping.inl:142
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
An Atom is like a String, except that its much cheaper to copy/store/compare, and the semantics of co...
Definition Atom.h:133
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void AddClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
nonvirtual void AddCommonType(ARGS &&... args)
nonvirtual VariantValue FromObject(const T &from) const
This COULD be easily used to read CSV files, or tab-delimited files, for example.
nonvirtual String WriteAsString(const VariantValue &v) const
nonvirtual Traversal::Iterable< Interface > GetAll()
nonvirtual optional< Interface > GetById(const Interface::SystemIDType &internalInterfaceID)
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
An Instrument is a stateful object from which you can Capture () a series of measurements about a sys...
Definition Instrument.h:69
nonvirtual T CaptureOneMeasurement(Range< TimePointSeconds > *measurementTimeOut=nullptr)
Create a format-string (see std::wformat_string or Stroika FormatString, or python 'f' strings.
optional< Containers::Set< Status > > fStatus
Definition Interface.h:328
nonvirtual IOStatistics & operator+=(const IOStatistics &rhs)
Definition Network.cpp:96