mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
commit
b016fb43fa
@ -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 <aar@pengutronix.de>
|
||||
* @author Simon Brummer <simon.brummer@haw-hamburg.de>
|
||||
* @author Cenk Gündoğan <mail@cgundogan.de>
|
||||
@ -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
|
||||
*
|
||||
|
@ -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 <stdio.h>
|
||||
*
|
||||
* #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 <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 * 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
|
||||
|
@ -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.
|
||||
|
@ -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 <stdio.h>
|
||||
*
|
||||
* #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 <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();
|
||||
* 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.
|
||||
|
Loading…
Reference in New Issue
Block a user