Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ endif
ifneq (,$(filter sock_async_event,$(USEMODULE)))
DIRS += net/sock/async/event
endif
ifneq (,$(filter sock_async_msg,$(USEMODULE)))
DIRS += net/sock/async/msg
endif
ifneq (,$(filter sock_dns,$(USEMODULE)))
DIRS += net/application_layer/sock_dns
endif
Expand Down
4 changes: 4 additions & 0 deletions sys/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ ifneq (,$(filter sock_async_event,$(USEMODULE)))
include $(RIOTBASE)/sys/net/sock/async/event/Makefile.include
endif

ifneq (,$(filter sock_async_msg,$(USEMODULE)))
include $(RIOTBASE)/sys/net/sock/async/msg/Makefile.include
endif

ifneq (,$(filter ssp,$(USEMODULE)))
include $(RIOTBASE)/sys/ssp/Makefile.include
endif
Expand Down
313 changes: 313 additions & 0 deletions sys/include/net/sock/async/msg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup net_sock_async_msg Asynchronous sock with messaging / IPC
* @ingroup net_sock
* @brief Provides an implementation of asynchronous sock for
* @ref core_msg
*
* How To Use
* ----------
*
* You need to [include](@ref including-modules) at least one module that
* implements a [`sock` API](@ref net_sock) and the module `sock_async_event` in
* your application's Makefile.
*
* For the following example [`sock_udp`](@ref net_sock_udp) is used. It is
* however easily adaptable for other `sock` types:
*
* ### An asynchronous UDP Echo server using the event API
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* #include <stdio.h>
*
* #include "msg.h"
* #include "thread.h"
* #include "net/sock/udp.h"
* #include "net/sock/async/msg.h"
*
* msg_t queue[8];
* uint8_t buf[128];
*
* void handler(sock_udp_t *sock, sock_async_flags_t type, void *arg)
* {
* (void)arg;
* if (type & SOCK_ASYNC_MSG_RECV) {
* 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");
* }
* }
* }
* }
*
* int main(void)
* {
* sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
*
* local.port = 12345;
*
* if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
* puts("Error creating UDP sock");
* return 1;
* }
*
* msg_init_queue(&queue, 8);
* sock_udp_msg_init(&sock, thread_getpid(), handler, NULL);
* while (1) {
* msg_t msg;
*
* msg_receive(&msg);
* if (sock_async_msg_is(&msg)) {
* sock_async_msg_handler(&msg);
* }
* }
* 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 the header file for @ref net_sock_udp "UDP sock" and
* @ref net_sock_async_msg "asynchronous handling", we create a message queue
* `queue` (note: [must be of a size equal to a power of two]
* (@ref msg_init_queue)) and allocate some buffer space `buf` to store the
* data received by the server:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* #include "net/sock/udp.h"
* #include "net/sock/async/msg.h"
*
* msg_t queue[8];
* uint8_t buf[128];
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* We then define an event handler in form of a function. The event handler
* checks if the triggering event was a receive event by checking the flags
* provided with sock_event_t::type. If it is a receive event it copies the
* incoming message to `buf` and its sender into `remote` using @ref
* sock_udp_recv(). Note, that we use @ref sock_udp_recv() non-blocking by
* setting `timeout` to 0. If an error occurs on receive, we just ignore it and
* return from the event handler.
*
* If we receive a message we use its `remote` to reply. In case of an error on
* send, we print an according message:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* void handler(sock_udp_t *sock, sock_async_flags_t type, void *arg)
* {
* (void)arg;
* if (type & SOCK_ASYNC_MSG_RECV) {
* 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");
* }
* }
* }
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* To be able to listen for incoming packets we bind the `sock` by setting a
* local end point 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;
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* We then initialize the message queue for the running thread to allow for
* asynchronous IPC (see @ref core_msg) and register the current thread as the
* asynchronous event handler for `sock` using the previously defined
* `handler()` function.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* msg_init_queue(&queue, 8);
* sock_udp_msg_init(&sock, thread_getpid(), handler, NULL);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* The thread then blocks to wait for an IPC message and check if the event
* triggering the IPC message was an asynchronous sock event.
* If it is an asynchronous sock event, the handler function is called, which
* in turn calls the registered callback:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* msg_t msg;
*
* msg_receive(&msg);
* if (sock_async_msg_is(&msg)) {
* sock_async_msg_handler(&msg);
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @{
*
* @file
* @brief
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_SOCK_ASYNC_MSG_H
#define NET_SOCK_ASYNC_MSG_H

#include "kernel_types.h"
#include "msg.h"
#include "net/sock/async.h"
#ifdef MODULE_SOCK_DTLS
#include "net/sock/dtls.h"
#endif /* MODULE_SOCK_DTLS */
#include "net/sock/ip.h"
#include "net/sock/tcp.h"
#include "net/sock/udp.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Message type mask for all messages notifying events on the sock.
*
* The event flags of a sock event are identified by checking the respective
* bits in the message type:
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* if (sock_async_msg_type(&msg) && msg.type & SOCK_EVENT_CONN_RDY) {
* // ... the connection of msg.content.ptr is ready
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define SOCK_ASYNC_MSG_TYPE_MASK (0xff00)

/**
* @brief Message type ID for all messages notifying events on the sock.
*/
#define SOCK_ASYNC_MSG_TYPE_ID (0x8500)

/**
* @brief Checks if a given message is a @ref net_sock_async_msg message
*
* @param[in] msg A message.
*/
static inline bool sock_async_msg_is(msg_t *msg)
{
return (msg->type & SOCK_ASYNC_MSG_TYPE_MASK) == SOCK_ASYNC_MSG_TYPE_ID;
}

static inline sock_async_flags_t sock_async_msg_flags(msg_t *msg)
{
return msg->type & ~SOCK_ASYNC_MSG_TYPE_MASK;
}

/**
* @brief Handles a `sock_async_msg` IPC message and calls the associated
* callback.
*
* @pre @ref sock_async_msg_is(@p msg)
*
* @param[in] msg An IPC message.
*/
void sock_async_msg_handler(msg_t *msg);

#if defined(MODULE_SOCK_DTLS) || defined(DOXYGEN)
/**
* @brief Makes a DTLS sock able to handle asynchronous events using
* @ref core_msg.
*
* @param[in] sock A DTLS sock object.
* @param[in] target Thread to send the events to.
*
* @note Only available with module `sock_dtls`.
*/
void sock_dtls_msg_init(sock_dtls_t *sock, kernel_pid_t target,
sock_dtls_cb_t handler, void *handler_arg);
#endif /* defined(MODULE_SOCK_DTLS) || defined(DOXYGEN) */

#if defined(MODULE_SOCK_IP) || defined(DOXYGEN)
/**
* @brief Makes a raw IPv4/IPv6 sock able to handle asynchronous events using
* @ref core_msg.
*
* @param[in] sock A raw IPv4/IPv6 sock object.
* @param[in] target Thread to send the events to.
*
* @note Only available with module `sock_ip`.
*/
void sock_ip_msg_init(sock_ip_t *sock, kernel_pid_t target,
sock_ip_cb_t handler, void *handler_arg);
#endif /* defined(MODULE_SOCK_IP) || defined(DOXYGEN) */

#if defined(MODULE_SOCK_TCP) || defined(DOXYGEN)
/**
* @brief Makes a TCP sock able to handle asynchronous events using
* @ref core_msg.
*
* @param[in] sock A TCP sock object.
* @param[in] target Thread to send the events to.
*
* @note Only available with module `sock_tcp`.
*/
void sock_tcp_msg_init(sock_tcp_t *sock, kernel_pid_t target,
sock_tcp_cb_t handler, void *handler_arg);

/**
* @brief Makes a TCP listening queue able to handle asynchronous events using
* @ref core_msg.
*
* @param[in] sock A TCP listening queue.
* @param[in] target Thread to send the events to.
*
* @note Only available with module `sock_tcp`.
*/
void sock_tcp_queue_msg_init(sock_tcp_queue_t *sock, kernel_pid_t target,
sock_udp_tcp_t handler, void *handler_arg);
#endif /* defined(MODULE_SOCK_TCP) || defined(DOXYGEN) */

#if defined(MODULE_SOCK_UDP) || defined(DOXYGEN)
/**
* @brief Makes a UDP sock able to handle asynchronous events using
* @ref core_msg.
*
* @param[in] sock A UDP sock object.
* @param[in] target Thread to send the events to.
*
* @note Only available with module `sock_udp`.
*/
void sock_udp_msg_init(sock_udp_t *sock, kernel_pid_t target,
sock_udp_cb_t handler, void *handler_arg);
#endif /* defined(MODULE_SOCK_UDP) || defined(DOXYGEN) */

#ifdef __cplusplus
}
#endif

#endif /* NET_SOCK_ASYNC_MSG_H */
/** @} */
3 changes: 3 additions & 0 deletions sys/net/sock/async/msg/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE := sock_async_msg

include $(RIOTBASE)/Makefile.base
2 changes: 2 additions & 0 deletions sys/net/sock/async/msg/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/sock/async/msg
CFLAGS += -DSOCK_HAS_ASYNC -DSOCK_HAS_ASYNC_CTX
Loading