Raw IPv4/IPv6 sock API

Sock submodule for raw IPv4/IPv6. More...

Detailed Description

Sock submodule for raw IPv4/IPv6.

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

A Simple IPv6 Server

#include <stdio.h>
#include "net/protnum.h"
#include "net/sock/ip.h"
uint8_t buf[128];
int main(void)
{
sock_ip_t sock;
if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
puts("Error creating raw IP sock");
return 1;
}
while (1) {
sock_ip_ep_t remote;
ssize_t res;
if ((res = sock_ip_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_ip_send(&sock, buf, res, 0, &remote) < 0) {
puts("Error sending reply");
}
}
}
return 0;
}

Above you see a simple IPv6 server. 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.

After including header files for the address families, protocol numbers and the raw `sock`s themselves, we create some buffer space buf to store the data received by the server:

#include "net/af.h"
#include "net/protnum.h"
#include "net/sock/ip.h"
uint8_t buf[128];

To be able to listen for incoming packets we bind the sock by setting a local end point (even if we just state here, that we just want to bind it to any IPv6 address).

We then proceed to create the sock. It is bound to local and listens for IPv6 packets with next header field PROTNUM_IPV6_NONXT. Since we don't need any further configuration we set the flags to 0. In case of an error we stop the program:

sock_ip_t sock;
if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
puts("Error creating raw IP 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_ip_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. Note since the proto was already set during sock_ip_create() we can just leave proto for the sock_ip_send() set to 0 (it is ignored by that function in that case anyway). In case of an error on send we print an according message:

while (1) {
sock_ip_ep_t remote;
ssize_t res;
if ((res = sock_ip_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
&remote)) >= 0) {
puts("Received a message");
if (sock_ip_send(&sock, buf, res, 0, &remote) < 0) {
puts("Error sending reply");
}
}
}

A Simple IPv6 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_ip_send(NULL, data, data_len, PROTNUM, &remote);

With data being the data sent, data_len the length of data, PROTNUM the next header number for the sent packet and remote the remote end point the packet that 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/ip.h"
#include "xtimer.h"
uint8_t buf[7];
int main(void)
{
sock_ip_t sock;
if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
puts("Error creating raw IP sock");
return 1;
}
while (1) {
sock_ip_ep_t remote = { .family = AF_INET6 };
ssize_t res;
if (sock_ip_send(&sock, "Hello!", sizeof("Hello!"), 0, &remote) < 0) {
puts("Error sending message");
sock_ip_close(&sock);
return 1;
}
if ((res = sock_ip_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. Note that we also could specify the remote end point here and not use it with sock_ip_send().

sock_ip_t sock;
if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
puts("Error creating raw IP sock");
return 1;
}

We then create a remote end point for the link-local all nodes multicast address (ff02::1) and send a "Hello!" message to that end point.

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

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

if ((res = sock_ip_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  ip.h
 Raw IPv4/IPv6 sock definitions.
 

Typedefs

typedef struct sock_ip sock_ip_t
 Type for a raw IPv4/IPv6 sock object. More...
 

Functions

int sock_ip_create (sock_ip_t *sock, const sock_ip_ep_t *local, const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
 Creates a new raw IPv4/IPv6 sock object. More...
 
void sock_ip_close (sock_ip_t *sock)
 Closes a raw IPv4/IPv6 sock object. More...
 
int sock_ip_get_local (sock_ip_t *sock, sock_ip_ep_t *ep)
 Gets the local end point of a raw IPv4/IPv6 sock object. More...
 
int sock_ip_get_remote (sock_ip_t *sock, sock_ip_ep_t *ep)
 Gets the remote end point of a raw IPv4/IPv6 sock object. More...
 
ssize_t sock_ip_recv (sock_ip_t *sock, void *data, size_t max_len, uint32_t timeout, sock_ip_ep_t *remote)
 Receives a message over IPv4/IPv6 from remote end point. More...
 
ssize_t sock_ip_recv_buf (sock_ip_t *sock, void **data, void **buf_ctx, uint32_t timeout, sock_ip_ep_t *remote)
 Provides stack-internal buffer space containing an IPv4/IPv6 message from remote end point. More...
 
ssize_t sock_ip_send (sock_ip_t *sock, const void *data, size_t len, uint8_t proto, const sock_ip_ep_t *remote)
 Sends a message over IPv4/IPv6 to remote end point. More...
 

Typedef Documentation

◆ sock_ip_t

typedef struct sock_ip sock_ip_t

Type for a raw IPv4/IPv6 sock object.

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

Definition at line 294 of file ip.h.

Function Documentation

◆ sock_ip_close()

void sock_ip_close ( sock_ip_t sock)

Closes a raw IPv4/IPv6 sock object.

Precondition
(sock != NULL)
Parameters
[in]sockA raw IPv4/IPv6 sock object.

◆ sock_ip_create()

int sock_ip_create ( sock_ip_t sock,
const sock_ip_ep_t local,
const sock_ip_ep_t remote,
uint8_t  proto,
uint16_t  flags 
)

Creates a new raw IPv4/IPv6 sock object.

Precondition
(sock != NULL)
Parameters
[out]sockThe resulting sock object.
[in]localLocal end point for the sock object. May be NULL. sock_ip_ep_t::netif must either be SOCK_ADDR_ANY_NETIF or equal to sock_ip_ep_t::netif of remote if remote != NULL. If NULL sock_ip_send() may bind implicitly.
[in]remoteRemote end point for the sock object. May be NULL but then the remote parameter of sock_ip_send() may not be NULL or it will always error with return value -ENOTCONN. sock_ip_ep_t::port may not be 0 if remote != NULL. sock_ip_ep_t::netif must either be SOCK_ADDR_ANY_NETIF or equal to sock_ip_ep_t::netif of local if local != NULL.
[in]protoProtocol to use in the raw IPv4/IPv6 sock object (the protocol header field in IPv4 and the next_header field in IPv6).
[in]flagsFlags for the sock object. See also [sock flags](net_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_ip_ep_t::family of local or remote is not supported.
-EINVAL, if sock_ip_ep_t::addr of remote is an invalid address.
-EINVAL, if sock_ip_ep_t::netif of local or remote are not 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.
-EPROTONOSUPPORT, if local != NULL or remote != NULL and proto is not supported by sock_ip_ep_t::family of local or remote.

◆ sock_ip_get_local()

int sock_ip_get_local ( sock_ip_t sock,
sock_ip_ep_t ep 
)

Gets the local end point of a raw IPv4/IPv6 sock object.

This gets the local end point of a raw IPv4/IPv6 sock object. Note that this might not be the same end point you added in sock_ip_create(), but an end point more suitable for the implementation. Examples for this might be that if sock_ip_ep_t::netif is given in sock_ip_create(), the implementation might choose to return the address on this interface the sock is bound to in ep's sock_ip_ep_t::addr.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]sockA raw IPv4/IPv6 sock object.
[out]epThe local end point.
Returns
0 on success.
-EADDRNOTAVAIL, when sock has no end point bound to it.

◆ sock_ip_get_remote()

int sock_ip_get_remote ( sock_ip_t sock,
sock_ip_ep_t ep 
)

Gets the remote end point of a raw IPv4/IPv6 sock object.

Precondition
(sock != NULL) && (ep != NULL)

This gets the remote end point of a raw IPv4/IPv6 sock object. Note that this might not be the same end point you added in sock_ip_create(), but an end point more suitable for the implementation. Examples for this might be that if sock_ip_ep_t::netif is given in sock_ip_create(), the implementation might choose to return the address on this interface the sock is bound to in ep's sock_ip_ep_t::addr.

Parameters
[in]sockA raw IPv4/IPv6 sock object.
[out]epThe remote end point.
Returns
0 on success.
-ENOTCONN, when sock has no remote end point bound to it.

◆ sock_ip_recv()

ssize_t sock_ip_recv ( sock_ip_t sock,
void *  data,
size_t  max_len,
uint32_t  timeout,
sock_ip_ep_t remote 
)

Receives a message over IPv4/IPv6 from 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_ip_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_ip_recv_buf()

ssize_t sock_ip_recv_buf ( sock_ip_t sock,
void **  data,
void **  buf_ctx,
uint32_t  timeout,
sock_ip_ep_t remote 
)

Provides stack-internal buffer space containing an IPv4/IPv6 message from remote end point.

Precondition
(sock != NULL) && (data != NULL) && (buf_ctx != NULL)
Parameters
[in]sockA raw IPv4/IPv6 sock object.
[out]dataPointer to a stack-internal buffer space containing the received data.
[in,out]buf_ctxStack-internal buffer context. If it points to a NULL pointer, the stack returns a new buffer space for a new packet. If it does not point to a NULL pointer, an existing context is assumed to get a next segment in a buffer.
[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.
Warning
This feature is experimental!
This function is quite new, not implemented for all stacks yet, and may be subject to sudden API changes. Do not use in production if this is unacceptable.
Note
Function blocks if no packet is currently waiting.
Returns
The number of bytes received on success. May not be the complete payload. Continue calling with the returned buf_ctx to get more buffers until result is 0 or an error.
0, if no received data is available, but everything is in order. If buf_ctx was provided, it was released.
-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_ip_recv() blocks).
-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_ip_send()

ssize_t sock_ip_send ( sock_ip_t sock,
const void *  data,
size_t  len,
uint8_t  proto,
const sock_ip_ep_t remote 
)

Sends a message over IPv4/IPv6 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]protoProtocol to use in the packet sent, in case sock == NULL. If sock != NULL this parameter will be ignored.
[in]remoteRemote end point for the sent data. May be NULL, if sock has a remote end point. sock_ip_ep_t::family may be AF_UNSPEC, if local end point of sock provides this information.
Returns
The number of bytes sent on success.
-EAFNOSUPPORT, if remote != NULL and sock_ip_ep_t::family of remote is != AF_UNSPEC and not supported.
-EINVAL, if sock_ip_ep_t::addr of remote is an invalid address.
-EINVAL, if sock_ip_ep_t::netif of remote is not a valid interface or contradicts the local interface of sock.
-EHOSTUNREACH, if remote or remote end point of sock is not reachable.
-ENOMEM, if no memory was available to send data.
-ENOTCONN, if remote == NULL, but sock has no remote end point.
-EPROTOTYPE, if sock == NULL and proto is not by sock_ip_ep_t::family of remote.
protnum.h
Protocol number definitions.
sock_ip
Raw IP sock type.
Definition: sock_types.h:91
sock_ip_ep_t::addr
union sock_ip_ep_t::@290 addr
address
ipv6_addr_t
Data type to represent an IPv6 address.
Definition: addr.h:74
addr.h
Definitions for IPv6 addresses.
sock_ip_ep_t::family
int family
family of sock_ip_ep_t::addr
Definition: sock.h:182
SOCK_IPV6_EP_ANY
#define SOCK_IPV6_EP_ANY
Address to bind to any IPv6 address.
Definition: sock.h:164
PROTNUM_IPV6_NONXT
#define PROTNUM_IPV6_NONXT
No Next Header for IPv6.
Definition: protnum.h:97
sock_ip_ep_t::ipv6
uint8_t ipv6[16]
IPv6 address mode.
Definition: sock.h:191
ETIMEDOUT
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:147
sock_ip_create
int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local, const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
Creates a new raw IPv4/IPv6 sock object.
IPV6_ADDR_MCAST_SCP_LINK_LOCAL
#define IPV6_ADDR_MCAST_SCP_LINK_LOCAL
link-local scope
Definition: addr.h:239
af.h
Global UNIX address family definitions.
AF_INET6
@ AF_INET6
internetwork address family with IPv6: UDP, TCP, etc.
Definition: af.h:38
ip.h
Raw IPv4/IPv6 sock definitions.
SOCK_NO_TIMEOUT
#define SOCK_NO_TIMEOUT
Special value meaning "wait forever" (don't timeout)
Definition: sock.h:171
xtimer_sleep
static void xtimer_sleep(uint32_t seconds)
Pause the execution of a thread for some seconds.
sock_ip_close
void sock_ip_close(sock_ip_t *sock)
Closes a raw IPv4/IPv6 sock object.
ipv6_addr_set_all_nodes_multicast
static void ipv6_addr_set_all_nodes_multicast(ipv6_addr_t *addr, unsigned int scope)
Sets addr dynamically to an all nodes multicast IPv6 address (ff0S::1, where S is the scope).
Definition: addr.h:654
sock_ip_recv
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len, uint32_t timeout, sock_ip_ep_t *remote)
Receives a message over IPv4/IPv6 from remote end point.
sock_ip_send
ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len, uint8_t proto, const sock_ip_ep_t *remote)
Sends a message over IPv4/IPv6 to remote end point.
xtimer.h
xtimer interface definitions
sock_ip_ep_t
Abstract IP end point and end point for a raw IP sock object.
Definition: sock.h:176
US_PER_SEC
#define US_PER_SEC
The number of microseconds per second.
Definition: timex.h:34