UDP sock API¶
Sock submodule for UDP.
How To Use¶
First you need to a module that implements this API in your application’s Makefile. For example the implementation for GNRC is called gnrc_sock_udp
.
A Simple UDP Echo Server¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <stdio.h>
#include "net/sock/udp.h"
uint8_t buf[128];
int main(void)
{
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 12345;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
while (1) {
sock_udp_ep_t remote;
ssize_t res;
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_udp_send(&sock, buf, res, &remote) < 0) {
puts("Error sending reply");
}
}
}
return 0;
}
|
Above you see a simple UDP echo server. Don’t forget to also the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default
for Generic (GNRC) network stack GNRC) and at least one network device.
After including the header file for UDP sock, we create some buffer space buf
to store the data received by the server:
1 2 3 | #include "net/sock/udp.h"
uint8_t buf[128];
|
To be able to listen for incoming packets we bind the sock
by setting a local end point with a port (12345
in this case).
We then proceed to create the sock
. It is bound to local
and thus listens for UDP packets with udp.h::udp_hdr_t::dst_port
12345
. Since we don’t need any further configuration we set the flags to 0. In case of an error we stop the program:
1 2 3 4 5 6 7 8 9 | sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 12345;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
|
The application then waits indefinitely for an incoming message in buf
from remote
. If we want to timeout this wait period we could alternatively set the timeout
parameter of sock/udp.h::sock_udp_recv()
to a value != sock.h::SOCK_NO_TIMEOUT
. If an error occurs on receive we just ignore it and continue looping.
If we receive a message we use its remote
to reply. In case of an error on send we print an according message:
1 2 3 4 5 6 7 8 9 10 11 12 | while (1) {
sock_udp_ep_t remote;
ssize_t res;
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_udp_send(&sock, buf, res, &remote) < 0) {
puts("Error sending reply");
}
}
}
|
A Simple UDP Echo Client¶
There are two kinds of clients. Those that do expect a reply and those who don’t. A client that does not require a reply is very simple to implement in one line:
1 | res = sock_udp_send(NULL, data, data_len, &remote);
|
With data
being the data sent, data_len
the length of data
and remote
the remote end point the packet that is is to be sent.
To see some other capabilities we look at a more complex example in form of the counter of the echo server above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include <stdio.h>
#include "net/af.h"
#include "net/protnum.h"
#include "net/ipv6/addr.h"
#include "net/sock/udp.h"
#include "xtimer.h"
uint8_t buf[7];
int main(void)
{
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 0xabcd;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
while (1) {
sock_udp_ep_t remote = { .family = AF_INET6 };
ssize_t res;
remote.port = 12345;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
sock_udp_close(&sock);
return 1;
}
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
NULL)) < 0) {
if (res == -ETIMEDOUT) {
puts("Timed out");
}
else {
puts("Error receiving message");
}
}
else {
printf("Received message: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
printf("\"\n");
}
xtimer_sleep(1);
}
return 0;
}
|
Again: Don’t forget to also the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default
for GNRC) and at least one network device.
We first create again a sock
with a local end point bound to any IPv6 address and some port. Note that we also could specify the remote here and not use it with sock/udp.h::sock_udp_send()
.
1 2 3 4 5 6 7 8 9 | sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 0xabcd;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
|
We then create a remote end point with the link-local all nodes multicast address (ff02::1
) and port 12345
and send a “Hello!” message to that end point.
1 2 3 4 5 6 7 8 9 10 11 | sock_udp_ep_t remote = { .family = AF_INET6 };
ssize_t res;
remote.port = 12345;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
sock_udp_close(&sock);
return 1;
}
|
We then wait a second for a reply and print it when it is received.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
NULL)) < 0) {
if (res == -ETIMEDOUT) {
puts("Timed out");
}
else {
puts("Error receiving message");
}
}
else {
printf("Received message: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
printf("\"\n");
}
|
Finally, we wait a second before sending out the next “Hello!” with xtimer_sleep(1)
.
A Simple UDP Echo Server¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <stdio.h>
#include "net/sock/udp.h"
uint8_t buf[128];
int main(void)
{
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 12345;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
while (1) {
sock_udp_ep_t remote;
ssize_t res;
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_udp_send(&sock, buf, res, &remote) < 0) {
puts("Error sending reply");
}
}
}
return 0;
}
|
Above you see a simple UDP echo server. Don’t forget to also the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default
for Generic (GNRC) network stack GNRC) and at least one network device.
After including the header file for UDP sock, we create some buffer space buf
to store the data received by the server:
1 2 3 | #include "net/sock/udp.h"
uint8_t buf[128];
|
To be able to listen for incoming packets we bind the sock
by setting a local end point with a port (12345
in this case).
We then proceed to create the sock
. It is bound to local
and thus listens for UDP packets with udp.h::udp_hdr_t::dst_port
12345
. Since we don’t need any further configuration we set the flags to 0. In case of an error we stop the program:
1 2 3 4 5 6 7 8 9 | sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 12345;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
|
The application then waits indefinitely for an incoming message in buf
from remote
. If we want to timeout this wait period we could alternatively set the timeout
parameter of sock/udp.h::sock_udp_recv()
to a value != sock.h::SOCK_NO_TIMEOUT
. If an error occurs on receive we just ignore it and continue looping.
If we receive a message we use its remote
to reply. In case of an error on send we print an according message:
1 2 3 4 5 6 7 8 9 10 11 12 | while (1) {
sock_udp_ep_t remote;
ssize_t res;
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_udp_send(&sock, buf, res, &remote) < 0) {
puts("Error sending reply");
}
}
}
|
A Simple UDP Echo Client¶
There are two kinds of clients. Those that do expect a reply and those who don’t. A client that does not require a reply is very simple to implement in one line:
1 | res = sock_udp_send(NULL, data, data_len, &remote);
|
With data
being the data sent, data_len
the length of data
and remote
the remote end point the packet that is is to be sent.
To see some other capabilities we look at a more complex example in form of the counter of the echo server above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include <stdio.h>
#include "net/af.h"
#include "net/protnum.h"
#include "net/ipv6/addr.h"
#include "net/sock/udp.h"
#include "xtimer.h"
uint8_t buf[7];
int main(void)
{
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 0xabcd;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
while (1) {
sock_udp_ep_t remote = { .family = AF_INET6 };
ssize_t res;
remote.port = 12345;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
sock_udp_close(&sock);
return 1;
}
if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
NULL)) < 0) {
if (res == -ETIMEDOUT) {
puts("Timed out");
}
else {
puts("Error receiving message");
}
}
else {
printf("Received message: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
printf("\"\n");
}
xtimer_sleep(1);
}
return 0;
}
|
Again: Don’t forget to also the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default
for GNRC) and at least one network device.
We first create again a sock
with a local end point bound to any IPv6 address and some port. Note that we also could specify the remote here and not use it with sock/udp.h::sock_udp_send()
.
1 2 3 4 5 6 7 8 9 | sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
sock_udp_t sock;
local.port = 0xabcd;
if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return 1;
}
|
We then create a remote end point with the link-local all nodes multicast address (ff02::1
) and port 12345
and send a “Hello!” message to that end point.
1 2 3 4 5 6 7 8 9 10 11 | sock_udp_ep_t remote = { .family = AF_INET6 };
ssize_t res;
remote.port = 12345;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
sock_udp_close(&sock);
return 1;
}
|
We then wait a second for a reply and print it when it is received.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
NULL)) < 0) {
if (res == -ETIMEDOUT) {
puts("Timed out");
}
else {
puts("Error receiving message");
}
}
else {
printf("Received message: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
printf("\"\n");
}
|
Finally, we wait a second before sending out the next “Hello!” with xtimer_sleep(1)
.
-
struct _sock_tl_ep
sock_udp_ep_t
¶ An end point for a UDP sock object.
-
struct sock_udp
sock_udp_t
¶ Type for a UDP sock object.
Note
API implementors:
struct sock_udp
needs to be defined by implementation-specificsock_types.h
.
-
int
sock_udp_create
(sock/udp.h::sock_udp_t
* sock, constsock/udp.h::sock_udp_ep_t
* local, constsock/udp.h::sock_udp_ep_t
* remote, uint16_t flags)¶ Creates a new UDP sock object.
Parameters
sock: The resulting sock object. local: Local end point for the sock object. May be NULL. sock.h::_sock_tl_ep::netif
must either besock.h::SOCK_ADDR_ANY_NETIF
or equal tosock.h::_sock_tl_ep::netif
ofremote
ifremote != NULL
. If NULLsock/udp.h::sock_udp_send()
may bind implicitly.sock.h::_sock_tl_ep::port
may also be 0 to bind thesock
to an ephemeral port.remote: Remote end point for the sock object. May be NULL
but then theremote
parameter ofsock/udp.h::sock_udp_send()
may not beNULL
or it will always error with return value -ENOTCONN.sock.h::_sock_tl_ep::port
must not be 0 ifremote != NULL
.sock.h::_sock_tl_ep::netif
must either besock.h::SOCK_ADDR_ANY_NETIF
or equal tosock.h::_sock_tl_ep::netif
oflocal
iflocal != NULL
.flags: Flags for the sock object. See also . May be 0. Return values
- 0 on success.
- -EADDRINUSE, if
local != NULL
andlocal
is already used elsewhere or iflocal->port == 0
but the pool of ephemeral ports is depleted - -EAFNOSUPPORT, if
local != NULL
orremote != NULL
andsock.h::_sock_tl_ep::family
oflocal
orremote
is not supported. - -EINVAL, if
sock.h::_sock_tl_ep::addr
ofremote
is an invalid address. - -EINVAL, if
sock.h::_sock_tl_ep::netif
oflocal
orremote
are not a valid interfaces or contradict each other (i.e. `(local->netif != remote->netif) && ((local->netif != SOCK_ADDR_ANY_NETIF) || (remote->netif != SOCK_ADDR_ANY_NETIF))if neither is
NULL). @return -ENOMEM, if not enough resources can be provided for
sock` to be created.
-
void
sock_udp_close
(sock/udp.h::sock_udp_t
* sock)¶ Closes a UDP sock object.
Parameters
sock: A UDP sock object.
-
int
sock_udp_get_local
(sock/udp.h::sock_udp_t
* sock,sock/udp.h::sock_udp_ep_t
* ep)¶ Gets the local end point of a UDP sock object.
Parameters
sock: A UDP sock object. ep: The local end point. Return values
- 0 on success.
- -EADDRNOTAVAIL, when
sock
has no local end point.
-
int
sock_udp_get_remote
(sock/udp.h::sock_udp_t
* sock,sock/udp.h::sock_udp_ep_t
* ep)¶ Gets the remote end point of a UDP sock object.
Parameters
sock: A UDP sock object. ep: The remote end point. Return values
- 0 on success.
- -ENOTCONN, when
sock
has no remote end point bound to it.
-
msp430_types.h::ssize_t
sock_udp_recv
(sock/udp.h::sock_udp_t
* sock, void * data,msp430_types.h::size_t
max_len, uint32_t timeout,sock/udp.h::sock_udp_ep_t
* remote)¶ Receives a UDP message from a remote end point.
Parameters
sock: A raw IPv4/IPv6 sock object. data: Pointer where the received data should be stored. max_len: Maximum space available at data
.timeout: Timeout for receive in microseconds. If 0 and no data is available, the function returns immediately. May be sock.h::SOCK_NO_TIMEOUT
for no timeout (wait until data is available).remote: Remote end point of the received data. May be NULL
, if it is not required by the application.Note
Function blocks if no packet is currently waiting.
Return values
- The number of bytes received on success.
- 0, if no received data is available, but everything is in order.
- -EADDRNOTAVAIL, if local of
sock
is not given. - -EAGAIN, if
timeout
is0
and no data is available. - -EINVAL, if
remote
is invalid orsock
is not properly initialized (or closed whilesock/udp.h::sock_udp_recv()
blocks). - -ENOBUFS, if buffer space is not large enough to store received data.
- -ENOMEM, if no memory was available to receive
data
. - -EPROTO, if source address of received packet did not equal the remote of
sock
. - -ETIMEDOUT, if
timeout
expired.
-
msp430_types.h::ssize_t
sock_udp_send
(sock/udp.h::sock_udp_t
* sock, const void * data,msp430_types.h::size_t
len, constsock/udp.h::sock_udp_ep_t
* remote)¶ Sends a UDP message to remote end point.
Parameters
sock: A raw IPv4/IPv6 sock object. May be NULL
. A sensible local end point should be selected by the implementation in that case.data: Pointer where the received data should be stored. May be NULL
iflen == 0
.len: Maximum space available at data
.remote: Remote end point for the sent data. May be NULL
, ifsock
has a remote end point.sock.h::_sock_tl_ep::family
may be AF_UNSPEC, if local end point ofsock
provides this information.sock.h::_sock_tl_ep::port
may not be 0.Return values
- The number of bytes sent on success.
- -EADDRINUSE, if
sock
has no local end-point or wasNULL
and the pool of available ephemeral ports is depleted. - -EAFNOSUPPORT, if
remote != NULL
andsock.h::_sock_tl_ep::family
ofremote
is != AF_UNSPEC and not supported. - -EHOSTUNREACH, if
remote
or remote end point ofsock
is not reachable. - -EINVAL, if
sock.h::_sock_tl_ep::addr
ofremote
is an invalid address. - -EINVAL, if
sock.h::_sock_tl_ep::netif
ofremote
is not a valid interface or contradicts the given local interface (i.e. neither the local end point ofsock
nor remote are assigned toSOCK_ADDR_ANY_NETIF
but are nevertheless different. - -EINVAL, if
sock.h::_sock_tl_ep::port
ofremote
is 0. - -ENOMEM, if no memory was available to send
data
. - -ENOTCONN, if
remote == NULL
, butsock
has no remote end point.