1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

net/sock_ip: Extend API for auxiliary data

This commit is contained in:
Marian Buschsieweke 2020-07-27 10:57:11 +02:00
parent f84d34f2be
commit ebcf1c0ab4
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
6 changed files with 269 additions and 21 deletions

View File

@ -112,6 +112,8 @@ PSEUDOMODULES += shell_hooks
PSEUDOMODULES += slipdev_stdio
PSEUDOMODULES += sock
PSEUDOMODULES += sock_async
PSEUDOMODULES += sock_aux_local
PSEUDOMODULES += sock_aux_timestamp
PSEUDOMODULES += sock_dtls
PSEUDOMODULES += sock_ip
PSEUDOMODULES += sock_tcp

View File

@ -151,8 +151,9 @@ static int _parse_iphdr(struct netbuf *buf, void **data, void **ctx,
return (ssize_t)data_len;
}
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote)
ssize_t sock_ip_recv_aux(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux)
{
void *pkt = NULL;
struct netbuf *ctx = NULL;
@ -161,8 +162,8 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
bool nobufs = false;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
while ((res = sock_ip_recv_buf(sock, &pkt, (void **)&ctx, timeout,
remote)) > 0) {
while ((res = sock_ip_recv_buf_aux(sock, &pkt, (void **)&ctx, timeout,
remote, aux)) > 0) {
if (ctx->p->tot_len > (ssize_t)max_len) {
nobufs = true;
/* progress context to last element */
@ -176,9 +177,11 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
return (nobufs) ? -ENOBUFS : ((res < 0) ? res : ret);
}
ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **ctx,
uint32_t timeout, sock_ip_ep_t *remote)
ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **ctx,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux)
{
(void)aux;
struct netbuf *buf;
int res;
@ -203,9 +206,11 @@ ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **ctx,
return res;
}
ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote)
ssize_t sock_ip_send_aux(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote,
sock_ip_aux_tx_t *aux)
{
(void)aux;
assert((sock != NULL) || (remote != NULL));
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
return lwip_sock_send(sock ? sock->base.conn : NULL, data, len, proto,

View File

@ -354,6 +354,7 @@ void sock_dtls_session_destroy(sock_dtls_t *sock, sock_dtls_session_t *remote)
ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
const void *data, size_t len, uint32_t timeout)
{
(void)aux;
int res;
assert(sock);
@ -511,6 +512,7 @@ static ssize_t _complete_handshake(sock_dtls_t *sock,
ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
void *data, size_t max_len, uint32_t timeout)
{
(void)aux;
assert(sock);
assert(data);
assert(remote);

View File

@ -245,6 +245,61 @@ struct _sock_tl_ep {
uint16_t port; /**< transport layer port (in host byte order) */
};
/**
* @brief Flags used to request auxiliary data
*/
enum {
/**
* @brief Flag to request the local address/endpoint
*
* @note Select module `sock_aux_local` and a compatible network stack
* to use this
*
* This is the address/endpoint the packet/datagram/segment was received on.
* This flag will be cleared if the network stack stored the local
* address/endpoint as requested, otherwise the bit remains set.
*
* Depending on the family of the socket, the timestamp will be stored in
* @ref sock_udp_aux_rx_t::local, @ref sock_ip_aux_rx_t::local, or in
* @ref sock_dtls_aux_rx_t::local.
*/
SOCK_AUX_GET_LOCAL = (1LU << 0),
/**
* @brief Flag to request the time stamp of transmission / reception
*
* @note Select module `sock_aux_timestamp` and a compatible network
* stack to use this
*
* Unless otherwise noted, the time stamp is the current system time in
* nanoseconds on which the start of frame delimiter or preamble was
* sent / received.
*
* Set this flag in the auxiliary data structure prior to the call of
* @ref sock_udp_recv_aux / @ref sock_udp_send_aux / @ref sock_ip_recv_aux
* / etc. to request the time stamp of reception / transmission. This flag
* will be cleared if the timestamp was stored, otherwise it remains set.
*
* Depending on the family of the socket, the timestamp will be stored in
* for reception in @ref sock_udp_aux_rx_t::timestamp,
* @ref sock_ip_aux_rx_t::timestamp, or @ref sock_dtls_aux_rx_t::timestamp.
* For transmission it will be stored in @ref sock_udp_aux_tx_t::timestamp,
* @ref sock_ip_aux_tx_t::timestamp, or @ref sock_dtls_aux_tx_t::timestamp.
*/
SOCK_AUX_GET_TIMESTAMP = (1LU << 1),
};
/**
* @brief Type holding the flags used to request specific auxiliary data
*
* This is a bitmask of `SOCK_AUX_GET_...`, e.g. if the mask contains
* @ref SOCK_AUX_GET_LOCAL, the local address/endpoint is requested
*
* @details The underlying type can be changed without further notice, if more
* flags are needed. Thus, only the `typedef`ed type should be used
* to store the flags.
*/
typedef uint8_t sock_aux_flags_t;
#ifdef __cplusplus
}
#endif

View File

@ -297,6 +297,51 @@ typedef struct sock_ip sock_ip_t;
# pragma clang diagnostic pop
#endif
/**
* @brief Auxiliary data provided when receiving using an IP sock object
*/
typedef struct {
#if defined(MODULE_SOCK_AUX_LOCAL) || defined(DOXYGEN)
/**
* @brief The local address the packet was received on
*
* @see SOCK_AUX_GET_LOCAL
*/
sock_ip_ep_t local;
#endif /* MODULE_SOCK_AUX_ENDPOINT */
#if defined(MODULE_SOCK_AUX_TIMESTAMP) || defined(DOXYGEN)
/**
* @brief System time the packet was received
*
* @see SOCK_AUX_GET_TIMESTAMP
*/
uint64_t timestamp;
#endif /* MODULE_SOCK_AUX_TIMESTAP*/
sock_aux_flags_t flags; /**< Flags used request information */
} sock_ip_aux_rx_t;
/**
* @brief Auxiliary data provided when sending using an IP sock object
*/
typedef struct {
#if defined(MODULE_SOCK_AUX_TIMESTAMP) || defined(DOXYGEN)
/**
* @brief System time the packet was send
*
* Add @ref SOCK_AUX_GET_TIMESTAMP to the bitmask in
* @ref sock_ip_aux_tx_t::flags to request a transmission timestamp. This
* bit will be cleared by @ref sock_ip_send_aux if and only if the timestamp
* was provided. The module `sock_aux_timestamp` needs to be selected to use
* this. The timestamp refers to the transmission of start of frame
* delimiter or preamble of the frame carrying the IP packet and is given in
* nanoseconds since epoch, unless otherwise documented by the underlying
* implementation.
*/
uint64_t timestamp;
#endif /* MODULE_SOCK_AUX_TIMESTAP*/
sock_aux_flags_t flags; /**< Flags used request information */
} sock_ip_aux_tx_t;
/**
* @brief Creates a new raw IPv4/IPv6 sock object
*
@ -406,6 +451,8 @@ int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep);
* data is available).
* @param[out] remote Remote end point of the received data.
* May be NULL, if it is not required by the application.
* @param[out] aux Auxiliary data of the reception.
* May be NULL, if it is not required by the application.
*
* @note Function blocks if no packet is currently waiting.
*
@ -422,8 +469,94 @@ int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep);
* the remote of @p sock.
* @return -ETIMEDOUT, if @p timeout expired.
*/
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote);
ssize_t sock_ip_recv_aux(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux);
/**
* @brief Receives a message over IPv4/IPv6 from remote end point
*
* @pre `(sock != NULL) && (data != NULL) && (max_len > 0)`
*
* @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.
* @param[in] timeout Timeout for receive in microseconds.
* If 0 and no data is available, the function returns
* immediately.
* May be @ref SOCK_NO_TIMEOUT for no timeout (wait until
* data is available).
* @param[out] 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 The number of bytes received on success.
* @return 0, if no received data is available, but everything is in order.
* @return -EADDRNOTAVAIL, if local of @p sock is not given.
* @return -EAGAIN, if @p timeout is `0` and no data is available.
* @return -EINVAL, if @p remote is invalid or @p sock is not properly
* initialized (or closed while sock_ip_recv() blocks).
* @return -ENOBUFS, if buffer space is not large enough to store received
* data.
* @return -ENOMEM, if no memory was available to receive @p data.
* @return -EPROTO, if source address of received packet did not equal
* the remote of @p sock.
* @return -ETIMEDOUT, if @p timeout expired.
*/
static inline ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote)
{
return sock_ip_recv_aux(sock, data, max_len, timeout, remote, NULL);
}
/**
* @brief Provides stack-internal buffer space containing an IPv4/IPv6
* message from remote end point
*
* @pre `(sock != NULL) && (data != NULL) && (buf_ctx != NULL)`
*
* @param[in] sock A raw IPv4/IPv6 sock object.
* @param[out] data Pointer to a stack-internal buffer space containing the
* received data.
* @param[in,out] buf_ctx Stack-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.
* @param[in] timeout Timeout for receive in microseconds.
* If 0 and no data is available, the function returns
* immediately.
* May be @ref SOCK_NO_TIMEOUT for no timeout (wait until
* data is available).
* @param[out] remote Remote end point of the received data.
* May be NULL, if it is not required by the application.
* @param[out] aux Auxiliary data of the reception.
* May be NULL, if it is not required by the application.
*
* @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.
*
* @return 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.
* @return 0, if no received data is available, but everything is in order.
* If @p buf_ctx was provided, it was released.
* @return -EADDRNOTAVAIL, if local of @p sock is not given.
* @return -EAGAIN, if @p timeout is `0` and no data is available.
* @return -EINVAL, if @p remote is invalid or @p sock is not properly
* initialized (or closed while sock_ip_recv() blocks).
* @return -ENOMEM, if no memory was available to receive @p data.
* @return -EPROTO, if source address of received packet did not equal
* the remote of @p sock.
* @return -ETIMEDOUT, if @p timeout expired.
*/
ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux);
/**
* @brief Provides stack-internal buffer space containing an IPv4/IPv6
@ -467,8 +600,50 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
* the remote of @p sock.
* @return -ETIMEDOUT, if @p timeout expired.
*/
ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **buf_ctx,
uint32_t timeout, sock_ip_ep_t *remote);
static inline ssize_t sock_ip_recv_buf(sock_ip_t *sock,
void **data, void **buf_ctx,
uint32_t timeout, sock_ip_ep_t *remote)
{
return sock_ip_recv_buf_aux(sock, data, buf_ctx, timeout, remote, NULL);
}
/**
* @brief Sends a message over IPv4/IPv6 to remote end point
*
* @pre `((sock != NULL || remote != NULL)) && (if (len != 0): (data != NULL))`
*
* @param[in] sock A raw IPv4/IPv6 sock object. May be NULL.
* A sensible local end point should be selected by the
* 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 sent, in case
* `sock == NULL`. If `sock != NULL` this parameter will be
* ignored.
* @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.
* @param[out] aux Auxiliary data for the transmission.
* May be `NULL` if not needed by the caller.
*
* @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 -EINVAL, if sock_ip_ep_t::addr of @p remote is an invalid address.
* @return -EINVAL, if sock_ip_ep_t::netif of @p remote is not a
* valid interface or contradicts the local interface of @p sock.
* @return -EHOSTUNREACH, if @p remote or remote end point of @p sock is not
* reachable.
* @return -ENOMEM, if no memory was available to send @p data.
* @return -ENOTCONN, if `remote == NULL`, but @p sock has no remote end point.
* @return -EPROTOTYPE, if `sock == NULL` and @p proto is not by
* sock_ip_ep_t::family of @p remote.
*/
ssize_t sock_ip_send_aux(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote,
sock_ip_aux_tx_t *aux);
/**
* @brief Sends a message over IPv4/IPv6 to remote end point
@ -502,8 +677,12 @@ ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **buf_ctx,
* @return -EPROTOTYPE, if `sock == NULL` and @p proto is not by
* sock_ip_ep_t::family of @p remote.
*/
ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote);
static inline ssize_t sock_ip_send(sock_ip_t *sock,
const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote)
{
return sock_ip_send_aux(sock, data, len, proto, remote, NULL);
}
#include "sock_types.h"

View File

@ -87,8 +87,9 @@ int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *remote)
return 0;
}
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote)
ssize_t sock_ip_recv_aux(sock_ip_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux)
{
void *pkt = NULL, *ctx = NULL;
uint8_t *ptr = data;
@ -96,7 +97,7 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
bool nobufs = false;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
while ((res = sock_ip_recv_buf(sock, &pkt, &ctx, timeout, remote)) > 0) {
while ((res = sock_ip_recv_buf_aux(sock, &pkt, &ctx, timeout, remote, aux)) > 0) {
if (res > (ssize_t)max_len) {
nobufs = true;
continue;
@ -108,9 +109,11 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
return (nobufs) ? -ENOBUFS : ((res < 0) ? res : ret);
}
ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **buf_ctx,
uint32_t timeout, sock_ip_ep_t *remote)
ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
uint32_t timeout, sock_ip_ep_t *remote,
sock_ip_aux_rx_t *aux)
{
(void)aux;
gnrc_pktsnip_t *pkt;
sock_ip_ep_t tmp;
int res;
@ -149,9 +152,11 @@ ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **buf_ctx,
return res;
}
ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote)
ssize_t sock_ip_send_aux(sock_ip_t *sock, const void *data, size_t len,
uint8_t proto, const sock_ip_ep_t *remote,
sock_ip_aux_tx_t *aux)
{
(void)aux;
int res;
gnrc_pktsnip_t *pkt;
sock_ip_ep_t local;