UDP sock API

Sock submodule for UDP. More...

Detailed Description

Sock submodule for UDP.

How To Use

First you need to include 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

#include <stdio.h>
#include "net/sock/udp.h"
uint8_t buf[128];
int main(void)
{
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 include 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:

#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 destination 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:

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_recv() to a value != 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:

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:

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:

#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_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;
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
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");
}
}
return 0;
}

Again: Don't forget to also include 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_send().

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.

sock_udp_ep_t remote = { .family = AF_INET6 };
ssize_t res;
remote.port = 12345;
if (sock_udp_send(&sock, "Hello!", sizeof("Hello!"), &remote) < 0) {
puts("Error sending message");
return 1;
}

We then wait a second for a reply and print it when it is received.

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).

Files

file  sock/udp.h
 UDP sock definitions.
 

Typedefs

typedef struct _sock_tl_ep sock_udp_ep_t
 An end point for a UDP sock object.
 
typedef struct sock_udp sock_udp_t
 Type for a UDP sock object. More...
 

Functions

int sock_udp_create (sock_udp_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote, uint16_t flags)
 Creates a new UDP sock object. More...
 
void sock_udp_close (sock_udp_t *sock)
 Closes a UDP sock object. More...
 
int sock_udp_get_local (sock_udp_t *sock, sock_udp_ep_t *ep)
 Gets the local end point of a UDP sock object. More...
 
int sock_udp_get_remote (sock_udp_t *sock, sock_udp_ep_t *ep)
 Gets the remote end point of a UDP sock object. More...
 
ssize_t sock_udp_recv (sock_udp_t *sock, void *data, size_t max_len, uint32_t timeout, sock_udp_ep_t *remote)
 Receives a UDP message from a remote end point. More...
 
ssize_t sock_udp_send (sock_udp_t *sock, const void *data, size_t len, const sock_udp_ep_t *remote)
 Sends a UDP message to remote end point. More...
 

Typedef Documentation

◆ sock_udp_t

typedef struct sock_udp sock_udp_t

Type for a UDP sock object.

Note
API implementors: struct sock_udp needs to be defined by implementation-specific sock_types.h.

Definition at line 290 of file sock/udp.h.

Function Documentation

◆ sock_udp_close()

void sock_udp_close ( sock_udp_t sock)

Closes a UDP sock object.

Precondition
(sock != NULL)
Parameters
[in]sockA UDP sock object.

◆ sock_udp_create()

int sock_udp_create ( sock_udp_t sock,
const sock_udp_ep_t local,
const sock_udp_ep_t remote,
uint16_t  flags 
)

Creates a new UDP sock object.

Precondition
(sock != NULL)
(local == NULL) || (local->port != 0)
(remote == NULL) || (remote->port != 0)
Parameters
[out]sockThe resulting sock object.
[in]localLocal end point for the sock object. May be NULL. sock_udp_ep_t::port may not be 0 if local != NULL. sock_udp_ep_t::netif must either be SOCK_ADDR_ANY_NETIF or equal to sock_udp_ep_t::netif of remote if remote != NULL. If NULL sock_udp_send() may bind implicitly.
[in]remoteRemote end point for the sock object. May be NULL but then the remote parameter of sock_udp_send() may not be NULL and or it will always error with return value -ENOTCONN. sock_udp_ep_t::port may not be 0 if remote != NULL. sock_udp_ep_t::netif must either be SOCK_ADDR_ANY_NETIF or equal to sock_udp_ep_t::netif of local if local != NULL.
[in]flagsFlags for the sock object. See also sock flags. May be 0.
Returns
0 on success.
-EADDRINUSE, if local != NULL and local is already used elsewhere
-EAFNOSUPPORT, if local != NULL or remote != NULL and sock_udp_ep_t::family of local or remote is not supported.
-EINVAL, if sock_udp_ep_t::addr of remote is an invalid address.
-EINVAL, if sock_udp_ep_t::netif of local or remote 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 isNULL). @return -ENOMEM, if not enough resources can be provided forsock` to be created.

◆ sock_udp_get_local()

int sock_udp_get_local ( sock_udp_t sock,
sock_udp_ep_t ep 
)

Gets the local end point of a UDP sock object.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]sockA UDP sock object.
[out]epThe local end point.
Returns
0 on success.
-EADDRNOTAVAIL, when sock has no local end point.

◆ sock_udp_get_remote()

int sock_udp_get_remote ( sock_udp_t sock,
sock_udp_ep_t ep 
)

Gets the remote end point of a UDP sock object.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]sockA UDP sock object.
[out]epThe remote end point.
Returns
0 on success.
-ENOTCONN, when sock has no remote end point bound to it.

◆ sock_udp_recv()

ssize_t sock_udp_recv ( sock_udp_t sock,
void *  data,
size_t  max_len,
uint32_t  timeout,
sock_udp_ep_t remote 
)

Receives a UDP message from a remote end point.

Precondition
(sock != NULL) && (data != NULL) && (max_len > 0)
Parameters
[in]sockA raw IPv4/IPv6 sock object.
[out]dataPointer where the received data should be stored.
[in]max_lenMaximum space available at data.
[in]timeoutTimeout for receive in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT for no timeout (wait until data is available).
[out]remoteRemote 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.
Returns
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 is 0 and no data is available.
-EINVAL, if remote is invalid or sock is not properly initialized (or closed while 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.

◆ sock_udp_send()

ssize_t sock_udp_send ( sock_udp_t sock,
const void *  data,
size_t  len,
const sock_udp_ep_t remote 
)

Sends a UDP message to remote end point.

Precondition
((sock != NULL || remote != NULL)) && (if (len != 0): (data != NULL))
Parameters
[in]sockA raw IPv4/IPv6 sock object. May be NULL. A sensible local end point should be selected by the implementation in that case.
[in]dataPointer where the received data should be stored. May be NULL if len == 0.
[in]lenMaximum space available at data.
[in]remoteRemote end point for the sent data. May be NULL, if sock has a remote end point. sock_udp_ep_t::family may be AF_UNSPEC, if local end point of sock provides this information. sock_udp_ep_t::port may not be 0.
Returns
The number of bytes sent on success.
-EAFNOSUPPORT, if remote != NULL and sock_udp_ep_t::family of remote is != AF_UNSPEC and not supported.
-EHOSTUNREACH, if remote or remote end point of sock is not reachable.
-EINVAL, if sock_udp_ep_t::addr of remote is an invalid address.
-EINVAL, if sock_udp_ep_t::netif of remote is not a valid interface or contradicts the given local interface (i.e. neither the local end point of sock nor remote are assigned to SOCK_ADDR_ANY_NETIF but are nevertheless different.
-EINVAL, if sock_udp_ep_t::port of remote is 0.
-ENOMEM, if no memory was available to send data.
-ENOTCONN, if remote == NULL, but sock has no remote end point.