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