diff --git a/src/cli/README_UDP.md b/src/cli/README_UDP.md index 2ef631e60..24592c167 100644 --- a/src/cli/README_UDP.md +++ b/src/cli/README_UDP.md @@ -113,20 +113,32 @@ Send a UDP message. ```bash > udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 hello +Done ``` -### send \-s \ \ \ +### send \ \ \ \ Send a few bytes over UDP. -* message_size: number of bytes to be send. * ip: the IPv6 destination address. * port: the UDP destination port. +* type: the type of the message: + * `-t`: text payload in the `value`, same as without specifying the type. + * `-s`: autogenerated payload with specified length indicated in the `value`. + * `-x`: binary data in hexadecimal representation in the `value`. + ```bash -> udp send -s 800 fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -``` +> udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -t hello +Done +> udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -x 68656c6c6f +Done + +> udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -s 800 +Done + +``` ### send \ Send a UDP message on a connected socket. @@ -135,4 +147,25 @@ Send a UDP message on a connected socket. ```bash > udp send hello +Done +``` + +### send \ \ + +Send a few bytes over UDP. + +* type: the type of the message: + * `-t`: text payload in the `value`, same as without specifying the type. + * `-s`: autogenerated payload with specified length indicated in the `value`. + * `-x`: binary data in hexadecimal representation in the `value`. + +```bash +> udp send -t hello +Done + +> udp send -x 68656c6c6f +Done + +> udp send -s 800 +Done ``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f49ea19a3..88f9e34e9 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -261,16 +261,20 @@ Interpreter::Interpreter(Instance *aInstance) #endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE } -int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength) +int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength, bool aAllowTruncate) { size_t hexLength = strlen(aHex); const char *hexEnd = aHex + hexLength; uint8_t * cur = aBin; uint8_t numChars = hexLength & 1; uint8_t byte = 0; + int len = 0; int rval; - VerifyOrExit((hexLength + 1) / 2 <= aBinLength, rval = -1); + if (!aAllowTruncate) + { + VerifyOrExit((hexLength + 1) / 2 <= aBinLength, rval = -1); + } while (aHex < hexEnd) { @@ -299,6 +303,12 @@ int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength) numChars = 0; *cur++ = byte; byte = 0; + len++; + + if (len == aBinLength) + { + ExitNow(rval = len); + } } else { @@ -306,7 +316,7 @@ int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength) } } - rval = static_cast(cur - aBin); + rval = len; exit: return rval; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 5567c6710..ce89800fc 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -147,13 +147,16 @@ public: /** * This method converts a hex string to binary. * - * @param[in] aHex A pointer to the hex string. - * @param[out] aBin A pointer to where the binary representation is placed. - * @param[in] aBinLength Maximum length of the binary representation. + * @param[in] aHex A pointer to the hex string. + * @param[out] aBin A pointer to where the binary representation is placed. + * @param[in] aBinLength Maximum length of the binary representation. + * @param[in] aAllowTruncate TRUE if @p aBinLength may be less than what is required + * to convert @p aHex to binary representation, FALSE otherwise. + * * * @returns The number of bytes in the binary representation. */ - static int Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength); + static int Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength, bool aAllowTruncate = false); /** * Write error code the CLI console diff --git a/src/cli/cli_udp.cpp b/src/cli/cli_udp.cpp index 06a88ef83..ef28f66d4 100644 --- a/src/cli/cli_udp.cpp +++ b/src/cli/cli_udp.cpp @@ -134,35 +134,20 @@ otError UdpExample::ProcessOpen(int argc, char *argv[]) otError UdpExample::ProcessSend(int argc, char *argv[]) { - otError error; + otError error = OT_ERROR_NONE; otMessageInfo messageInfo; - otMessage * message = NULL; - int curArg = 0; - bool autoGenPayload = false; - unsigned long autoGenPayloadLength = 0; + otMessage * message = NULL; + int curArg = 0; + uint16_t payloadLength = 0; + PayloadType payloadType = kTypeText; memset(&messageInfo, 0, sizeof(messageInfo)); - VerifyOrExit(argc == 1 || argc == 3 || argc == 4, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(argc >= 1 && argc <= 4, error = OT_ERROR_INVALID_ARGS); - if (argc == 4) - { - if (strcmp(argv[curArg++], "-s") == 0) - { - autoGenPayload = true; - error = Interpreter::ParseUnsignedLong(argv[curArg++], autoGenPayloadLength); - SuccessOrExit(error); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - - if (argc >= 3) + if (argc > 2) { long value; - error = otIp6AddressFromString(argv[curArg++], &messageInfo.mPeerAddr); SuccessOrExit(error); @@ -172,18 +157,66 @@ otError UdpExample::ProcessSend(int argc, char *argv[]) messageInfo.mPeerPort = static_cast(value); } + if (argc == 2 || argc == 4) + { + int typePos = curArg++; + + if (strcmp(argv[typePos], "-s") == 0) + { + unsigned long value; + payloadType = kTypeAutoSize; + SuccessOrExit(error = Interpreter::ParseUnsignedLong(argv[curArg], value)); + payloadLength = static_cast(value); + } + else if (strcmp(argv[typePos], "-x") == 0) + { + payloadLength = static_cast(strlen(argv[curArg])); + payloadType = kTypeHexString; + } + else if (strcmp(argv[typePos], "-t") == 0) + { + payloadType = kTypeText; + } + } + message = otUdpNewMessage(mInterpreter.mInstance, NULL); VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - if (autoGenPayload) + switch (payloadType) { - error = WriteCharToBuffer(message, static_cast(autoGenPayloadLength)); - } - else + case kTypeText: + SuccessOrExit(error = otMessageAppend(message, argv[curArg], static_cast(strlen(argv[curArg])))); + break; + case kTypeAutoSize: + SuccessOrExit(error = WriteCharToBuffer(message, payloadLength)); + break; + case kTypeHexString: { - error = otMessageAppend(message, argv[curArg], static_cast(strlen(argv[curArg]))); + uint8_t buf[50]; + int16_t bufLen; + uint16_t conversionLength = 0; + const char *hexString = argv[curArg]; + + while (payloadLength > 0) + { + bufLen = static_cast(Interpreter::Hex2Bin(hexString, buf, sizeof(buf), true)); + + VerifyOrExit(bufLen > 0, error = OT_ERROR_INVALID_ARGS); + + conversionLength = static_cast(bufLen * 2); + + if ((payloadLength & 0x01) != 0) + { + conversionLength -= 1; + } + + hexString += conversionLength; + payloadLength -= conversionLength; + SuccessOrExit(error = otMessageAppend(message, buf, static_cast(bufLen))); + } + break; + } } - SuccessOrExit(error); error = otUdpSend(&mSocket, message, &messageInfo); diff --git a/src/cli/cli_udp.hpp b/src/cli/cli_udp.hpp index 41db927c9..1fc34a439 100644 --- a/src/cli/cli_udp.hpp +++ b/src/cli/cli_udp.hpp @@ -74,6 +74,13 @@ private: otError (UdpExample::*mCommand)(int argc, char *argv[]); }; + enum PayloadType + { + kTypeText = 0, + kTypeAutoSize = 1, + kTypeHexString = 2, + }; + otError ProcessHelp(int argc, char *argv[]); otError ProcessBind(int argc, char *argv[]); otError ProcessClose(int argc, char *argv[]); diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 7ddcd37ee..f5f08f937 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1062,7 +1062,7 @@ class Node: self._expect('Done') def udp_send(self, bytes, ipaddr, port, success=True): - cmd = 'udp send -s %d %s %d' % (bytes, ipaddr, port) + cmd = 'udp send %s %d -s %d ' % (ipaddr, port, bytes) self.send_command(cmd) if success: self._expect('Done')