Stroika Library 3.0d21
 
Loading...
Searching...
No Matches
Samples/Traceroute/Sources/Traceroute.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <iostream>
7
8#include "Stroika/Foundation/Characters/String2Int.h"
10#include "Stroika/Foundation/Containers/Collection.h"
12#include "Stroika/Foundation/Execution/CommandLine.h"
14
16#include "Stroika/Frameworks/NetworkMonitor/Traceroute.h"
17
18using namespace std;
19
20using namespace Stroika::Foundation;
23using namespace Stroika::Foundation::IO::Network::InternetProtocol;
24using namespace Stroika::Foundation::Time;
25using namespace Stroika::Frameworks;
26using namespace Stroika::Frameworks::NetworkMonitor;
27
30
31int main (int argc, const char* argv[])
32{
34 Stroika_Foundation_Debug_OptionalizeTraceArgs ("main", "argv={}"_f, Characters::ToString (vector<const char*>{argv, argv + argc}))};
35 String targetAddress;
36 enum class MajorOp {
37 ePing,
38 eTraceroute,
39 };
40 MajorOp majorOp = MajorOp::eTraceroute;
41 unsigned int maxHops = Ping::Options::kDefaultMaxHops;
42 unsigned int sampleCount = 3;
43 static const Duration kInterSampleTime_{"PT.1S"}; // aka 1.5s
44 size_t packetSize = Ping::Options::kDefaultPayloadSize + sizeof (ICMP::V4::PacketHeader); // historically, the app ping has measured this including ICMP packet header, but not ip packet header size
45 const Execution::CommandLine::Option kPingO_{.fLongName = "ping"sv, .fHelpOptionText = "Ping the target address"sv};
46 const Execution::CommandLine::Option kTraceRtO_{.fLongName = "traceroute"sv, .fHelpOptionText = "Trace the route to the target address"sv};
47 const Execution::CommandLine::Option kPacketSizeO_{
48 .fLongName = "packetSize"sv, .fSupportsArgument = true, .fHelpArgName = "N", .fHelpOptionText = "Number of bytes to send in each test packet"sv};
49 const Execution::CommandLine::Option kMaxHopsO_{
50 .fLongName = "maxHops"sv, .fSupportsArgument = true, .fHelpArgName = "N", .fHelpOptionText = "Max number of hops to get to the target address"sv};
51 const Execution::CommandLine::Option kSampleCntO_{
52 .fLongName = "sampleCount"sv,
53 .fSupportsArgument = true,
54 .fHelpArgName = "N"sv,
55 .fHelpOptionText = "(default 3) - if sampleCount is 1, exception details shown, otherwise just summary of number of exceptions"sv};
56 const Execution::CommandLine::Option kTargetAddress_{.fSupportsArgument = true, .fRequired = true, .fHelpArgName = "target-address"sv};
57
58 using namespace Execution::StandardCommandLineOptions;
59
60 const initializer_list<Execution::CommandLine::Option> kAllOptions_{kHelp, kPingO_, kTraceRtO_, kPacketSizeO_,
61 kMaxHopsO_, kSampleCntO_, kTargetAddress_};
62
63 auto usage = [&] (const optional<String>& extraArg = {}) {
64 if (extraArg) {
65 cerr << *extraArg << endl;
66 }
67 cerr << Execution::CommandLine::GenerateUsage ("traceroute"sv, kAllOptions_);
68 };
69
70 Execution::CommandLine cmdLine{argc, argv};
71 using namespace Execution::StandardCommandLineOptions;
72
73 if (cmdLine.Has (kPingO_)) {
74 majorOp = MajorOp::ePing;
75 }
76 if (cmdLine.Has (kTraceRtO_)) {
77 majorOp = MajorOp::eTraceroute;
78 }
79 if (auto o = cmdLine.GetArgument (kPacketSizeO_)) {
80 packetSize = Characters::String2Int<unsigned int> (*o);
81 }
82 if (auto o = cmdLine.GetArgument (kMaxHopsO_)) {
83 maxHops = Characters::String2Int<unsigned int> (*o);
84 }
85 if (auto o = cmdLine.GetArgument (kSampleCntO_)) {
86 sampleCount = Characters::String2Int<unsigned int> (*o);
87 }
88 if (cmdLine.Has (kHelp)) {
89 usage ();
90 return EXIT_SUCCESS;
91 }
92 targetAddress = cmdLine.GetArgument (kTargetAddress_).value_or (String{});
93
94 try {
95 cmdLine.Validate (kAllOptions_);
97 if (addrList.empty ()) {
98 Execution::Throw (Execution::Exception{"whoops no addrs"sv});
99 }
100 InternetAddress addr = addrList.Nth (0);
101
102 switch (majorOp) {
103 case MajorOp::ePing: {
104 Ping::Options options{};
105 options.fPacketPayloadSize = Ping::Options::kAllowedICMPPayloadSizeRange.Pin (packetSize - sizeof (ICMP::V4::PacketHeader));
106 options.fMaxHops = maxHops;
107 // options.fSampleInfo = Ping::Options::SampleInfo{kInterSampleTime_, sampleCount};
108 NetworkMonitor::Ping::SampleResults t =
109 NetworkMonitor::Ping::Sample (addr, Ping::SampleOptions{kInterSampleTime_, sampleCount}, options);
110 cout << "Ping to " << addr.ToString () << ": " << Characters::ToString (t) << endl;
111 } break;
112 case MajorOp::eTraceroute: {
113 Traceroute::Options options{};
114 options.fPacketPayloadSize = Traceroute::Options::kAllowedICMPPayloadSizeRange.Pin (packetSize - sizeof (ICMP::V4::PacketHeader));
115 options.fMaxHops = maxHops;
116
117 cout << "Tracing Route to " << targetAddress << " [" << Characters::ToString (addr) << "] over a maximum of " << maxHops
118 << " hops." << endl;
119 cout << endl;
120
121 // quickie - weak attempt at formatting the output
122 cout << "Hop\tTime\t\tAddress" << endl;
123 unsigned int hopIdx{1};
124 auto perHopCallback = [&] (Traceroute::Hop h) {
125 String hopName = [=] () -> String {
126 if (h.fAddress.empty ()) {
127 return "*"sv;
128 }
129 String addrStr = h.fAddress.As<String> ();
130 if (auto rdnsName = DNS::kThe.QuietReverseLookup (h.fAddress)) {
131 return *rdnsName + " ["_k + addrStr + "]"_k;
132 }
133 else {
134 return addrStr;
135 }
136 }();
137 String timeStr = h.fTime.empty () ? "timeout\t"_k : h.fTime.PrettyPrint ();
138 cout << hopIdx++ << "\t" << timeStr << "\t" << hopName << endl;
139 };
140 // can call without callback, and just get all the hops in a list, which is simpler. But using the callback allows you to see
141 // per hop progress as its accumulated, which is more typical for traceroute UI
142 Traceroute::Run (addr, perHopCallback, options);
143 } break;
144 }
145 }
146 catch (...) {
147 cerr << "Exception - " << Characters::ToString (current_exception ()) << " - terminating..." << endl;
148 return EXIT_FAILURE;
149 }
150 return EXIT_SUCCESS;
151}
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
Definition Trace.h:270
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 ...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:157
nonvirtual Sequence< InternetAddress > GetHostAddresses(const String &hostNameOrAddress) const
simple wrapper on GetHostEntry - looking up the hostname/ip address and returning the list of associa...
Definition DNS.cpp:238
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
nonvirtual T Nth(ptrdiff_t n) const
Find the Nth element of the Iterable<>
nonvirtual bool empty() const
Returns true iff size() == 0.
Definition Iterable.inl:308
STL namespace.