diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 49366e312..41aecda67 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (120) +#define OPENTHREAD_API_VERSION (121) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 96c9dffa8..c2fd39485 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -590,6 +590,24 @@ otError otIp6AddressFromString(const char *aString, otIp6Address *aAddress); */ void otIp6AddressToString(const otIp6Address *aAddress, char *aBuffer, uint16_t aSize); +#define OT_IP6_SOCK_ADDR_STRING_SIZE 48 ///< Recommended size for string representation of an IPv6 socket address. + +/** + * This function converts a given IPv6 socket address to a human-readable string. + * + * The IPv6 socket address string is formatted as "[
]:" where `
is shown as 16 hex values + * separated by ':' and `` is the port number in decimal format (i.e., "[%x:%x:...:%x]:%u") + * + * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be truncated + * but the outputted string is always null-terminated. + * + * @param[in] aSockAddr A pointer to an IPv6 socket address (MUST NOT be NULL). + * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL). + * @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_IP6_SOCK_ADDR_STRING_SIZE`. + * + */ +void otIp6SockAddrToString(const otSockAddr *aSockAddr, char *aBuffer, uint16_t aSize); + #define OT_IP6_PREFIX_STRING_SIZE 45 ///< Recommended size for string representation of an IPv6 prefix. /** diff --git a/src/cli/README.md b/src/cli/README.md index 756a4e593..dba1ba509 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -1767,12 +1767,12 @@ List all UDP sockets. ```bash > netstat -| Local Address | Peer Address | -+-----------------------------------------------+-----------------------------------------------+ -| 0:0:0:0:0:0:0:0:49153 | 0:0:0:0:0:0:0:0:* | -| 0:0:0:0:0:0:0:0:49152 | 0:0:0:0:0:0:0:0:* | -| 0:0:0:0:0:0:0:0:61631 | 0:0:0:0:0:0:0:0:* | -| 0:0:0:0:0:0:0:0:19788 | 0:0:0:0:0:0:0:0:* | +| Local Address | Peer Address | ++-------------------------------------------------+-------------------------------------------------+ +| [0:0:0:0:0:0:0:0]:49153 | [0:0:0:0:0:0:0:0]:0 | +| [0:0:0:0:0:0:0:0]:49152 | [0:0:0:0:0:0:0:0]:0 | +| [0:0:0:0:0:0:0:0]:61631 | [0:0:0:0:0:0:0:0]:0 | +| [0:0:0:0:0:0:0:0]:19788 | [0:0:0:0:0:0:0:0]:0 | Done ``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index dd5d669ae..db4a52f89 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -3025,66 +3025,25 @@ exit: otError Interpreter::ProcessNetstat(uint8_t aArgsLength, Arg aArgs[]) { - otUdpSocket *socket = otUdpGetSockets(mInstance); - OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); - OutputLine("| Local Address | Peer Address |"); - OutputLine("+-----------------------------------------------+-----------------------------------------------+"); + char string[OT_IP6_SOCK_ADDR_STRING_SIZE]; - while (socket) + OutputLine("| Local Address | Peer Address |"); + OutputLine("+-------------------------------------------------+-------------------------------------------------+"); + + for (const otUdpSocket *socket = otUdpGetSockets(mInstance); socket != nullptr; socket = socket->mNext) { - constexpr int kMaxOutputLength = 45; - int outputLength; - - OutputFormat("| "); - - outputLength = OutputSocketAddress(socket->mSockName); - for (int i = outputLength; 0 <= i && i < kMaxOutputLength; ++i) - { - OutputFormat(" "); - } - OutputFormat(" | "); - - outputLength = OutputSocketAddress(socket->mPeerName); - for (int i = outputLength; 0 <= i && i < kMaxOutputLength; ++i) - { - OutputFormat(" "); - } - OutputLine(" |"); - - socket = socket->mNext; + otIp6SockAddrToString(&socket->mSockName, string, sizeof(string)); + OutputFormat("| %-47s ", string); + otIp6SockAddrToString(&socket->mPeerName, string, sizeof(string)); + OutputLine("| %-47s |", string); } return OT_ERROR_NONE; } -int Interpreter::OutputSocketAddress(const otSockAddr &aAddress) -{ - int outputLength; - int result = 0; - - VerifyOrExit((outputLength = OutputIp6Address(aAddress.mAddress)) >= 0, result = -1); - result += outputLength; - - VerifyOrExit((outputLength = OutputFormat(":")) >= 0, result = -1); - result += outputLength; - if (aAddress.mPort == 0) - { - VerifyOrExit((outputLength = OutputFormat("*")) >= 0, result = -1); - result += outputLength; - } - else - { - VerifyOrExit((outputLength = OutputFormat("%d", aAddress.mPort)) >= 0, result = -1); - result += outputLength; - } - -exit: - return result; -} - #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE otError Interpreter::ProcessServiceList(void) { diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 94c1eb4ff..914a7a2e4 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -460,7 +460,6 @@ private: void OutputPrefix(const otMeshLocalPrefix &aPrefix); otError ProcessNetstat(uint8_t aArgsLength, Arg aArgs[]); - int OutputSocketAddress(const otSockAddr &aAddress); #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE otError ProcessService(uint8_t aArgsLength, Arg aArgs[]); otError ProcessServiceList(void); diff --git a/src/cli/cli_srp_client.cpp b/src/cli/cli_srp_client.cpp index 959e448c6..fd5227003 100644 --- a/src/cli/cli_srp_client.cpp +++ b/src/cli/cli_srp_client.cpp @@ -303,9 +303,10 @@ otError SrpClient::ProcessServer(uint8_t aArgsLength, Arg aArgs[]) if (aArgsLength == 0) { - mInterpreter.OutputFormat("["); - mInterpreter.OutputIp6Address(serverSockAddr->mAddress); - mInterpreter.OutputLine("]:%u", serverSockAddr->mPort); + char string[OT_IP6_SOCK_ADDR_STRING_SIZE]; + + otIp6SockAddrToString(serverSockAddr, string, sizeof(string)); + mInterpreter.OutputLine(string); ExitNow(); } diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 7af46394a..9ec4f5359 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -237,6 +237,11 @@ void otIp6AddressToString(const otIp6Address *aAddress, char *aBuffer, uint16_t static_cast(aAddress)->ToString(aBuffer, aSize); } +void otIp6SockAddrToString(const otSockAddr *aSockAddr, char *aBuffer, uint16_t aSize) +{ + static_cast(aSockAddr)->ToString(aBuffer, aSize); +} + void otIp6PrefixToString(const otIp6Prefix *aPrefix, char *aBuffer, uint16_t aSize) { static_cast(aPrefix)->ToString(aBuffer, aSize); diff --git a/src/core/net/socket.cpp b/src/core/net/socket.cpp index 623f9ce96..89fd19d82 100644 --- a/src/core/net/socket.cpp +++ b/src/core/net/socket.cpp @@ -40,10 +40,22 @@ SockAddr::InfoString SockAddr::ToString(void) const { InfoString string; - string.Append("[%s]:%u", GetAddress().ToString().AsCString(), GetPort()); + ToString(string); return string; } +void SockAddr::ToString(char *aBuffer, uint16_t aSize) const +{ + StringWriter writer(aBuffer, aSize); + + ToString(writer); +} + +void SockAddr::ToString(StringWriter &aWriter) const +{ + aWriter.Append("[%s]:%u", GetAddress().ToString().AsCString(), GetPort()); +} + } // namespace Ip6 } // namespace ot diff --git a/src/core/net/socket.hpp b/src/core/net/socket.hpp index a7a259fa2..bdbc884f5 100644 --- a/src/core/net/socket.hpp +++ b/src/core/net/socket.hpp @@ -239,7 +239,7 @@ class SockAddr : public otSockAddr, public Clearable, public Unequatab public: enum : uint16_t { - kInfoStringSize = 50, ///< Max chars for the info string (`ToString()`). + kInfoStringSize = OT_IP6_SOCK_ADDR_STRING_SIZE, ///< Max chars for the info string (`ToString()`). }; /** @@ -343,6 +343,23 @@ public: * */ InfoString ToString(void) const; + + /** + * This method converts a given IPv6 socket address to a human-readable string. + * + * The IPv6 socket address string is formatted as "[]:". + * + * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be + * truncated but the outputted string is always null-terminated. + * + * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL). + * @param[in] aSize The size of @p aBuffer (in bytes). + * + */ + void ToString(char *aBuffer, uint16_t aSize) const; + +private: + void ToString(StringWriter &aWriter) const; }; /** diff --git a/tests/scripts/expect/tun-netstat.exp b/tests/scripts/expect/tun-netstat.exp index bd33388aa..33a082bce 100755 --- a/tests/scripts/expect/tun-netstat.exp +++ b/tests/scripts/expect/tun-netstat.exp @@ -35,24 +35,24 @@ setup_leader send "udp open\n" expect_line "Done" send "netstat\n" -expect "| Local Address | Peer Address |" -expect "+-----------------------------------------------+-----------------------------------------------+" -expect "| 0:0:0:0:0:0:0:0:* | 0:0:0:0:0:0:0:0:* |" +expect "| Local Address | Peer Address |" +expect "+-------------------------------------------------+-------------------------------------------------+" +expect "| [0:0:0:0:0:0:0:0]:0 | [0:0:0:0:0:0:0:0]:0 |" expect_line "Done" send "udp bind :: 10001\n" expect_line "Done" send "netstat\n" -expect "| Local Address | Peer Address |" -expect "+-----------------------------------------------+-----------------------------------------------+" -expect "| 0:0:0:0:0:0:0:0:10001 | 0:0:0:0:0:0:0:0:* |" +expect "| Local Address | Peer Address |" +expect "+-------------------------------------------------+-------------------------------------------------+" +expect "| [0:0:0:0:0:0:0:0]:1001 | [0:0:0:0:0:0:0:0]:0 |" expect_line "Done" set addr [get_ipaddr mleid] send "udp connect $addr 10001\n" expect_line "Done" send "netstat\n" -expect "| Local Address | Peer Address |" -expect "+-----------------------------------------------+-----------------------------------------------+" -expect -re "\\| 0:0:0:0:0:0:0:0:10001 +\\| $addr:10001 +\\|" +expect "| Local Address | Peer Address |" +expect "+-------------------------------------------------+-------------------------------------------------+" +expect -re "\\| \\[0:0:0:0:0:0:0:0\\]:10001 +\\| \\[$addr\\]:10001 +\\|" expect_line "Done" dispose_all