UDP send example?

1,152 views
Skip to first unread message

Stuart Longland

unread,
Jul 10, 2017, 3:05:57 AM7/10/17
to openthread-users
Hi all,

I've got a problem where my device shares the one UART device with both
the serial console and polling some Modbus/RTU energy meters, and this
is proving a little tricky to debug.

My usual method would be to have the client write hexdumps of all
traffic to the console, but this doesn't work when the serial console is
tied up talking to the said meter.

Whilst pondering this, it occurred to me the Linux kernel has a feature
called `netconsole` wherein it sends console traffic over UDP to `nc`
where it can be monitored. My thinking was, I could set up `nc` on my
workstation and once the Thread device was on the network, I could tell
it the IP and port to stream logs to over 6LoWPAN to the workstation.

Long term, it'd be nice to have the devices be able to stream logs to a
syslog daemon running on the border router, but that requires more
set-up and overhead than plain `netconsole`.

On my workstation, I run `nc -6 -u -l -p 1234`, `netstat` informs me
that `nc` is listening on all IPv6 interfaces. Indeed, if I try sending
from another IPv6 host:

> RC=0 stuartl@atomos ~ $ fortune | nc -u 2001:44b8:21ac:7053:3c67:3bff:fe75:3e4a 1234
> nc: using datagram socket
> ^C

I see this:
> stuartl@vk4msl-ws:~$ nc -6 -u -l -p 1234
> This fortune is encrypted -- get your decoder rings ready!
>

So that end works.

I have a CoAP endpoint, which I can hit via Copper with a POST,
containing the IP address and port number of the `nc` instance. The
code for the actual CoAP handler is pretty simple: on receipt of a POST,
it looks for a comma in the message body, replaces that with a NULL and
passes a pointer to the next character along to `strtoul`.

With that, I'm able to parse an IP/port in the form:

2001:db8:1111:2222::abcd,1234

In my code, I have:
> static void serial_console_udp_receive(
> void *context, otMessage *msg,
> const otMessageInfo *msg_info) {
> /*
> * Extract the message content and inject that into the console buffer
> */
> (void)context;
> (void)msg_info;
>
> int length = otMessageGetLength(msg);
> uint8_t buffer[length];
> length = otMessageRead(msg, otMessageGetOffset(msg),
> buffer, length);
>
> otPlatUartReceived(buffer, length);
> }
>
> otError serial_console_init(otInstance* thread_instance,
> const char* target_ip, uint16_t target_port) {
> otError err;
> otSockAddr addr;
>
> err = otIp6AddressFromString(target_ip, &serial_console_target.addr);
> if (err)
> return err;
>
> serial_console_target.thread_instance = thread_instance;
> serial_console_target.port = target_port;
>
> memcpy(&(addr.mAddress), &serial_console_target.addr,
> sizeof(otIp6Address));
> addr.mPort = target_port;
> addr.mScopeId = 0;
>
> err = otUdpOpen(thread_instance,
> &serial_console_target.socket,
> serial_console_udp_receive, NULL);
> if (err) {
> memset(&serial_console_target, 0,
> sizeof(struct serial_console_target_t));
> return err;
> }
>
> err = otUdpConnect(&serial_console_target.socket, &addr);
> if (err) {
> otUdpClose(&serial_console_target.socket);
> memset(&serial_console_target, 0,
> sizeof(struct serial_console_target_t));
> }
> return err;
> }

and in my `_write_r` newlib stub (my OpenThread platform code calls
`write(0, …)`; so `iprintf` et all work too), I have:

> /* If there's a network console target, send a message */
> if (serial_console_target.port) {
> otError err = OT_ERROR_NONE;
> otMessageInfo msg_info;
> otMessage* msg = otUdpNewMessage(
> serial_console_target.thread_instance, true);
> if (!msg)
> err = OT_ERROR_NO_BUFS;
>
> if (err == OT_ERROR_NONE) {
> memset(&msg_info, 0, sizeof(otMessageInfo));
> memcpy(&(msg_info.mPeerAddr),
> &serial_console_target.addr,
> sizeof(otIp6Address));
> msg_info.mPeerPort = serial_console_target.port;
> msg_info.mHopLimit = 1;
>
> err = otMessageAppend(msg, (const uint8_t*)buf,
> cnt);
> }
>
> if (err == OT_ERROR_NONE)
> err = otUdpSend(&serial_console_target.socket, msg, &msg_info);
>
> if (err != OT_ERROR_NONE)
> otMessageFree(msg);
> }

In my browser, I send POST "fdde:ad00:beef:0:37ff:93ed:d6e9:26aa,1234"
(IP address is that of the `wlan0` interface created by `wpantund`) to
the /console endpoint, that calls `serial_console_init(thread_instance,
"fdde:…", 1234);`. This returns back `OT_ERROR_NONE`.

If I set a breakpoint within the above `if` block, typing a key on the
console breaks right there, and single-stepping, I see it call
`otUdpSend`, which again, returns `OT_ERROR_NONE`.

The device is acting as a "leader", with an NCP joined. I can ping it
and otherwise communicate with the device… it tells me it is sending
these UDP messages, but I don't seem to receive them. `ip6tables-save`
shows a clear firewall ruleset too.

The NCP shows no traffic in the `wpantund` logs.

Is there any other steps needed in order to send UDP datagrams to an
arbitrary IP/port?

Regards,
--
_ ___ Stuart Longland - Systems Engineer
\ /|_) | T: +61 7 3535 9619
\/ | \ | 38b Douglas Street F: +61 7 3535 9699
SYSTEMS Milton QLD 4064 http://www.vrt.com.au

Jonathan Hui

unread,
Jul 11, 2017, 12:51:41 AM7/11/17
to Stuart Longland, openthread-users
Hi Stuart,

I'm not aware of a simple UDP example, but I can see about putting one together (and investigate your issue if it reproduces).

Thanks.

--
Jonathan Hui

--
You received this message because you are subscribed to the Google Groups "openthread-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openthread-users+unsubscribe@googlegroups.com.
To post to this group, send email to openthread-users@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openthread-users/7fb2ae07-acb3-1de5-048b-8f540203bf1a%40vrt.com.au.
For more options, visit https://groups.google.com/d/optout.

Stuart Longland

unread,
Aug 1, 2017, 1:35:43 AM8/1/17
to openthre...@googlegroups.com
Hi all,

An update on this… looking at the example that was merged as part of
pull request 2027, and the notes from TuKeZ… I figured out what was wrong.

Firstly, my code:

On 10/07/17 17:05, Stuart Longland wrote:
> In my code, I have:
>> …>> err = otUdpOpen(thread_instance,
>> &serial_console_target.socket,
>> serial_console_udp_receive, NULL);
>> if (err) {
>> memset(&serial_console_target, 0,
>> sizeof(struct serial_console_target_t));
>> return err;
>> }
>>
>> err = otUdpConnect(&serial_console_target.socket, &addr);
>> if (err) {
>> otUdpClose(&serial_console_target.socket);
>> memset(&serial_console_target, 0,
>> sizeof(struct serial_console_target_t));
>> }
>> return err;
>> }

The `otUdpConnect` seems to be in error, the CLI examples don't call it
when sending packets. This was half the problem, and the example code
helped reveal that.

The other half was setting up `nc`, it seems the bind address has to be
*exact*, or it just won't work. The following procedure, works:

First, figure out the IP address of `wpan0`:
> stuartl@vk4msl-ws:~/vrt/projects/metermaster/drivers/wideskyhub/src$ ip -6 addr show dev wpan0
> 39: wpan0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 state UNKNOWN qlen 500
> inet6 fdde:ad00:beef:0:5801:1005:202a:da89/64 scope global
> valid_lft forever preferred_lft forever
> inet6 fe80::1425:ac0:ac32:6f4e/64 scope link
> valid_lft forever preferred_lft forever
> inet6 fe80::c01d:9433:6be3:9afd/64 scope link flags 800
> valid_lft forever preferred_lft forever

Now start `nc`, specifying that address as the source address.
> stuartl@vk4msl-ws:~/vrt/projects/metermaster/drivers/wideskyhub/src$ nc -u -6 -l -p 1234 -s fdde:ad00:beef:0:5801:1005:202a:da89

Having done that, you should start seeing things when you trigger the
device. I found that as soon as I hit ENTER on my serial terminal, the
prompt showed up on my network console, and I could then interact with
the end device over 6LoWPAN:

> stuartl@vk4msl-ws:~/vrt/projects/metermaster/drivers/wideskyhub/src$ nc -u -6 -l -p 1234 -s fdde:ad00:beef:0:5801:1005:202a:da89
> nc: using datagram socket

The `nc` appears the moment the first message is received. Anything
typed prior to this point may be sent. The following is me interacting
with the end device via `nc`.

>
>> version
> version
> OPENTHREAD/0.01.00; WIDESKYHUB; Aug 1 2017 12:52:04
> Done
>> ipaddr
> ipaddr
> fdde:ad00:beef:0:0:ff:fe00:fc00
> fdde:ad00:beef:0:0:ff:fe00:1800
> fe80:0:0:0:f853:71bb:b747:8428
> fdde:ad00:beef:0:616e:fe43:24ca:cc5c
> Done
>> leaderdata
> leaderdata
> Partition ID: 1639054763
> Weighting: 64
> Data Version: 117
> Stable Data Version: 248
> Leader Router ID: 6
> Done
>> state
> state
> leader
> Done

Jonathan Hui

unread,
Aug 2, 2017, 1:05:52 PM8/2/17
to Stuart Longland, openthread-users
Great to hear you got things working.  Thanks for the follow-up.

--
Jonathan Hui

--
You received this message because you are subscribed to the Google Groups "openthread-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openthread-users+unsubscribe@googlegroups.com.
To post to this group, send email to openthread-users@googlegroups.com.

Jeremy Ellis

unread,
Oct 3, 2019, 2:05:10 AM10/3/19
to openthread-users

An example UDP 

udp send fdde:ad00:beef:0:bb1:ebc6:ad10:f33 1234 hello


This works for me when sending to a specific node, however I can't seem to find an example of
how to send a message multicast to every node in the openthread. Any suggestions?

Jonathan Hui

unread,
Oct 3, 2019, 12:50:02 PM10/3/19
to Jeremy Ellis, openthread-users
Thread supports IPv6 multicast for communicating sending a message to multiple devices. You can learn more about the IPv6 Address architecture and how it applies to Thread in our Thread Primer - IPv6 Addressing guide.

For a specific example, you can send to the IPv6 link-local all nodes with:
  • udp send ff02::1 1234 hello
Hope that helps.

--
Jonathan Hui

--
You received this message because you are subscribed to the Google Groups "openthread-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openthread-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openthread-users/80c0c574-84de-413b-a2d0-6825cccebba6%40googlegroups.com.

Jeremy Ellis

unread,
Oct 4, 2019, 12:43:30 AM10/4/19
to openthread-users
Thanks Jonathan:

That makes a lot of sense. I was doing ping ff02::1 but did not see an example for udp send ff02::1 1234 hello

Second part to this question. The actual message, can it be in JSON format or object, meaning what symbols are allowed and what isn't. Can I send:

udp send ff02::1 1234 {"name":"fred","age":"40"}






On Thursday, October 3, 2019 at 9:50:02 AM UTC-7, Jonathan Hui wrote:
Thread supports IPv6 multicast for communicating sending a message to multiple devices. You can learn more about the IPv6 Address architecture and how it applies to Thread in our Thread Primer - IPv6 Addressing guide.

For a specific example, you can send to the IPv6 link-local all nodes with:
  • udp send ff02::1 1234 hello
Hope that helps.

--
Jonathan Hui

On Wed, Oct 2, 2019 at 11:05 PM Jeremy Ellis <keyfre...@gmail.com> wrote:

An example UDP 

udp send fdde:ad00:beef:0:bb1:ebc6:ad10:f33 1234 hello


This works for me when sending to a specific node, however I can't seem to find an example of
how to send a message multicast to every node in the openthread. Any suggestions?

--
You received this message because you are subscribed to the Google Groups "openthread-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openthre...@googlegroups.com.

Jonathan Hui

unread,
Oct 4, 2019, 12:07:05 PM10/4/19
to Jeremy Ellis, openthread-users
OpenThread's CLI uses a simple command line parser that treats any space character as the argument delimiter.

As a result, `udp send ff02::1 1234 {"name":"fred","age":"40"}` should work since the message payload does not contain any spaces and will be treated as a single argument.

I have tested it myself and it seems to work fine.

Node A:

> udp open                                
Done

> udp send ff02::1 1234 {"name":"fred","age":"40"}
Done

Node B:

> udp open
Done
> udp bind :: 1234
Done
26 bytes from fe80:0:0:0:b459:6368:a779:b6df 49154 {"name":"fred","age":"40"}


--
Jonathan Hui

To unsubscribe from this group and stop receiving emails from it, send an email to openthread-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openthread-users/78120450-c2f8-4e64-b4ad-76e170a17461%40googlegroups.com.

Jeremy Ellis

unread,
Oct 4, 2019, 1:35:36 PM10/4/19
to openthread-users
Thank you so much for the help Jonathan.

In your examples I feel that the 1234
Can be auto set in my startup file.

What is it called? 
Do you know any links to setting it.
I thought it was the PanID.

Jonathan Hui

unread,
Oct 4, 2019, 1:38:06 PM10/4/19
to Jeremy Ellis, openthread-users
The "1234" in the example is the UDP port. The receiver needs to bind to that port. The sender needs to specify that port.

--
Jonathan Hui

To unsubscribe from this group and stop receiving emails from it, send an email to openthread-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openthread-users/a76c3e59-3317-4265-829b-29183535a6e8%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages