Skip to content

Commit 0f25aec

Browse files
committed
sock/async: cancel sock async events when closing the socket
1 parent 775f596 commit 0f25aec

9 files changed

Lines changed: 211 additions & 0 deletions

File tree

pkg/lwip/contrib/sock/ip/lwip_sock_ip.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
#include "lwip/sys.h"
3131
#include "lwip/sock_internal.h"
3232

33+
#ifdef SOCK_HAS_ASYNC_CTX
34+
#include "net/sock/async/event.h"
35+
#endif
36+
3337
int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
3438
const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
3539
{
@@ -60,6 +64,9 @@ void sock_ip_close(sock_ip_t *sock)
6064
netconn_delete(sock->base.conn);
6165
sock->base.conn = NULL;
6266
}
67+
#ifdef SOCK_HAS_ASYNC_CTX
68+
sock_event_close(sock_ip_get_async_ctx(sock));
69+
#endif
6370
}
6471

6572
int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *ep)

pkg/lwip/contrib/sock/tcp/lwip_sock_tcp.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include "lwip/api.h"
2525
#include "lwip/opt.h"
2626

27+
#ifdef SOCK_HAS_ASYNC_CTX
28+
#include "net/sock/async/event.h"
29+
#endif
30+
2731
static inline void _tcp_sock_init(sock_tcp_t *sock, struct netconn *conn,
2832
sock_tcp_queue_t *queue)
2933
{
@@ -125,6 +129,10 @@ void sock_tcp_disconnect(sock_tcp_t *sock)
125129
}
126130
}
127131

132+
#ifdef SOCK_HAS_ASYNC_CTX
133+
sock_event_close(sock_tcp_get_async_ctx(sock));
134+
#endif
135+
128136
mutex_unlock(&sock->mutex);
129137
memset(&sock->mutex, 0, sizeof(mutex_t));
130138
}

pkg/lwip/contrib/sock/udp/lwip_sock_udp.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include "lwip/sys.h"
2828
#include "lwip/udp.h"
2929

30+
#ifdef SOCK_HAS_ASYNC_CTX
31+
#include "net/sock/async/event.h"
32+
#endif
33+
3034
int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
3135
const sock_udp_ep_t *remote, uint16_t flags)
3236
{
@@ -56,6 +60,9 @@ void sock_udp_close(sock_udp_t *sock)
5660
netconn_delete(sock->base.conn);
5761
sock->base.conn = NULL;
5862
}
63+
#ifdef SOCK_HAS_ASYNC_CTX
64+
sock_event_close(sock_udp_get_async_ctx(sock));
65+
#endif
5966
}
6067

6168
int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *ep)

pkg/openwsn/sock/openwsn_sock_udp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ void sock_udp_close(sock_udp_t *sock)
349349
LL_DELETE(_udp_socket_list, sock);
350350
mutex_unlock(&_sock_list_lock);
351351
sock->next = NULL;
352+
#ifdef SOCK_HAS_ASYNC_CTX
353+
sock_event_close(sock_udp_get_async_ctx(udp));
354+
#endif
352355
}
353356
}
354357

pkg/tinydtls/contrib/sock_dtls.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,9 @@ ssize_t sock_dtls_recv_buf_aux(sock_dtls_t *sock, sock_dtls_session_t *remote,
939939
void sock_dtls_close(sock_dtls_t *sock)
940940
{
941941
dtls_free_context(sock->dtls_ctx);
942+
#ifdef SOCK_HAS_ASYNC_CTX
943+
sock_event_close(sock_dtls_get_async_ctx(sock));
944+
#endif
942945
}
943946

944947
void sock_dtls_init(void)

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525
* For the following example [`sock_udp`](@ref net_sock_udp) is used. It is
2626
* however easily adaptable for other `sock` types:
2727
*
28+
* @warning An async socket may only be closed from the same thread that
29+
* processes the queue. This is because there is no way to prevent the
30+
* networking subsystem from posting socket events other than calling
31+
* sock_*_close(), which would then race against these events. If
32+
* unsure, use sock_*_event_close(), which will close the socket on
33+
* the correct thread.
34+
*
2835
* ### An asynchronous UDP Echo server using the event API
2936
*
3037
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
@@ -191,6 +198,15 @@ extern "C" {
191198
*/
192199
void sock_dtls_event_init(sock_dtls_t *sock, event_queue_t *ev_queue,
193200
sock_dtls_cb_t handler, void *handler_arg);
201+
202+
/**
203+
* @brief Close a possibly async DTLS socket
204+
*
205+
* Helper function that closes a possibly async socket on the event thread.
206+
*
207+
* @param sock socket
208+
*/
209+
void sock_dtls_event_close(sock_dtls_t *sock);
194210
#endif /* defined(MODULE_SOCK_DTLS) || defined(DOXYGEN) */
195211

196212
#if defined(MODULE_SOCK_IP) || defined(DOXYGEN)
@@ -208,6 +224,15 @@ void sock_dtls_event_init(sock_dtls_t *sock, event_queue_t *ev_queue,
208224
*/
209225
void sock_ip_event_init(sock_ip_t *sock, event_queue_t *ev_queue,
210226
sock_ip_cb_t handler, void *handler_arg);
227+
228+
/**
229+
* @brief Close a possibly async IP socket
230+
*
231+
* Helper function that closes a possibly async socket on the event thread.
232+
*
233+
* @param sock socket
234+
*/
235+
void sock_ip_event_close(sock_ip_t *sock);
211236
#endif /* defined(MODULE_SOCK_IP) || defined(DOXYGEN) */
212237

213238
#if defined(MODULE_SOCK_TCP) || defined(DOXYGEN)
@@ -226,6 +251,15 @@ void sock_ip_event_init(sock_ip_t *sock, event_queue_t *ev_queue,
226251
void sock_tcp_event_init(sock_tcp_t *sock, event_queue_t *ev_queue,
227252
sock_tcp_cb_t handler, void *handler_arg);
228253

254+
/**
255+
* @brief Close a possibly async TCP socket
256+
*
257+
* Helper function that closes a possibly async socket on the event thread.
258+
*
259+
* @param sock socket
260+
*/
261+
void sock_tcp_event_close(sock_tcp_t *sock);
262+
229263
/**
230264
* @brief Makes a TCP listening queue able to handle asynchronous events using
231265
* @ref sys_event.
@@ -257,8 +291,28 @@ void sock_tcp_queue_event_init(sock_tcp_queue_t *queue, event_queue_t *ev_queue,
257291
*/
258292
void sock_udp_event_init(sock_udp_t *sock, event_queue_t *ev_queue,
259293
sock_udp_cb_t handler, void *handler_arg);
294+
295+
/**
296+
* @brief Close a possibly async UDP socket
297+
*
298+
* Helper function that closes a possibly async socket on the event thread.
299+
*
300+
* @param sock socket
301+
*/
302+
void sock_udp_event_close(sock_udp_t *sock);
303+
260304
#endif /* defined(MODULE_SOCK_UDP) || defined(DOXYGEN) */
261305

306+
/**
307+
* @brief clear any pending socket async events
308+
*
309+
* @warning Do not call this in the application, it is automatically called by
310+
* sock_*_close().
311+
*
312+
* @param[in] async_ctx socket async context
313+
*/
314+
void sock_event_close(sock_async_ctx_t *async_ctx);
315+
262316
#ifdef __cplusplus
263317
}
264318
#endif

sys/net/gnrc/sock/ip/gnrc_sock_ip.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
#include "gnrc_sock_internal.h"
3030

31+
#ifdef SOCK_HAS_ASYNC_CTX
32+
#include "net/sock/async/event.h"
33+
#endif
34+
3135
int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
3236
const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
3337
{
@@ -65,6 +69,9 @@ void sock_ip_close(sock_ip_t *sock)
6569
{
6670
assert(sock != NULL);
6771
gnrc_netreg_unregister(GNRC_NETTYPE_IPV6, &sock->reg.entry);
72+
#ifdef SOCK_HAS_ASYNC_CTX
73+
sock_event_close(sock_ip_get_async_ctx(sock));
74+
#endif
6875
}
6976

7077
int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *local)

sys/net/gnrc/sock/udp/gnrc_sock_udp.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include "net/udp.h"
2929
#include "random.h"
3030

31+
#ifdef SOCK_HAS_ASYNC_CTX
32+
#include "net/sock/async/event.h"
33+
#endif
34+
3135
#include "gnrc_sock_internal.h"
3236

3337
#define ENABLE_DEBUG 0
@@ -155,6 +159,9 @@ void sock_udp_close(sock_udp_t *sock)
155159
{
156160
assert(sock != NULL);
157161
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &sock->reg.entry);
162+
#ifdef SOCK_HAS_ASYNC_CTX
163+
sock_event_close(sock_udp_get_async_ctx(sock));
164+
#endif
158165
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
159166
if (_udp_socks != NULL) {
160167
gnrc_sock_reg_t *head = (gnrc_sock_reg_t *)_udp_socks;

sys/net/sock/async/event/sock_async_event.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,100 @@ static void _set_ctx(sock_async_ctx_t *ctx, event_queue_t *ev_queue)
6262
ctx->queue = ev_queue;
6363
}
6464

65+
void sock_event_close(sock_async_ctx_t *async_ctx)
66+
{
67+
event_queue_t *queue = async_ctx->queue;
68+
if (!queue) {
69+
/* no callback registered */
70+
return;
71+
}
72+
73+
/* RIOTs socket API is not thread safe so we assume that wherever this is
74+
* called from it's not racing against some other socket usage.
75+
*
76+
* But we have to go stricter and assume this is called from the same thread
77+
* that processes the events. There is no way of preventing the networking
78+
* subsystem from posting socket events until the socket has been
79+
* unregistered, which is only happening when closing the socket and the
80+
* reason we're here in the first place. */
81+
assume(!queue->waiter || thread_getpid_of(queue->waiter) == thread_getpid());
82+
83+
event_cancel(async_ctx->queue, &async_ctx->event.super);
84+
}
85+
86+
typedef enum {
87+
#if defined(MODULE_SOCK_UDP) || defined(DOXYGEN)
88+
SOCK_ASYNC_UDP,
89+
#endif
90+
#if defined(MODULE_SOCK_TCP) || defined(DOXYGEN)
91+
SOCK_ASYNC_TCP,
92+
#endif
93+
#if defined(MODULE_SOCK_IP) || defined(DOXYGEN)
94+
SOCK_ASYNC_IP,
95+
#endif
96+
#if defined(MODULE_SOCK_DTLS) || defined(DOXYGEN)
97+
SOCK_ASYNC_DTLS,
98+
#endif
99+
} sock_async_t;
100+
101+
typedef struct {
102+
event_t super;
103+
sock_async_t type;
104+
void *sock;
105+
} _sock_close_ev;
106+
107+
static void _sock_event_close_cb(event_t *ev)
108+
{
109+
_sock_close_ev *close_ev = container_of(ev, _sock_close_ev, super);
110+
111+
switch (close_ev->type) {
112+
#if defined(MODULE_SOCK_UDP) || defined(DOXYGEN)
113+
case SOCK_ASYNC_UDP:
114+
sock_udp_close(close_ev->sock);
115+
break;
116+
#endif
117+
#if defined(MODULE_SOCK_TCP) || defined(DOXYGEN)
118+
case SOCK_ASYNC_TCP:
119+
sock_tcp_disconnect(close_ev->sock);
120+
break;
121+
#endif
122+
#if defined(MODULE_SOCK_IP) || defined(DOXYGEN)
123+
case SOCK_ASYNC_IP:
124+
sock_ip_close(close_ev->sock);
125+
break;
126+
#endif
127+
#if defined(MODULE_SOCK_DTLS) || defined(DOXYGEN)
128+
case SOCK_ASYNC_DTLS:
129+
sock_dtls_close(close_ev->sock);
130+
break;
131+
#endif
132+
}
133+
}
134+
135+
static void _sock_event_close_common(void *sock, sock_async_ctx_t *async_ctx,
136+
sock_async_t type)
137+
{
138+
_sock_close_ev ev = {
139+
.super.handler = _sock_event_close_cb,
140+
.type = type,
141+
.sock = sock,
142+
};
143+
144+
if (!async_ctx->queue ||
145+
!async_ctx->queue->waiter ||
146+
thread_getpid_of(async_ctx->queue->waiter) == thread_getpid()) {
147+
/* - this socket is not async OR
148+
* - there is no thread processing the event queue (in which case we
149+
* might race against @ref event_queue_claim() but so is life)
150+
* OR we are on the event queue thread. In the first case we might
151+
* block forever, in the second we surely will, so do it now. */
152+
_sock_event_close_cb(&ev.super);
153+
return;
154+
}
155+
156+
event_post(async_ctx->queue, &ev.super);
157+
event_sync(async_ctx->queue);
158+
}
65159
#ifdef MODULE_SOCK_DTLS
66160
static void _dtls_cb(sock_dtls_t *sock, sock_async_flags_t type, void *arg)
67161
{
@@ -77,6 +171,11 @@ void sock_dtls_event_init(sock_dtls_t *sock, event_queue_t *ev_queue,
77171
ctx->event.cb.dtls = handler;
78172
sock_dtls_set_cb(sock, _dtls_cb, handler_arg);
79173
}
174+
175+
void sock_dtls_event_close(sock_dtls_t *sock)
176+
{
177+
_sock_event_close_common(sock, sock_dtls_get_async_ctx(sock), SOCK_ASYNC_DTLS);
178+
}
80179
#endif /* MODULE_SOCK_DTLS */
81180

82181
#ifdef MODULE_SOCK_IP
@@ -94,6 +193,11 @@ void sock_ip_event_init(sock_ip_t *sock, event_queue_t *ev_queue,
94193
ctx->event.cb.ip = handler;
95194
sock_ip_set_cb(sock, _ip_cb, handler_arg);
96195
}
196+
197+
void sock_ip_event_close(sock_ip_t *sock)
198+
{
199+
_sock_event_close_common(sock, sock_ip_get_async_ctx(sock), SOCK_ASYNC_IP);
200+
}
97201
#endif /* MODULE_SOCK_IP */
98202

99203
#ifdef MODULE_SOCK_TCP
@@ -127,6 +231,11 @@ void sock_tcp_queue_event_init(sock_tcp_queue_t *queue, event_queue_t *ev_queue,
127231
ctx->event.cb.tcp_queue = handler;
128232
sock_tcp_queue_set_cb(queue, _tcp_queue_cb, handler_arg);
129233
}
234+
235+
void sock_tcp_event_close(sock_tcp_t *sock)
236+
{
237+
_sock_event_close_common(sock, sock_tcp_get_async_ctx(sock), SOCK_ASYNC_TCP);
238+
}
130239
#endif /* MODULE_SOCK_TCP */
131240

132241
#ifdef MODULE_SOCK_UDP
@@ -144,6 +253,12 @@ void sock_udp_event_init(sock_udp_t *sock, event_queue_t *ev_queue,
144253
ctx->event.cb.udp = handler;
145254
sock_udp_set_cb(sock, _udp_cb, handler_arg);
146255
}
256+
257+
void sock_udp_event_close(sock_udp_t *sock)
258+
{
259+
_sock_event_close_common(sock, sock_udp_get_async_ctx(sock), SOCK_ASYNC_UDP);
260+
}
261+
147262
#endif /* MODULE_SOCK_UDP */
148263

149264
/** @} */

0 commit comments

Comments
 (0)