diff --git a/sys/include/net/sock.h b/sys/include/net/sock.h index 4db055bb44..e2d48c14a1 100644 --- a/sys/include/net/sock.h +++ b/sys/include/net/sock.h @@ -12,8 +12,7 @@ /** * @defgroup net_sock Sock API * @ingroup net - * @brief Provides a minimal common API for applications to connect to the - * different network stacks + * @brief Provides a network API for applications and library * * About * ===== @@ -34,39 +33,55 @@ * +---------------+ * ~~~~~~~~~~~~~~~~~~~~ * - * This module provides a minimal set of functions to establish connections or - * send and receives datagrams using different types of communication. Together, - * they serve as a common API that connects application- and network stack code. + * This module provides a set of functions to establish connections or send and + * receive datagrams using different types of protocols. Together, they serve as + * an API that allows an application or library to connect to a network. * - * Currently the following sock types are defined: + * It was designed with the following priorities in mind + * + * 1. No need for dynamic memory allocation + * 2. User friendliness + * 3. Simplicity + * 4. Efficiency (at both front- and backend) + * 5. Portability + * + * Currently the following `sock` types are defined: * * * @ref sock_ip_t (net/sock/ip.h): raw IP sock * * @ref sock_tcp_t (net/sock/tcp.h): TCP sock * * @ref sock_udp_t (net/sock/udp.h): UDP sock * - * Each network stack must implement at least one sock type. - * - * Note that there might be no relation between the different sock types. - * For simplicity and modularity this API doesn't put any restriction of the - * actual implementation of the type. For example, one implementation might - * choose to have all sock types have a common base class or use the raw IP - * sock type to send e.g. UDP packets, while others will keep them - * completely separate from each other. + * Note that there might be no relation between the different `sock` types. + * So casting e.g. `sock_ip_t` to `sock_udp_t` might not be as straight forward, + * as you think depending on the networking architecture. * * How To Use * ========== * * A RIOT application uses the functions provided by one or more of the - * sock type headers (for example @ref sock_udp), regardless of the + * `sock` type headers (for example @ref sock_udp_t), regardless of the * network stack it uses. * The network stack used under the bonnet is specified by including the - * appropriate module (for example USEMODULE += gnrc_sock_udp) + * appropriate module (for example `USEMODULE += gnrc_sock_udp` for + * [GNRC's](net_gnrc) version of this API). * * This allows for network stack agnostic code on the application layer. * The application code to establish a connection is always the same, allowing * the network stack underneath to be switched simply by changing the * `USEMODULE` definitions in the application's Makefile. * + * The actual code very much depends on the used `sock` type. Please refer to + * their documentation for specific examples. + * + * Implementor Notes + * ================= + * ### Type definition + * For simplicity and modularity this API doesn't put any restriction on the + * actual implementation of the type. For example, one implementation might + * choose to have all `sock` types having a common base class or use the raw IP + * `sock` type to send e.g. UDP packets, while others will keep them + * completely separate from each other. + * * @author Alexander Aring * @author Simon Brummer * @author Cenk Gündoğan @@ -94,14 +109,18 @@ extern "C" { #if defined(DOXYGEN) /** - * @brief compile flag to activate IPv6 support for sock + * @name Compile flags + * @brief Flags to (de)activate certain functionalities + * @{ */ -#define SOCK_HAS_IPV6 +#define SOCK_HAS_IPV6 /**< activate IPv6 support */ +/** @} */ #endif /** - * @brief Common flags for @ref net_conn - * @name net_sock_flags + * @name Sock flags + * @brief Common flags for @ref net_sock + * @anchor net_sock_flags * @{ */ #define SOCK_FLAGS_REUSE_EP (0x0001) /**< allow to reuse end point on bind */ @@ -140,7 +159,7 @@ typedef struct { int family; union { -#if defined(SOCK_HAS_IPV6) || defined(DOXYGEN) +#ifdef SOCK_HAS_IPV6 /** * @brief IPv6 address mode * @@ -176,7 +195,7 @@ struct _sock_tl_ep { int family; union { -#if defined(SOCK_HAS_IPV6) || defined(DOXYGEN) +#ifdef SOCK_HAS_IPV6 /** * @brief IPv6 address mode * diff --git a/sys/include/net/sock/ip.h b/sys/include/net/sock/ip.h index 5895a5007b..baf92d3caf 100644 --- a/sys/include/net/sock/ip.h +++ b/sys/include/net/sock/ip.h @@ -12,7 +12,246 @@ /** * @defgroup net_sock_ip Raw IPv4/IPv6 sock API * @ingroup net_sock - * @brief Sock Submodule for raw IPv4/IPv6 + * @brief Sock submodule for raw IPv4/IPv6 + * + * How To Use + * ---------- + * First you need to @ref including-modules "include" a module that implements + * this API in your application's Makefile. For example the implementation for + * @ref net_gnrc "GNRC" is called `gnrc_sock_ip`. + * + * ### A Simple IPv6 Server + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include + * + * #include "net/af.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), 0, &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 + * @ref including-modules "include" the IPv6 module of your networking + * implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least + * one network device. + * + * After including header files for the @ref net_af "address families", + * @ref net_protnum "protocol numbers" and the @ref net_sock_ip "raw `sock`s" + * themselves, we create some buffer space `buf` to store the data received by + * the server: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #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 @ref ipv6_hdr_t::nh "next header field" + * @ref 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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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 @ref sock_ip_recv() to a + * value `> 0`. 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 @ref sock_ip_create() we can just leave `proto` for + * the @ref 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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * while (1) { + * sock_ip_ep_t remote; + * ssize_t res; + * + * if ((res = sock_ip_recv(&sock, buf, sizeof(buf), 0, &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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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: + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include + * + * #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 * SEC_IN_USEC, + * 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 @ref including-modules "include" the IPv6 module + * of your networking implementation (e.g. `gnrc_ipv6_default` for + * @ref net_gnrc 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 @ref sock_ip_send(). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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](https://tools.ietf.org/html/rfc4291#page-16) (`ff02::1`) and send + * a "Hello!" message to that end point. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * if ((res = sock_ip_recv(&sock, buf, sizeof(buf), 1 * SEC_IN_USEC, + * 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)`. + * * @{ * * @file @@ -40,9 +279,10 @@ extern "C" { #endif /** - * @brief Implementation-specific type of a raw IPv4/IPv6 sock object + * @brief Type for a raw IPv4/IPv6 sock object * - * `struct sock_ip` needs to be defined by stack-specific `sock_types.h`. + * @note API implementors: `struct sock_ip` needs to be defined by + * implementation-specific `sock_types.h`. */ typedef struct sock_ip sock_ip_t; @@ -53,11 +293,10 @@ typedef struct sock_ip sock_ip_t; * * @param[out] sock The resulting sock object. * @param[in] local Local end point for the sock object. - * May be NULL to solicit implicit bind on - * @ref sock_ip_send(). - * sock_ip_ep_t::netif must either be + * May be NULL. sock_ip_ep_t::netif must either be * @ref SOCK_ADDR_ANY_NETIF or equal to sock_ip_ep_t::netif * of @p remote if `remote != NULL`. + * If NULL @ref sock_ip_send() may bind implicitly. * @param[in] remote Remote end point for the sock object. * May be `NULL` but then the `remote` parameter of * @ref sock_ip_send() may not be `NULL` or it will always @@ -69,12 +308,12 @@ typedef struct sock_ip sock_ip_t; * @param[in] proto Protocol to use in the raw IPv4/IPv6 sock object * (the `protocol` header field in IPv4 and the `next_header` * field in IPv6). - * @param[in] flags Flags for the sock object. See also @ref net_sock_flags. - * May be 0. + * @param[in] flags Flags for the sock object. See also + * [sock flags](net_sock_flags). May be 0. * * @return 0 on success. - * @return -EADDRINUSE, if `local != NULL` and the stack reports that @p local - * is already used elsewhere + * @return -EADDRINUSE, if `local != NULL` and @p local is already used + * elsewhere * @return -EAFNOSUPPORT, if `local != NULL` or `remote != NULL` and * sock_ip_ep_t::family of @p local or @p remote is not supported. * @return -EINVAL, if `proto` is not supported or if sock_ip_ep_t::netif of @@ -82,8 +321,8 @@ typedef struct sock_ip sock_ip_t; * 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 the stack can't provide enough resources for `sock` to - * be created. + * @return -ENOMEM, if not enough resources can be provided for `sock` to be + * created. * @return -EPROTONOSUPPORT, if `local != NULL` or `remote != NULL` and * proto is not supported by sock_ip_ep_t::family of @p local or @p * remote. @@ -103,6 +342,13 @@ void sock_ip_close(sock_ip_t *sock); /** * @brief 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 @ref 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 @ref sock_ip_create(), the + * implementation might choose to return the address on this interface the + * @p sock is bound to in @p ep's sock_ip_ep_t::addr. + * * @pre `(sock != NULL) && (ep != NULL)` * * @param[in] sock A raw IPv4/IPv6 sock object. @@ -118,6 +364,13 @@ int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *ep); * * @pre `(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 @ref 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 @ref sock_ip_create(), the + * implementation might choose to return the address on this interface the + * @p sock is bound to in @p ep's sock_ip_ep_t::addr. + * * @param[in] sock A UDP sock object. * @param[out] ep The remote end point. * @@ -134,13 +387,10 @@ int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep); * @param[in] sock A raw IPv4/IPv6 sock object. * @param[out] data Pointer where the received data should be stored. * @param[in] max_len Maximum space available at @p data. - * If received data exceeds @p max_len the data is - * truncated and the remaining data can be retrieved - * later on. * @param[in] timeout Timeout for receive in microseconds. * This value can be ignored (no timeout) if the - * @ref sys_xtimer module is not present and the stack does - * not support timeouts on its own. + * @ref sys_xtimer module is not present or the + * implementation does not support timeouts on its own. * May be 0 for no timeout. * @param[out] remote Remote end point of the received data. * May be NULL, if it is not required by the application. @@ -167,21 +417,19 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len, * * @param[in] sock A raw IPv4/IPv6 sock object. May be NULL. * A sensible local end point should be selected by the - * stack in that case. + * implementation in that case. * @param[in] data Pointer where the received data should be stored. * May be `NULL` if `len == 0`. * @param[in] len Maximum space available at @p data. - * @param[in] proto Protocol to use in the packet send, in case + * @param[in] proto Protocol to use in the packet sent, in case * `sock == NULL`. If `sock != NULL` this parameter will be * ignored. - * @param[in] remote Remote end point for the send data. + * @param[in] remote Remote end point for the sent data. * May be `NULL`, if @p sock has a remote end point. * sock_ip_ep_t::family may be AF_UNSPEC, if local * end point of @p sock provides this information. * - * @note Function blocks until packet is handed to the stack. - * - * @return The number of bytes send on success. + * @return The number of bytes sent on success. * @return -EAFNOSUPPORT, if `remote != NULL` and sock_ip_ep_t::family of * @p remote is != AF_UNSPEC and not supported. * @return -EHOSTUNREACH, if @p remote or remote end point of @p sock is not diff --git a/sys/include/net/sock/tcp.h b/sys/include/net/sock/tcp.h index 4c7958fd7c..bb71568915 100644 --- a/sys/include/net/sock/tcp.h +++ b/sys/include/net/sock/tcp.h @@ -13,6 +13,15 @@ * @defgroup net_sock_tcp TCP sock API * @ingroup net_sock * @brief Sock submodule for TCP + * + * How To Use + * ---------- + * First you need to @ref including-modules "include" a module that implements + * this API in your application's Makefile. For example the implementation for + * @ref net_gnrc "GNRC" is called `gnrc_sock_udp`. + * + * @todo add detailed examples when implementation exists. + * * @{ * * @file @@ -41,17 +50,18 @@ extern "C" { typedef struct _sock_tl_ep sock_tcp_ep_t; /**< An end point for a TCP sock object */ /** - * @brief Implementation-specific type of a TCP sock object + * @brief Type for a TCP sock object * - * `struct sock_tcp` needs to be defined by stack-specific `sock_types.h`. + * @note API implementors: `struct sock_tcp` needs to be defined by + * implementation-specific `sock_types.h`. */ typedef struct sock_tcp sock_tcp_t; /** - * @brief Implementation-specific type of a TCP listening queue + * @brief Type for a TCP listening queue * - * `struct sock_tcp_queue` needs to be defined by stack-specific - * `sock_types.h`. + * @note API implementors: `struct sock_tcp_queue` needs to be defined by + * implementation-specific `sock_types.h`. */ typedef struct sock_tcp_queue sock_tcp_queue_t; @@ -164,7 +174,7 @@ int sock_tcp_get_remote(sock_tcp_t *sock, sock_tcp_ep_t *ep); * establish connection. * @return -EPERM, if connections on local end point of @p queue are not * permitted on this system (e.g. by firewall rules). - * @return -ETIMEDOUT, if the operation timed out stack-internally. + * @return -ETIMEDOUT, if the operation timed out internally. */ int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock); @@ -181,8 +191,8 @@ int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock); * later on. * @param[in] timeout Timeout for receive in microseconds. * This value can be ignored (no timeout) if the - * @ref sys_xtimer module is not present and the stack does - * not support timeouts on its own. + * @ref sys_xtimer module is not present and the + * implementation does not support timeouts on its own. * May be 0 for no timeout. * * @note Function may block. diff --git a/sys/include/net/sock/udp.h b/sys/include/net/sock/udp.h index 3bf67bb843..59dfead42a 100644 --- a/sys/include/net/sock/udp.h +++ b/sys/include/net/sock/udp.h @@ -13,6 +13,247 @@ * @defgroup net_sock_udp UDP sock API * @ingroup net_sock * @brief Sock submodule for UDP + * + * How To Use + * ---------- + * First you need to @ref including-modules "include" a module that implements + * this API in your application's Makefile. For example the implementation for + * @ref net_gnrc "GNRC" is called `gnrc_sock_udp`. + * + * ### A Simple UDP Echo Server + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include + * + * #include "net/af.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), 0, &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 + * @ref including-modules "include" the IPv6 module of your networking + * implementation (e.g. gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least + * one network device. + * + * After including header files for the @ref net_af "address families" and + * the @ref net_sock_ip "raw `sock`s" themselves, we create some buffer space + * `buf` to store the data received by the server: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include "net/af.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 with 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 @ref udp_hdr_t::dst_port "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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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 @ref sock_udp_recv() to a + * value `> 0`. 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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * while (1) { + * sock_udp_ep_t remote; + * ssize_t res; + * + * if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 0, &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: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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: + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #include + * + * #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(); + * return 1; + * } + * if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * SEC_IN_USEC, + * 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 @ref including-modules "include" the IPv6 module + * of your networking implementation (e.g. `gnrc_ipv6_default` for + * @ref net_gnrc 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 @ref sock_udp_send(). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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](https://tools.ietf.org/html/rfc4291#page-16) (`ff02::1`) and port + * `12345` and send a "Hello!" message to that end point. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * 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(); + * return 1; + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * We then wait a second for a reply and print it when it is received. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * SEC_IN_USEC, + * 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)`. + * * @{ * * @file @@ -42,9 +283,10 @@ extern "C" { typedef struct _sock_tl_ep sock_udp_ep_t; /**< An end point for a UDP sock object */ /** - * @brief Implementation-specific type of a UDP sock object + * @brief Type for a UDP sock object * - * `struct sock_udp` needs to be defined by stack-specific `sock_types.h`. + * @note API implementors: `struct sock_udp` needs to be defined by + * implementation-specific `sock_types.h`. */ typedef struct sock_udp sock_udp_t; @@ -57,12 +299,12 @@ typedef struct sock_udp sock_udp_t; * * @param[out] sock The resulting sock object. * @param[in] local Local end point for the sock object. - * May be `NULL` to solicit implicit bind on - * @ref sock_udp_send(). + * May be NULL. * sock_udp_ep_t::port may not be 0 if `local != NULL`. * sock_udp_ep_t::netif must either be - * @ref SOCK_ADDR_ANY_NETIF or equal to sock_udp_ep_t::netif - * of @p remote if `remote != NULL`. + * @ref SOCK_ADDR_ANY_NETIF or equal to + * sock_udp_ep_t::netif of @p remote if `remote != NULL`. + * If NULL @ref sock_udp_send() may bind implicitly. * @param[in] remote Remote end point for the sock object. * May be `NULL` but then the `remote` parameter of * @ref sock_udp_send() may not be `NULL` and or it will @@ -71,12 +313,13 @@ typedef struct sock_udp sock_udp_t; * sock_udp_ep_t::netif must either be * @ref SOCK_ADDR_ANY_NETIF or equal to sock_udp_ep_t::netif * of @p local if `local != NULL`. - * @param[in] flags Flags for the sock object. See also @ref net_sock_flags. + * @param[in] flags Flags for the sock object. See also + * [sock flags](net_sock_flags). * May be 0. * * @return 0 on success. - * @return -EADDRINUSE, if `local != NULL` and the stack reports that @p local - * is already used elsewhere + * @return -EADDRINUSE, if `local != NULL` and @p local is already used + * elsewhere * @return -EAFNOSUPPORT, if `local != NULL` or `remote != NULL` and * sock_udp_ep_t::family of @p local or @p remote is not supported. * @return -EINVAL, if sock_udp_ep_t::netif of @p local or @p remote is not a @@ -84,8 +327,8 @@ typedef struct sock_udp sock_udp_t; * `(local->netif != remote->netif) && * ((local->netif != SOCK_ADDR_ANY_NETIF) || * (remote->netif != SOCK_ADDR_ANY_NETIF))` if neither is `NULL`). - * @return -ENOMEM, if the stack can't provide enough resources for `sock` to - * be created. + * @return -ENOMEM, if not enough resources can be provided for `sock` to be + * created. */ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote, uint16_t flags); @@ -114,7 +357,6 @@ int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *ep); /** * @brief Gets the remote end point of a UDP sock object - * * @pre `(sock != NULL) && (ep != NULL)` * * @param[in] sock A UDP sock object. @@ -133,15 +375,11 @@ int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *ep); * @param[in] sock A raw IPv4/IPv6 sock object. * @param[out] data Pointer where the received data should be stored. * @param[in] max_len Maximum space available at @p data. - * If received data exceeds @p max_len the data is - * truncated and the remaining data can be retrieved - * later on. * @param[in] timeout Timeout for receive in microseconds. * This value can be ignored (no timeout) if the - * @ref sys_xtimer module is not present and the stack does - * not support timeouts on its own. + * @ref sys_xtimer module is not present or the + * implementation does not support timeouts on its own. * May be 0 for no timeout. - * Must be 0 if @ref sys_xtimer module is not present. * @param[out] remote Remote end point of the received data. * May be `NULL`, if it is not required by the application. * @@ -167,18 +405,16 @@ ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len, * * @param[in] sock A raw IPv4/IPv6 sock object. May be `NULL`. * A sensible local end point should be selected by the - * stack in that case. + * implementation in that case. * @param[in] data Pointer where the received data should be stored. * May be `NULL` if `len == 0`. * @param[in] len Maximum space available at @p data. - * @param[in] remote Remote end point for the send data. + * @param[in] remote Remote end point for the sent data. * May be `NULL`, if @p sock has a remote end point. * sock_udp_ep_t::family may be AF_UNSPEC, if local * end point of @p sock provides this information. * sock_udp_ep_t::port may not be 0. * - * @note Function blocks until packet is handed to the stack. - * * @return The number of bytes sent on success. * @return -EAFNOSUPPORT, if `remote != NULL` and sock_udp_ep_t::family of * @p remote is != AF_UNSPEC and not supported.