From 29177dbbae087c9ff441e9a4294f523a77fac979 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 10 Jan 2024 06:41:22 +0800 Subject: [PATCH] [cli] separate ping sender as a module (#9756) --- src/cli/BUILD.gn | 2 + src/cli/CMakeLists.txt | 1 + src/cli/cli.cpp | 206 +-------------------------------- src/cli/cli.hpp | 19 +-- src/cli/cli_ping.cpp | 256 +++++++++++++++++++++++++++++++++++++++++ src/cli/cli_ping.hpp | 99 ++++++++++++++++ 6 files changed, 367 insertions(+), 216 deletions(-) create mode 100644 src/cli/cli_ping.cpp create mode 100644 src/cli/cli_ping.hpp diff --git a/src/cli/BUILD.gn b/src/cli/BUILD.gn index b7ef7312a..318a4d0b9 100644 --- a/src/cli/BUILD.gn +++ b/src/cli/BUILD.gn @@ -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", diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 022de520b..f36439f26 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -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 diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f288740bd..eecfeecf2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -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(*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(aContext)->HandlePingReply(aReply); -} - -void Interpreter::HandlePingReply(const otPingSenderReply *aReply) -{ - OutputFormat("%u bytes from ", static_cast(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(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(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(avgRoundTripTime / 1000), static_cast(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(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::kMax, error = OT_ERROR_INVALID_ARGS); - config.mTimeout = static_cast(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(Arg aArgs[]) { return mPing.Process(aArgs); } #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE /** diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 7b687dfb0..94798f22a 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -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 diff --git a/src/cli/cli_ping.cpp b/src/cli/cli_ping.cpp new file mode 100644 index 000000000..80868c789 --- /dev/null +++ b/src/cli/cli_ping.cpp @@ -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 + +#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::kMax, error = OT_ERROR_INVALID_ARGS); + config.mTimeout = static_cast(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(*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(aContext)->HandlePingReply(aReply); +} + +void PingSender::HandlePingReply(const otPingSenderReply *aReply) +{ + OutputFormat("%u bytes from ", static_cast(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(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(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(avgRoundTripTime / 1000), static_cast(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 diff --git a/src/cli/cli_ping.hpp b/src/cli/cli_ping.hpp new file mode 100644 index 000000000..e517506bd --- /dev/null +++ b/src/cli/cli_ping.hpp @@ -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 + +#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_