Raw IPv4/IPv6 sock API¶
Sock submodule for raw IPv4/IPv6.
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_ip.
A Simple IPv6 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 | #include <stdio.h>
#include "net/protnum.h"
#include "net/sock/ip.h"
uint8_t buf[128];
int main(void)
{
sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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 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:
1 2 3 4 5 | #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 ipv6/hdr.h::ipv6_hdr_t::nh protnum.h::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:
1 2 3 4 5 6 7 | sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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 ip.h::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 ip.h::sock_ip_create() we can just leave proto for the ip.h::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:
1 2 3 4 5 6 7 8 9 10 11 12 | 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:
1 | 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:
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 | #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_ep_t local = SOCK_IPV6_EP_ANY;
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;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
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");
}
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. Note that we also could specify the remote end point here and not use it with ip.h::sock_ip_send().
1 2 3 4 5 6 7 | sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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.
1 2 3 4 5 6 7 8 9 10 11 | sock_ip_ep_t remote = { .family = AF_INET6 };
ssize_t res;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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).
A Simple IPv6 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 | #include <stdio.h>
#include "net/protnum.h"
#include "net/sock/ip.h"
uint8_t buf[128];
int main(void)
{
sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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 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:
1 2 3 4 5 | #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 ipv6/hdr.h::ipv6_hdr_t::nh protnum.h::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:
1 2 3 4 5 6 7 | sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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 ip.h::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 ip.h::sock_ip_create() we can just leave proto for the ip.h::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:
1 2 3 4 5 6 7 8 9 10 11 12 | 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:
1 | 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:
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 | #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_ep_t local = SOCK_IPV6_EP_ANY;
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;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
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");
}
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. Note that we also could specify the remote end point here and not use it with ip.h::sock_ip_send().
1 2 3 4 5 6 7 | sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
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.
1 2 3 4 5 6 7 8 9 10 11 | sock_ip_ep_t remote = { .family = AF_INET6 };
ssize_t res;
ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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).
-
struct sock_ip
sock_ip_t¶ Type for a raw IPv4/IPv6 sock object.
Note
API implementors:
struct sock_ipneeds to be defined by implementation-specificsock_types.h.
-
int
sock_ip_create(ip.h::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.
Parameters
sock: The resulting sock object. local: Local end point for the sock object. May be NULL. sock.h::sock_ip_ep_t::netifmust either besock.h::SOCK_ADDR_ANY_NETIFor equal tosock.h::sock_ip_ep_t::netifofremoteifremote != NULL. If NULLip.h::sock_ip_send()may bind implicitly.remote: Remote end point for the sock object. May be NULLbut then theremoteparameter ofip.h::sock_ip_send()may not beNULLor it will always error with return value -ENOTCONN. sock_ip_ep_t::port may not be 0 ifremote != NULL.sock.h::sock_ip_ep_t::netifmust either besock.h::SOCK_ADDR_ANY_NETIFor equal tosock.h::sock_ip_ep_t::netifoflocaliflocal != NULL.proto: Protocol to use in the raw IPv4/IPv6 sock object (the protocolheader field in IPv4 and thenext_headerfield in IPv6).flags: Flags for the sock object. See also [sock flags](net_sock_flags). May be 0. Return values
- 0 on success.
- -EADDRINUSE, if
local != NULLandlocalis already used elsewhere - -EAFNOSUPPORT, if
local != NULLorremote != NULLandsock.h::sock_ip_ep_t::familyoflocalorremoteis not supported. - -EINVAL, if
sock.h::sock_ip_ep_t::addrofremoteis an invalid address. - -EINVAL, if
sock.h::sock_ip_ep_t::netifoflocalorremoteare 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 != NULLorremote != NULLand proto is not supported bysock.h::sock_ip_ep_t::familyoflocalorremote.
-
void
sock_ip_close(ip.h::sock_ip_t* sock)¶ Closes a raw IPv4/IPv6 sock object.
Parameters
sock: A raw IPv4/IPv6 sock object.
-
int
sock_ip_get_local(ip.h::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
ip.h::sock_ip_create(), but an end point more suitable for the implementation. Examples for this might be that ifsock.h::sock_ip_ep_t::netifis given inip.h::sock_ip_create(), the implementation might choose to return the address on this interface thesockis bound to inep'ssock.h::sock_ip_ep_t::addr.Parameters
sock: A raw IPv4/IPv6 sock object. ep: The local end point. Return values
- 0 on success.
- -EADDRNOTAVAIL, when
sockhas no end point bound to it.
-
int
sock_ip_get_remote(ip.h::sock_ip_t* sock, sock_ip_ep_t * ep)¶ Gets the remote end point of a UDP sock object.
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
ip.h::sock_ip_create(), but an end point more suitable for the implementation. Examples for this might be that ifsock.h::sock_ip_ep_t::netifis given inip.h::sock_ip_create(), the implementation might choose to return the address on this interface thesockis bound to inep'ssock.h::sock_ip_ep_t::addr.Parameters
sock: A UDP sock object. ep: The remote end point. Return values
- 0 on success.
- -ENOTCONN, when
sockhas no remote end point bound to it.
-
msp430_types.h::ssize_tsock_ip_recv(ip.h::sock_ip_t* sock, void * data,msp430_types.h::size_tmax_len, uint32_t timeout, sock_ip_ep_t * remote)¶ Receives a message over IPv4/IPv6 from 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_TIMEOUTfor 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
sockis not given. - -EAGAIN, if
timeoutis0and no data is available. - -EINVAL, if
remoteis invalid orsockis not properly initialized (or closed whileip.h::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
timeoutexpired.
-
msp430_types.h::ssize_tsock_ip_send(ip.h::sock_ip_t* sock, const void * data,msp430_types.h::size_tlen, uint8_t proto, const sock_ip_ep_t * remote)¶ Sends a message over IPv4/IPv6 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 NULLiflen == 0.len: Maximum space available at data.proto: Protocol to use in the packet sent, in case sock == NULL. Ifsock != NULLthis parameter will be ignored.remote: Remote end point for the sent data. May be NULL, ifsockhas a remote end point.sock.h::sock_ip_ep_t::familymay be AF_UNSPEC, if local end point ofsockprovides this information.Return values
- The number of bytes sent on success.
- -EAFNOSUPPORT, if
remote != NULLandsock.h::sock_ip_ep_t::familyofremoteis != AF_UNSPEC and not supported. - -EINVAL, if
sock.h::sock_ip_ep_t::addrofremoteis an invalid address. - -EINVAL, if
sock.h::sock_ip_ep_t::netifofremoteis not a valid interface or contradicts the local interface ofsock. - -EHOSTUNREACH, if
remoteor remote end point ofsockis not reachable. - -ENOMEM, if no memory was available to send
data. - -ENOTCONN, if
remote == NULL, butsockhas no remote end point. - -EPROTOTYPE, if
sock == NULLandprotois not bysock.h::sock_ip_ep_t::familyofremote.