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