[cli] separate ping sender as a module (#9756)

This commit is contained in:
Li Cao
2024-01-10 06:41:22 +08:00
committed by GitHub
parent f40eeeb145
commit 29177dbbae
6 changed files with 367 additions and 216 deletions
+2
View File
@@ -57,6 +57,8 @@ openthread_cli_sources = [
"cli_network_data.hpp",
"cli_output.cpp",
"cli_output.hpp",
"cli_ping.cpp",
"cli_ping.hpp",
"cli_srp_client.cpp",
"cli_srp_client.hpp",
"cli_srp_server.cpp",
+1
View File
@@ -46,6 +46,7 @@ set(COMMON_SOURCES
cli_mac_filter.cpp
cli_network_data.cpp
cli_output.cpp
cli_ping.cpp
cli_srp_client.cpp
cli_srp_server.cpp
cli_tcat.cpp
+4 -202
View File
@@ -152,6 +152,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
, mTcat(aInstance, *this)
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
, mPing(aInstance, *this)
#endif
#if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
, mLocateInProgress(false)
#endif
@@ -447,57 +450,6 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
otError Interpreter::ParsePingInterval(const Arg &aArg, uint32_t &aInterval)
{
otError error = OT_ERROR_NONE;
const char *string = aArg.GetCString();
const uint32_t msFactor = 1000;
uint32_t factor = msFactor;
aInterval = 0;
while (*string)
{
if ('0' <= *string && *string <= '9')
{
// In the case of seconds, change the base of already calculated value.
if (factor == msFactor)
{
aInterval *= 10;
}
aInterval += static_cast<uint32_t>(*string - '0') * factor;
// In the case of milliseconds, change the multiplier factor.
if (factor != msFactor)
{
factor /= 10;
}
}
else if (*string == '.')
{
// Accept only one dot character.
VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS);
// Start analyzing hundreds of milliseconds.
factor /= 10;
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
string++;
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
otError Interpreter::ParsePreference(const Arg &aArg, otRoutePreference &aPreference)
{
otError error = OT_ERROR_NONE;
@@ -5550,55 +5502,6 @@ exit:
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
void Interpreter::HandlePingReply(const otPingSenderReply *aReply, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandlePingReply(aReply);
}
void Interpreter::HandlePingReply(const otPingSenderReply *aReply)
{
OutputFormat("%u bytes from ", static_cast<uint16_t>(aReply->mSize + sizeof(otIcmp6Header)));
OutputIp6Address(aReply->mSenderAddress);
OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime);
}
void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandlePingStatistics(aStatistics);
}
void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics)
{
OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount);
if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast &&
aStatistics->mReceivedCount <= aStatistics->mSentCount)
{
uint32_t packetLossRate =
1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount;
OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10),
static_cast<uint16_t>(packetLossRate % 10));
}
if (aStatistics->mReceivedCount != 0)
{
uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount;
OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime,
static_cast<uint16_t>(avgRoundTripTime / 1000), static_cast<uint16_t>(avgRoundTripTime % 1000),
aStatistics->mMaxRoundTripTime);
}
OutputNewLine();
if (!mPingIsAsync)
{
OutputResult(OT_ERROR_NONE);
}
}
/**
* @cli ping
* @code
@@ -5634,108 +5537,7 @@ void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics
* Note: The command will return InvalidState when the preferred NAT64 prefix is unavailable.
* @sa otPingSenderPing
*/
template <> otError Interpreter::Process<Cmd("ping")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otPingSenderConfig config;
bool async = false;
bool nat64SynthesizedAddress;
/**
* @cli ping stop
* @code
* ping stop
* Done
* @endcode
* @par
* Stop sending ICMPv6 Echo Requests.
* @sa otPingSenderStop
*/
if (aArgs[0] == "stop")
{
otPingSenderStop(GetInstancePtr());
ExitNow();
}
else if (aArgs[0] == "async")
{
async = true;
aArgs++;
}
memset(&config, 0, sizeof(config));
if (aArgs[0] == "-I")
{
SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource));
#if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS);
#endif
aArgs += 2;
}
if (aArgs[0] == "-m")
{
config.mMulticastLoop = true;
aArgs++;
}
SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Pinging synthesized IPv6 address: ");
OutputIp6AddressLine(config.mDestination);
}
if (!aArgs[1].IsEmpty())
{
SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize));
}
if (!aArgs[2].IsEmpty())
{
SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount));
}
if (!aArgs[3].IsEmpty())
{
SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval));
}
if (!aArgs[4].IsEmpty())
{
SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit));
config.mAllowZeroHopLimit = (config.mHopLimit == 0);
}
if (!aArgs[5].IsEmpty())
{
uint32_t timeout;
SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout));
VerifyOrExit(timeout <= NumericLimits<uint16_t>::kMax, error = OT_ERROR_INVALID_ARGS);
config.mTimeout = static_cast<uint16_t>(timeout);
}
VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
config.mReplyCallback = Interpreter::HandlePingReply;
config.mStatisticsCallback = Interpreter::HandlePingStatistics;
config.mCallbackContext = this;
SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config));
mPingIsAsync = async;
if (!async)
{
error = OT_ERROR_PENDING;
}
exit:
return error;
}
template <> otError Interpreter::Process<Cmd("ping")>(Arg aArgs[]) { return mPing.Process(aArgs); }
#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
/**
+5 -14
View File
@@ -69,6 +69,7 @@
#include "cli/cli_mac_filter.hpp"
#include "cli/cli_network_data.hpp"
#include "cli/cli_output.hpp"
#include "cli/cli_ping.hpp"
#include "cli/cli_srp_client.hpp"
#include "cli/cli_srp_server.hpp"
#include "cli/cli_tcat.hpp"
@@ -117,6 +118,7 @@ class Interpreter : public OutputImplementer, public Output
friend class Joiner;
friend class LinkMetrics;
friend class NetworkData;
friend class PingSender;
friend class SrpClient;
friend class SrpServer;
#endif
@@ -382,9 +384,6 @@ private:
void OutputPrompt(void);
void OutputResult(otError aError);
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
otError ParsePingInterval(const Arg &aArg, uint32_t &aInterval);
#endif
static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner);
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig);
@@ -458,10 +457,6 @@ private:
void OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo);
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
static void HandlePingReply(const otPingSenderReply *aReply, void *aContext);
static void HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext);
#endif
static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext);
static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext);
@@ -497,10 +492,6 @@ private:
static void HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult);
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
void HandlePingReply(const otPingSenderReply *aReply);
void HandlePingStatistics(const otPingSenderStatistics *aStatistics);
#endif
void HandleActiveScanResult(otActiveScanResult *aResult);
void HandleEnergyScanResult(otEnergyScanResult *aResult);
void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx);
@@ -602,11 +593,11 @@ private:
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
Tcat mTcat;
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
PingSender mPing;
#endif
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
bool mPingIsAsync : 1;
#endif
#if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
bool mLocateInProgress : 1;
#endif
+256
View File
@@ -0,0 +1,256 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the CLI interpreter for Ping Sender function.
*/
#include "cli_ping.hpp"
#include <openthread/ping_sender.h>
#include "cli/cli.hpp"
#include "cli/cli_output.hpp"
#include "common/code_utils.hpp"
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
namespace ot {
namespace Cli {
PingSender::PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer)
: Output(aInstance, aOutputImplementer)
, mPingIsAsync(false)
{
}
otError PingSender::Process(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otPingSenderConfig config;
bool async = false;
bool nat64SynthesizedAddress;
/**
* @cli ping stop
* @code
* ping stop
* Done
* @endcode
* @par
* Stop sending ICMPv6 Echo Requests.
* @sa otPingSenderStop
*/
if (aArgs[0] == "stop")
{
otPingSenderStop(GetInstancePtr());
ExitNow();
}
else if (aArgs[0] == "async")
{
async = true;
aArgs++;
}
memset(&config, 0, sizeof(config));
if (aArgs[0] == "-I")
{
SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource));
#if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS);
#endif
aArgs += 2;
}
if (aArgs[0] == "-m")
{
config.mMulticastLoop = true;
aArgs++;
}
SuccessOrExit(error = Interpreter::GetInterpreter().ParseToIp6Address(
GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Pinging synthesized IPv6 address: ");
OutputIp6AddressLine(config.mDestination);
}
if (!aArgs[1].IsEmpty())
{
SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize));
}
if (!aArgs[2].IsEmpty())
{
SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount));
}
if (!aArgs[3].IsEmpty())
{
SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval));
}
if (!aArgs[4].IsEmpty())
{
SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit));
config.mAllowZeroHopLimit = (config.mHopLimit == 0);
}
if (!aArgs[5].IsEmpty())
{
uint32_t timeout;
SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout));
VerifyOrExit(timeout <= NumericLimits<uint16_t>::kMax, error = OT_ERROR_INVALID_ARGS);
config.mTimeout = static_cast<uint16_t>(timeout);
}
VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
config.mReplyCallback = PingSender::HandlePingReply;
config.mStatisticsCallback = PingSender::HandlePingStatistics;
config.mCallbackContext = this;
SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config));
mPingIsAsync = async;
if (!async)
{
error = OT_ERROR_PENDING;
}
exit:
return error;
}
otError PingSender::ParsePingInterval(const Arg &aArg, uint32_t &aInterval)
{
otError error = OT_ERROR_NONE;
const char *string = aArg.GetCString();
const uint32_t msFactor = 1000;
uint32_t factor = msFactor;
aInterval = 0;
while (*string)
{
if ('0' <= *string && *string <= '9')
{
// In the case of seconds, change the base of already calculated value.
if (factor == msFactor)
{
aInterval *= 10;
}
aInterval += static_cast<uint32_t>(*string - '0') * factor;
// In the case of milliseconds, change the multiplier factor.
if (factor != msFactor)
{
factor /= 10;
}
}
else if (*string == '.')
{
// Accept only one dot character.
VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS);
// Start analyzing hundreds of milliseconds.
factor /= 10;
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
string++;
}
exit:
return error;
}
void PingSender::HandlePingReply(const otPingSenderReply *aReply, void *aContext)
{
static_cast<PingSender *>(aContext)->HandlePingReply(aReply);
}
void PingSender::HandlePingReply(const otPingSenderReply *aReply)
{
OutputFormat("%u bytes from ", static_cast<uint16_t>(aReply->mSize + sizeof(otIcmp6Header)));
OutputIp6Address(aReply->mSenderAddress);
OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime);
}
void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext)
{
static_cast<PingSender *>(aContext)->HandlePingStatistics(aStatistics);
}
void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics)
{
OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount);
if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast &&
aStatistics->mReceivedCount <= aStatistics->mSentCount)
{
uint32_t packetLossRate =
1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount;
OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10),
static_cast<uint16_t>(packetLossRate % 10));
}
if (aStatistics->mReceivedCount != 0)
{
uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount;
OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime,
static_cast<uint16_t>(avgRoundTripTime / 1000), static_cast<uint16_t>(avgRoundTripTime % 1000),
aStatistics->mMaxRoundTripTime);
}
OutputNewLine();
if (!mPingIsAsync)
{
OutputResult(OT_ERROR_NONE);
}
}
void PingSender::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); }
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file contains definitions for the CLI interpreter for Ping Sneder function.
*/
#ifndef CLI_PING_SENDER_HPP_
#define CLI_PING_SENDER_HPP_
#include "openthread-core-config.h"
#include <openthread/ping_sender.h>
#include "cli/cli_output.hpp"
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
namespace ot {
namespace Cli {
/**
* Implements the Ping Sender CLI interpreter.
*
*/
class PingSender : private Output
{
public:
typedef Utils::CmdLineParser::Arg Arg;
/**
* Constructor
*
* @param[in] aInstance The OpenThread Instance.
* @param[in] aOutputImplementer An `OutputImplementer`.
*
*/
PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer);
/**
* Processes a CLI sub-command.
*
* @param[in] aArgs An array of command line arguments.
*
* @retval OT_ERROR_NONE Successfully executed the CLI command.
* @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending.
* @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command.
* @retval OT_ERROR_INVALID_ARGS Invalid arguments.
* @retval ... Error during execution of the CLI command.
*
*/
otError Process(Arg aArgs[]);
private:
otError ParsePingInterval(const Arg &aArg, uint32_t &aInterval);
static void HandlePingReply(const otPingSenderReply *aReply, void *aContext);
void HandlePingReply(const otPingSenderReply *aReply);
static void HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext);
void HandlePingStatistics(const otPingSenderStatistics *aStatistics);
void OutputResult(otError aError);
bool mPingIsAsync : 1;
};
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
#endif // CLI_PING_SENDER_HPP_