[udp] add cli-based example for UDP APIs (#2027)

This commit is contained in:
Jonathan Hui
2017-07-26 12:14:44 -07:00
committed by GitHub
parent 4dc80ee357
commit f88c537c6c
13 changed files with 484 additions and 10 deletions
@@ -10,14 +10,14 @@
<ClCompile Include="..\..\src\cli\cli.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_uart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_dataset.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_instance.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_uart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+1 -1
View File
@@ -59,7 +59,7 @@
<ClCompile Include="..\..\src\cli\cli.cpp" />
<ClCompile Include="..\..\src\cli\cli_dataset.cpp" />
<ClCompile Include="..\..\src\cli\cli_uart.cpp" />
<ClCompile Include="..\..\src\cli\cli_udp.cpp" />
<ClCompile Include="..\..\src\cli\cli_udp_example.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -10,14 +10,14 @@
<ClCompile Include="..\..\src\cli\cli.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_udp.cpp">
<ClCompile Include="..\..\src\cli\cli_dataset.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_uart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cli\cli_dataset.cpp">
<ClCompile Include="..\..\src\cli\cli_udp_example.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</ItemGroup>
</Project>
+1
View File
@@ -72,6 +72,7 @@
<ClCompile Include="..\..\src\core\api\tasklet_api.cpp" />
<ClCompile Include="..\..\src\core\api\thread_api.cpp" />
<ClCompile Include="..\..\src\core\api\thread_ftd_api.cpp" />
<ClCompile Include="..\..\src\core\api\udp_api.cpp" />
<ClCompile Include="..\..\src\core\coap\coap.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_secure.cpp" />
@@ -117,6 +117,9 @@
<ClCompile Include="..\..\src\core\api\thread_ftd_api.cpp">
<Filter>Source Files\api</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\api\udp_api.cpp">
<Filter>Source Files\api</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\coap\coap.cpp">
<Filter>Source Files\coap</Filter>
</ClCompile>
@@ -81,6 +81,7 @@
<ClCompile Include="..\..\src\core\api\tasklet_api.cpp" />
<ClCompile Include="..\..\src\core\api\thread_api.cpp" />
<ClCompile Include="..\..\src\core\api\thread_ftd_api.cpp" />
<ClCompile Include="..\..\src\core\api\udp_api.cpp" />
<ClCompile Include="..\..\src\core\coap\coap.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_secure.cpp" />
@@ -117,6 +117,9 @@
<ClCompile Include="..\..\src\core\api\thread_ftd_api.cpp">
<Filter>Source Files\api</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\api\udp_api.cpp">
<Filter>Source Files\api</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\coap\coap.cpp">
<Filter>Source Files\coap</Filter>
</ClCompile>
+2 -2
View File
@@ -137,7 +137,7 @@ SOURCES_COMMON = \
cli_dataset.cpp \
cli_uart.cpp \
cli_coap.cpp \
cli_udp.cpp \
cli_udp_example.cpp \
$(NULL)
libopenthread_cli_ftd_a_SOURCES = \
@@ -155,7 +155,7 @@ noinst_HEADERS = \
cli_uart.hpp \
cli_server.hpp \
cli_coap.hpp \
cli_udp.hpp \
cli_udp_example.hpp \
$(NULL)
if OPENTHREAD_BUILD_COVERAGE
+126
View File
@@ -0,0 +1,126 @@
# OpenThread CLI - UDP Example
The OpenThread UDP APIs may be invoked via the OpenThread CLI.
## Quick Start
### Form Network
Form a network with at least two devices.
### Node 1
On node 1, open and bind the example UDP socket.
```bash
> udp open
> udp bind :: 1234
```
The `::` specifies the IPv6 Unspecified Address.
### Node 2
On node 2, open the example UDP socket and send a simple message.
```bash
> udp open
> udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 hello
```
### Result
On node 1, you should see a print out similar to below:
```bash
5 bytes from fdde:ad00:beef:0:dac3:6792:e2e:90d8: hello
```
## Command List
* [help](#help)
* [bind](#bind-ip-port)
* [close](#close)
* [connect](#connect-ip-port)
* [open](#open)
* [send](#send-ip-port-message)
## Command Details
### help
List the UDP CLI commands.
```bash
> udp help
help
bind
close
connect
open
send
Done
```
### bind \<ip\> \<port\>
Assigns a name (i.e. IPv6 address and port) to the example socket.
* ip: the IPv6 address or the unspecified IPv6 address (`::`).
* port: the UDP port
```bash
> udp bind :: 1234
Done
```
### close
Closes the example socket.
```bash
> udp close
Done
```
### connect \<ip\> \<port\>
Specifies the peer with which the socket is to be associated.
* ip: the peer's IPv6 address.
* port: the peer's UDP port.
```bash
> udp connect fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234
Done
```
### open
Opens the example socket.
```bash
> udp open
Done
```
### send \<ip\> \<port\> \<message\>
Send a UDP message.
* ip: the IPv6 destination address.
* port: the UDP destination port.
* message: the message to send.
```bash
> udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 hello
```
### send \<message\>
Send a UDP message on a connected socket.
* message: the message to send.
```bash
> udp send hello
```
+13
View File
@@ -201,6 +201,9 @@ const struct Command Interpreter::sCommands[] =
{ "state", &Interpreter::ProcessState },
{ "thread", &Interpreter::ProcessThread },
{ "txpowermax", &Interpreter::ProcessTxPowerMax },
#ifndef OTDLL
{ "udp", &Interpreter::ProcessUdp },
#endif
{ "version", &Interpreter::ProcessVersion },
};
@@ -248,6 +251,7 @@ Interpreter::Interpreter(otInstance *aInstance):
#if OPENTHREAD_ENABLE_DNS_CLIENT
mResolvingInProgress(0),
#endif
mUdp(*this),
#endif
mInstance(aInstance)
{
@@ -2487,6 +2491,15 @@ void Interpreter::ProcessVersion(int argc, char *argv[])
OT_UNUSED_VARIABLE(argv);
}
#ifndef OTDLL
void Interpreter::ProcessUdp(int argc, char *argv[])
{
otError error;
error = mUdp.Process(argc, argv);
AppendResult(error);
}
#endif
#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
void Interpreter::ProcessCommissioner(int argc, char *argv[])
+8
View File
@@ -43,6 +43,7 @@
#include <openthread/udp.h>
#include "cli/cli_server.hpp"
#include "cli/cli_udp_example.hpp"
#if OPENTHREAD_ENABLE_APPLICATION_COAP
#include <coap/coap_header.hpp>
@@ -93,6 +94,7 @@ struct Command
class Interpreter
{
friend class Coap;
friend class Udp;
public:
@@ -287,6 +289,10 @@ private:
void ProcessInstance(int argc, char *argv[]);
#endif
#ifndef OTDLL
void ProcessUdp(int argc, char *argv[]);
#endif
#ifndef OTDLL
static void s_HandleIcmpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader);
@@ -383,6 +389,8 @@ private:
char mResolvingHostname[OT_DNS_MAX_HOSTNAME_LENGTH];
#endif
Udp mUdp;
#endif
otInstance *mInstance;
+224
View File
@@ -0,0 +1,224 @@
/*
* Copyright (c) 2017, 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 a simple CLI for the CoAP service.
*/
#include "cli_udp_example.hpp"
#include <openthread/config.h>
#include <openthread/message.h>
#include <openthread/udp.h>
#include "cli/cli.hpp"
#include "common/encoding.hpp"
using ot::Encoding::BigEndian::HostSwap16;
namespace ot {
namespace Cli {
const struct Udp::Command Udp::sCommands[] =
{
{ "help", &Udp::ProcessHelp },
{ "bind", &Udp::ProcessBind },
{ "close", &Udp::ProcessClose },
{ "connect", &Udp::ProcessConnect },
{ "open", &Udp::ProcessOpen },
{ "send", &Udp::ProcessSend }
};
otError Udp::ProcessHelp(int argc, char *argv[])
{
for (unsigned int i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
{
mInterpreter.mServer->OutputFormat("%s\r\n", sCommands[i].mName);
}
OT_UNUSED_VARIABLE(argc);
OT_UNUSED_VARIABLE(argv);
return OT_ERROR_NONE;
}
otError Udp::ProcessBind(int argc, char *argv[])
{
otError error;
otSockAddr sockaddr;
long value;
memset(&sockaddr, 0, sizeof(sockaddr));
VerifyOrExit(argc == 2, error = OT_ERROR_PARSE);
error = otIp6AddressFromString(argv[1], &sockaddr.mAddress);
SuccessOrExit(error);
error = Interpreter::ParseLong(argv[2], value);
SuccessOrExit(error);
sockaddr.mPort = static_cast<uint16_t>(value);
error = otUdpBind(&mSocket, &sockaddr);
exit:
return error;
}
otError Udp::ProcessConnect(int argc, char *argv[])
{
otError error;
otSockAddr sockaddr;
long value;
memset(&sockaddr, 0, sizeof(sockaddr));
VerifyOrExit(argc == 2, error = OT_ERROR_PARSE);
error = otIp6AddressFromString(argv[1], &sockaddr.mAddress);
SuccessOrExit(error);
error = Interpreter::ParseLong(argv[2], value);
SuccessOrExit(error);
sockaddr.mPort = static_cast<uint16_t>(value);
error = otUdpConnect(&mSocket, &sockaddr);
exit:
return error;
}
otError Udp::ProcessClose(int argc, char *argv[])
{
OT_UNUSED_VARIABLE(argc);
OT_UNUSED_VARIABLE(argv);
return otUdpClose(&mSocket);
}
otError Udp::ProcessOpen(int argc, char *argv[])
{
OT_UNUSED_VARIABLE(argc);
OT_UNUSED_VARIABLE(argv);
return otUdpOpen(mInterpreter.mInstance, &mSocket, HandleUdpReceive, this);
}
otError Udp::ProcessSend(int argc, char *argv[])
{
otError error;
otMessageInfo messageInfo;
otMessage *message = NULL;
int curArg = 1;
memset(&messageInfo, 0, sizeof(messageInfo));
VerifyOrExit(argc == 1 || argc == 3, error = OT_ERROR_PARSE);
if (argc == 3)
{
long value;
error = otIp6AddressFromString(argv[curArg++], &messageInfo.mPeerAddr);
SuccessOrExit(error);
error = Interpreter::ParseLong(argv[curArg++], value);
SuccessOrExit(error);
messageInfo.mPeerPort = static_cast<uint16_t>(value);
}
message = otUdpNewMessage(mInterpreter.mInstance, true);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
error = otMessageAppend(message, argv[curArg], static_cast<uint16_t>(strlen(argv[3])));
SuccessOrExit(error);
error = otUdpSend(&mSocket, message, &messageInfo);
exit:
if (error != OT_ERROR_NONE && message != NULL)
{
otMessageFree(message);
}
return error;
}
otError Udp::Process(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
for (size_t i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
{
if (strcmp(argv[0], sCommands[i].mName) == 0)
{
(this->*sCommands[i].mCommand)(argc, argv);
ExitNow();
}
}
error = OT_ERROR_PARSE;
exit:
return error;
}
void Udp::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
static_cast<Udp *>(aContext)->HandleUdpReceive(aMessage, aMessageInfo);
}
void Udp::HandleUdpReceive(otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
uint8_t buf[1500];
int length;
mInterpreter.mServer->OutputFormat("%d bytes from ", otMessageGetLength(aMessage) - otMessageGetOffset(aMessage));
mInterpreter.mServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x: ",
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[0]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[1]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[2]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[3]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[4]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[5]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[6]),
HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[7]));
length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
buf[length] = '\0';
mInterpreter.mServer->OutputFormat("%s\r\n", buf);
}
} // namespace Cli
} // namespace ot
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2017, 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 a simple CLI CoAP server and client.
*/
#ifndef CLI_UDP_EXAMPLE_HPP_
#define CLI_UDP_EXAMPLE_HPP_
#include <openthread/udp.h>
#include <openthread/types.h>
namespace ot {
namespace Cli {
class Interpreter;
/**
* This class implements a CLI-based UDP example.
*
*/
class Udp
{
public:
/**
* Constructor
*
* @param[in] aInterpreter The CLI interpreter.
*
*/
Udp(Interpreter &aInterpreter): mInterpreter(aInterpreter) { }
/**
* This method interprets a list of CLI arguments.
*
* @param[in] argc The number of elements in argv.
* @param[in] argv A pointer to an array of command line arguments.
*
*/
otError Process(int argc, char *argv[]);
private:
struct Command
{
const char *mName;
otError(Udp::*mCommand)(int argc, char *argv[]);
};
otError ProcessHelp(int argc, char *argv[]);
otError ProcessBind(int argc, char *argv[]);
otError ProcessClose(int argc, char *argv[]);
otError ProcessConnect(int argc, char *argv[]);
otError ProcessOpen(int argc, char *argv[]);
otError ProcessSend(int argc, char *argv[]);
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleUdpReceive(otMessage *aMessage, const otMessageInfo *aMessageInfo);
static const Command sCommands[];
Interpreter &mInterpreter;
otUdpSocket mSocket;
};
} // namespace Cli
} // namespace ot
#endif // CLI_UDP_EXAMPLE_HPP_