1 /* async.c -- state management for asynchronous messages
2 *
3 * Copyright (C) 2010,2011,2021 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 /**
12 * @file async.c
13 * @brief state management for asynchronous messages
14 */
15
16 #include "coap3/coap_internal.h"
17
18 #ifndef WITHOUT_ASYNC
19
20 /* utlist-style macros for searching pairs in linked lists */
21 #define SEARCH_PAIR(head,out,field1,val1,field2,val2,field3,val3) \
22 SEARCH_PAIR3(head,out,field1,val1,field2,val2,field3,val3,next)
23
24 #define SEARCH_PAIR3(head,out,field1,val1,field2,val2,field3,val3,next) \
25 do { \
26 LL_FOREACH2(head,out,next) { \
27 if ((out)->field1 == (val1) && (out)->field2 == (val2) && \
28 ((val2) == 0 || memcmp((out)->field3, (val3), (val2)) == 0)) break; \
29 } \
30 } while(0)
31
32 int
coap_async_is_supported(void)33 coap_async_is_supported(void) {
34 return 1;
35 }
36
37 coap_async_t *
coap_register_async(coap_session_t * session,const coap_pdu_t * request,coap_tick_t delay)38 coap_register_async(coap_session_t *session,
39 const coap_pdu_t *request, coap_tick_t delay) {
40 coap_async_t *s;
41 coap_mid_t mid = request->mid;
42 size_t len;
43 const uint8_t *data;
44
45 if (!COAP_PDU_IS_REQUEST(request))
46 return NULL;
47
48 SEARCH_PAIR(session->context->async_state, s,
49 session, session,
50 pdu->token_length, request->token_length,
51 pdu->token, request->token);
52
53 if (s != NULL) {
54 coap_log(LOG_DEBUG,
55 "asynchronous state for mid=0x%x already registered\n", mid);
56 return NULL;
57 }
58
59 /* store information for handling the asynchronous task */
60 s = (coap_async_t *)coap_malloc(sizeof(coap_async_t));
61 if (!s) {
62 coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
63 return NULL;
64 }
65
66 memset(s, 0, sizeof(coap_async_t));
67
68 s->pdu = coap_pdu_duplicate(request, session, request->token_length,
69 request->token, NULL);
70 if (s->pdu == NULL) {
71 coap_free_async(session, s);
72 coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
73 return NULL;
74 }
75 s->pdu->mid = mid; /* coap_pdu_duplicate() created one */
76
77 if (coap_get_data(request, &len, &data)) {
78 coap_add_data(s->pdu, len, data);
79 }
80
81 s->session = coap_session_reference( session );
82
83 coap_async_set_delay(s, delay);
84
85 LL_PREPEND(session->context->async_state, s);
86
87 return s;
88 }
89
90 void
coap_async_set_delay(coap_async_t * async,coap_tick_t delay)91 coap_async_set_delay(coap_async_t *async, coap_tick_t delay) {
92 assert(async != NULL);
93
94 if (delay) {
95 coap_ticks(&async->delay);
96 async->delay += delay;
97 }
98 else
99 async->delay = 0;
100 coap_log(LOG_DEBUG, " %s: Request for delayed for %u.%03u secs\n",
101 coap_session_str(async->session),
102 (unsigned int)(delay / COAP_TICKS_PER_SECOND),
103 (unsigned int)((delay % COAP_TICKS_PER_SECOND) *
104 1000 / COAP_TICKS_PER_SECOND));
105 }
106
107
108 coap_async_t *
coap_find_async(coap_session_t * session,coap_bin_const_t token)109 coap_find_async(coap_session_t *session, coap_bin_const_t token) {
110 coap_async_t *tmp;
111 SEARCH_PAIR(session->context->async_state, tmp,
112 session, session,
113 pdu->token_length, token.length,
114 pdu->token, token.s);
115 return tmp;
116 }
117
118 static void
coap_free_async_sub(coap_context_t * context,coap_async_t * s)119 coap_free_async_sub(coap_context_t *context, coap_async_t *s) {
120 if (s) {
121 LL_DELETE(context->async_state,s);
122 if (s->session) {
123 coap_session_release(s->session);
124 }
125 if (s->pdu) {
126 coap_delete_pdu(s->pdu);
127 s->pdu = NULL;
128 }
129 coap_free(s);
130 }
131 }
132
133 void
coap_free_async(coap_session_t * session,coap_async_t * s)134 coap_free_async(coap_session_t *session, coap_async_t *s) {
135 coap_free_async_sub(session->context, s);
136 }
137
138 void
coap_delete_all_async(coap_context_t * context)139 coap_delete_all_async(coap_context_t *context) {
140 coap_async_t *astate, *tmp;
141
142 LL_FOREACH_SAFE(context->async_state, astate, tmp) {
143 coap_free_async_sub(context, astate);
144 }
145 context->async_state = NULL;
146 }
147
148 void
coap_async_set_app_data(coap_async_t * async,void * app_data)149 coap_async_set_app_data(coap_async_t *async, void *app_data) {
150 async->appdata = app_data;
151 }
152
153 void *
coap_async_get_app_data(const coap_async_t * async)154 coap_async_get_app_data(const coap_async_t *async) {
155 return async->appdata;
156 }
157
158 #else
159
160 int
coap_async_is_supported(void)161 coap_async_is_supported(void) {
162 return 0;
163 }
164
165 coap_async_t *
coap_register_async(coap_session_t * session,const coap_pdu_t * request,coap_tick_t delay)166 coap_register_async(coap_session_t *session,
167 const coap_pdu_t *request,
168 coap_tick_t delay) {
169 (void)session;
170 (void)request;
171 (void)delay;
172 return NULL;
173 }
174
175 void
coap_async_set_delay(coap_async_t * async,coap_tick_t delay)176 coap_async_set_delay(coap_async_t *async, coap_tick_t delay) {
177 (void)async;
178 (void)delay;
179 }
180
181 void
coap_free_async(coap_session_t * session,coap_async_t * async)182 coap_free_async(coap_session_t *session, coap_async_t *async) {
183 (void)session;
184 (void)async;
185 }
186
187 coap_async_t *
coap_find_async(coap_session_t * session,coap_bin_const_t token)188 coap_find_async(coap_session_t *session,
189 coap_bin_const_t token) {
190 (void)session;
191 (void)token;
192 return NULL;
193 }
194
195 void
coap_async_set_app_data(coap_async_t * async,void * app_data)196 coap_async_set_app_data(coap_async_t *async, void *app_data) {
197 (void)async;
198 (void)app_data;
199 }
200
201 void *
coap_async_get_app_data(const coap_async_t * async)202 coap_async_get_app_data(const coap_async_t *async) {
203 (void)async;
204 return NULL;
205 }
206
207 #endif /* WITHOUT_ASYNC */
208