Skip to content

Commit 477bcc0

Browse files
committed
sock_async_event: initial import of event-based implementation
1 parent 024cea8 commit 477bcc0

File tree

8 files changed

+471
-0
lines changed

8 files changed

+471
-0
lines changed

Makefile.dep

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,11 @@ ifneq (,$(filter vfs,$(USEMODULE)))
788788
endif
789789
endif
790790

791+
ifneq (,$(filter sock_async_event,$(USEMODULE)))
792+
USEMODULE += sock_async
793+
USEMODULE += event
794+
endif
795+
791796
ifneq (,$(filter sock_dns,$(USEMODULE)))
792797
USEMODULE += sock_util
793798
USEMODULE += posix_headers

sys/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ endif
112112
ifneq (,$(filter emcute,$(USEMODULE)))
113113
DIRS += net/application_layer/emcute
114114
endif
115+
ifneq (,$(filter sock_async_event,$(USEMODULE)))
116+
DIRS += net/sock/async/event
117+
endif
115118
ifneq (,$(filter sock_util,$(USEMODULE)))
116119
DIRS += net/sock
117120
endif

sys/Makefile.include

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ ifneq (,$(filter riotboot,$(FEATURES_USED)))
9292
include $(RIOTBASE)/sys/riotboot/Makefile.include
9393
endif
9494

95+
ifneq (,$(filter sock_async_event,$(USEMODULE)))
96+
include $(RIOTBASE)/sys/net/sock/async/event/Makefile.include
97+
endif
98+
9599
ifneq (,$(filter ssp,$(USEMODULE)))
96100
include $(RIOTBASE)/sys/ssp/Makefile.include
97101
endif

sys/include/net/sock/async/event.h

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* Copyright (C) 2019 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @defgroup net_sock_async_event Asynchronous sock with event API
11+
* @ingroup net_sock
12+
* @brief Provides an implementation of asynchronous sock for
13+
* @ref sys_event
14+
*
15+
* How To Use
16+
* ----------
17+
*
18+
* You need to [include](@ref including-modules) at least one module that
19+
* implements a [`sock` API](@ref net_sock) and the module `sock_async_event` in
20+
* your application's Makefile.
21+
*
22+
* For the following example [`sock_udp`](@ref net_sock_udp) is used. It is
23+
* however easily adaptable for other `sock` types:
24+
*
25+
* ### An asynchronous UDP Echo server using the event API
26+
*
27+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
28+
* #include <stdio.h>
29+
*
30+
* #include "net/sock/udp.h"
31+
* #include "net/sock/async/event.h"
32+
*
33+
* event_queue_t queue;
34+
* uint8_t buf[128];
35+
*
36+
* int handler(sock_udp_t *sock, sock_async_flags_t type)
37+
* {
38+
* if (type & SOCK_EVENT_MSG_RECV) {
39+
* sock_udp_ep_t remote;
40+
* ssize_t res;
41+
*
42+
* if ((res = sock_udp_recv(sock, buf, sizeof(buf), 0,
43+
* &remote)) >= 0) {
44+
* puts("Received a message");
45+
* if (sock_udp_send(sock, buf, res, &remote) < 0) {
46+
* puts("Error sending reply");
47+
* }
48+
* }
49+
* }
50+
* }
51+
*
52+
* int main(void)
53+
* {
54+
* sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
55+
* sock_udp_t sock;
56+
*
57+
* local.port = 12345;
58+
*
59+
* if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
60+
* puts("Error creating UDP sock");
61+
* return 1;
62+
* }
63+
*
64+
* event_queue_init(&queue);
65+
* sock_udp_event_init(&sock, &queue, handler);
66+
* event_loop(&queue);
67+
* return 0;
68+
* }
69+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
70+
*
71+
* Above you see a simple UDP echo server using @ref sys_event. Don't forget to
72+
* also @ref including-modules "include" the IPv6 module of your networking
73+
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
74+
* one network device.
75+
*
76+
* After including the header file for @ref net_sock_udp "UDP sock" and
77+
* @ref net_sock_async_event "asynchronous handling", we create the event queue
78+
* `queue` and allocate some buffer space `buf` to store the data received by
79+
* the server:
80+
*
81+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
82+
* #include "net/sock/udp.h"
83+
* #include "net/sock/async/event.h"
84+
*
85+
* event_queue_t queue;
86+
* uint8_t buf[128];
87+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88+
*
89+
* We then define an event handler in form of a function. The event handler
90+
* checks if the triggering event was a receive event by checking the flags
91+
* provided with sock_event_t::type. If it is a receive event it copies the
92+
* incoming message to `buf` and its sender into `remote` using @ref
93+
* sock_udp_recv(). Note, that we use @ref sock_udp_recv() non-blocking by
94+
* setting `timeout` to 0. If an error occurs on receive, we just ignore it and
95+
* return from the event handler.
96+
*
97+
* If we receive a message we use its `remote` to reply. In case of an error on
98+
* send, we print an according message:
99+
*
100+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
101+
* int handler(sock_udp_t *sock, sock_async_flags_t type)
102+
* {
103+
* if (type & SOCK_EVENT_MSG_RECV) {
104+
* sock_udp_ep_t remote;
105+
* ssize_t res;
106+
*
107+
* if ((res = sock_udp_recv(sock, buf, sizeof(buf), 0,
108+
* &remote)) >= 0) {
109+
* puts("Received a message");
110+
* if (sock_udp_send(sock, buf, res, &remote) < 0) {
111+
* puts("Error sending reply");
112+
* }
113+
* }
114+
* }
115+
* }
116+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117+
*
118+
* To be able to listen for incoming packets we bind the `sock` by setting a
119+
* local end point with a port (`12345` in this case).
120+
*
121+
* We then proceed to create the `sock`. It is bound to `local` and thus listens
122+
* for UDP packets with @ref udp_hdr_t::dst_port "destination port" `12345`.
123+
* Since we don't need any further configuration we set the flags to 0.
124+
* In case of an error we stop the program:
125+
*
126+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
127+
* sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
128+
* sock_udp_t sock;
129+
*
130+
* local.port = 12345;
131+
*
132+
* if (sock_udp_create(&sock, &local, NULL, 0) < 0) {
133+
* puts("Error creating UDP sock");
134+
* return 1;
135+
* }
136+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
137+
*
138+
* Finally, we initialize the event queue `queue`, initialize asynchronous event
139+
* handling for `sock` using it and the previously defined event handler, and go
140+
* into an endless loop to handle all occurring events on `queue`:
141+
*
142+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
143+
* event_queue_init(&queue);
144+
* sock_udp_event_init(&sock, &queue, handler);
145+
* event_loop(&queue);
146+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147+
*
148+
* @{
149+
*
150+
* @file
151+
* @brief Asynchronous sock using @ref sys_event definitions.
152+
*
153+
* @author Martine Lenders <[email protected]>
154+
* @author Kaspar Schleiser <[email protected]>
155+
*/
156+
#ifndef NET_SOCK_ASYNC_EVENT_H
157+
#define NET_SOCK_ASYNC_EVENT_H
158+
159+
#include "event.h"
160+
#include "net/sock/async.h"
161+
/* guard required since `sock_dtls_types.h` might not be provided */
162+
#ifdef MODULE_SOCK_DTLS
163+
#include "net/sock/dtls.h"
164+
#endif /* MODULE_SOCK_DTLS */
165+
#include "net/sock/ip.h"
166+
#include "net/sock/tcp.h"
167+
#include "net/sock/udp.h"
168+
169+
#ifdef __cplusplus
170+
extern "C" {
171+
#endif
172+
173+
/* guard required since `sock_dtls_types.h` might not be provided */
174+
#if defined(MODULE_SOCK_DTLS) || defined(DOXYGEN)
175+
/**
176+
* @brief Makes a DTLS sock able to handle asynchronous events using
177+
* @ref sys_event.
178+
*
179+
* @param[in] sock A DTLS sock object.
180+
* @param[in] ev_queue The queue the events on @p sock will be added to.
181+
* @param[in] handler The event handler function to call on an event on
182+
* @p sock.
183+
*
184+
* @note Only available with module `sock_dtls`.
185+
*/
186+
void sock_dtls_event_init(sock_dtls_t *sock, event_queue_t *ev_queue,
187+
sock_dtls_cb_t handler);
188+
#endif /* defined(MODULE_SOCK_DTLS) || defined(DOXYGEN) */
189+
190+
#if defined(MODULE_SOCK_IP) || defined(DOXYGEN)
191+
/**
192+
* @brief Makes a raw IPv4/IPv6 sock able to handle asynchronous events using
193+
* @ref sys_event.
194+
*
195+
* @param[in] sock A raw IPv4/IPv6 sock object.
196+
* @param[in] ev_queue The queue the events on @p sock will be added to.
197+
* @param[in] handler The event handler function to call on an event on
198+
* @p sock.
199+
*
200+
* @note Only available with module `sock_ip`.
201+
*/
202+
void sock_ip_event_init(sock_ip_t *sock, event_queue_t *ev_queue,
203+
sock_ip_cb_t handler);
204+
#endif /* defined(MODULE_SOCK_IP) || defined(DOXYGEN) */
205+
206+
#if defined(MODULE_SOCK_TCP) || defined(DOXYGEN)
207+
/**
208+
* @brief Makes a TCP sock able to handle asynchronous events using
209+
* @ref sys_event.
210+
*
211+
* @param[in] sock A TCP sock object.
212+
* @param[in] ev_queue The queue the events on @p sock will be added to.
213+
* @param[in] handler The event handler function to call on an event on
214+
* @p sock.
215+
*
216+
* @note Only available with module `sock_tcp`.
217+
*/
218+
void sock_tcp_event_init(sock_tcp_t *sock, event_queue_t *ev_queue,
219+
sock_tcp_cb_t handler);
220+
221+
/**
222+
* @brief Makes a TCP listening queue able to handle asynchronous events using
223+
* @ref sys_event.
224+
*
225+
* @param[in] queue A TCP listening queue.
226+
* @param[in] ev_queue The queue the events on @p sock will be added to.
227+
* @param[in] handler The event handler function to call on an event on
228+
* @p sock.
229+
*
230+
* @note Only available with module `sock_tcp`.
231+
*/
232+
void sock_tcp_queue_event_init(sock_tcp_queue_t *queue, event_queue_t *ev_queue,
233+
sock_tcp_queue_cb_t handler);
234+
#endif /* defined(MODULE_SOCK_TCP) || defined(DOXYGEN) */
235+
236+
#if defined(MODULE_SOCK_UDP) || defined(DOXYGEN)
237+
/**
238+
* @brief Makes a UDP sock able to handle asynchronous events using
239+
* @ref sys_event.
240+
*
241+
* @param[in] sock A UDP sock object.
242+
* @param[in] ev_queue The queue the events on @p sock will be added to.
243+
* @param[in] handler The event handler function to call on an event on
244+
* @p sock.
245+
*
246+
* @note Only available with module `sock_udp`.
247+
*/
248+
void sock_udp_event_init(sock_udp_t *sock, event_queue_t *ev_queue,
249+
sock_udp_cb_t handler);
250+
#endif /* defined(MODULE_SOCK_UDP) || defined(DOXYGEN) */
251+
252+
#ifdef __cplusplus
253+
}
254+
#endif
255+
256+
#endif /* NET_SOCK_ASYNC_EVENT_H */
257+
/** @} */

sys/net/sock/async/event/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
MODULE := sock_async_event
2+
3+
include $(RIOTBASE)/Makefile.base
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/sock/async/event
2+
CFLAGS += -DSOCK_HAS_ASYNC -DSOCK_HAS_ASYNC_CTX
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2019 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @addtogroup net_sock_async_event
11+
* @{
12+
*
13+
* @file
14+
* @brief Type definitions for asynchronous socks with @ref sys_event
15+
*
16+
* @author Martine Lenders <[email protected]>
17+
*/
18+
#ifndef SOCK_ASYNC_CTX_H
19+
#define SOCK_ASYNC_CTX_H
20+
21+
#include "event.h"
22+
23+
#ifdef __cplusplus
24+
extern "C" {
25+
#endif
26+
27+
/**
28+
* @brief Generalized callback type
29+
*/
30+
typedef union {
31+
void (*generic)(void *, sock_async_flags_t); /**< anything goes */
32+
#ifdef MODULE_SOCK_DTLS
33+
sock_dtls_cb_t dtls; /**< DTLS callback */
34+
#endif
35+
#ifdef MODULE_SOCK_IP
36+
sock_ip_cb_t ip; /**< IP callback */
37+
#endif
38+
#ifdef MODULE_SOCK_TCP
39+
sock_tcp_cb_t tcp; /**< TCP callback */
40+
sock_tcp_queue_cb_t tcp_queue; /**< TCP queue callback */
41+
#endif
42+
#ifdef MODULE_SOCK_UDP
43+
sock_udp_cb_t udp; /**< UDP callback */
44+
#endif
45+
} sock_event_cb_t;
46+
47+
/**
48+
* @brief Event definition for context scope
49+
*/
50+
typedef struct {
51+
event_t super; /**< event structure that gets extended */
52+
sock_event_cb_t cb; /**< callback */
53+
void *sock; /**< generic pointer to a @ref net_sock object */
54+
sock_async_flags_t type; /**< types of the event */
55+
} sock_event_t;
56+
57+
/**
58+
* @brief Asynchronous context for @ref net_sock_async_event
59+
*/
60+
typedef struct {
61+
sock_event_t event; /**< event storage */
62+
event_queue_t *queue; /**< event queue to post socket events to */
63+
} sock_async_ctx_t;
64+
65+
66+
#ifdef __cplusplus
67+
}
68+
#endif
69+
70+
#endif /* SOCK_ASYNC_CTX_H */
71+
/** @} */

0 commit comments

Comments
 (0)