• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* coap_async.c -- state management for asynchronous messages
2  *
3  * Copyright (C) 2010,2011,2021-2023 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 coap_async.c
13  * @brief State handling for asynchronous messages
14  */
15 
16 #include "coap3/coap_internal.h"
17 
18 #if COAP_ASYNC_SUPPORT
19 #include <stdio.h>
20 
21 /* utlist-style macros for searching pairs in linked lists */
22 #define SEARCH_PAIR(head,out,field1,val1,field2,val2,field3,val3)   \
23   SEARCH_PAIR3(head,out,field1,val1,field2,val2,field3,val3,next)
24 
25 #define SEARCH_PAIR3(head,out,field1,val1,field2,val2,field3,val3,next) \
26   do {                                                                  \
27     LL_FOREACH2(head,out,next) {                                        \
28       if ((out)->field1 == (val1) && (out)->field2 == (val2) &&         \
29           ((val2) == 0 || memcmp((out)->field3, (val3), (val2)) == 0)) break; \
30     }                                                                   \
31   } while(0)
32 
33 int
coap_async_is_supported(void)34 coap_async_is_supported(void) {
35   return 1;
36 }
37 
38 coap_async_t *
coap_register_async(coap_session_t * session,const coap_pdu_t * request,coap_tick_t delay)39 coap_register_async(coap_session_t *session,
40                     const coap_pdu_t *request, coap_tick_t delay) {
41   coap_async_t *s;
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->actual_token.length, request->actual_token.length,
51               pdu->actual_token.s, request->actual_token.s);
52 
53   if (s != NULL) {
54     size_t i;
55     char outbuf[2*8 + 1];
56     size_t outbuflen;
57 
58     outbuf[0] = '\000';
59     for (i = 0; i < request->actual_token.length; i++) {
60       /* Output maybe truncated */
61       outbuflen = strlen(outbuf);
62       snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
63                "%02x", request->token[i]);
64     }
65     coap_log_debug("asynchronous state for token '%s' already registered\n", outbuf);
66     return NULL;
67   }
68 
69   /* store information for handling the asynchronous task */
70   s = (coap_async_t *)coap_malloc_type(COAP_STRING, sizeof(coap_async_t));
71   if (!s) {
72     coap_log_crit("coap_register_async: insufficient memory\n");
73     return NULL;
74   }
75 
76   memset(s, 0, sizeof(coap_async_t));
77   LL_PREPEND(session->context->async_state, s);
78 
79   /* Note that this generates a new MID */
80   s->pdu = coap_pdu_duplicate(request, session, request->actual_token.length,
81                               request->actual_token.s, NULL);
82   if (s->pdu == NULL) {
83     coap_free_async(session, s);
84     coap_log_crit("coap_register_async: insufficient memory\n");
85     return NULL;
86   }
87 
88   if (coap_get_data(request, &len, &data)) {
89     coap_add_data(s->pdu, len, data);
90   }
91 
92   s->session = coap_session_reference(session);
93 
94   coap_async_set_delay(s, delay);
95 
96   return s;
97 }
98 
99 void
coap_async_trigger(coap_async_t * async)100 coap_async_trigger(coap_async_t *async) {
101   assert(async != NULL);
102   coap_ticks(&async->delay);
103 
104   coap_log_debug("   %s: Async request triggered\n",
105                  coap_session_str(async->session));
106 #ifdef COAP_EPOLL_SUPPORT
107   coap_update_epoll_timer(async->session->context, 0);
108 #endif /* COAP_EPOLL_SUPPORT */
109 }
110 
111 
112 void
coap_async_set_delay(coap_async_t * async,coap_tick_t delay)113 coap_async_set_delay(coap_async_t *async, coap_tick_t delay) {
114   coap_tick_t now;
115 
116   assert(async != NULL);
117   coap_ticks(&now);
118 
119   if (delay) {
120     async->delay = now + delay;
121 #ifdef COAP_EPOLL_SUPPORT
122     coap_update_epoll_timer(async->session->context, delay);
123 #endif /* COAP_EPOLL_SUPPORT */
124     coap_log_debug("   %s: Async request delayed for %u.%03u secs\n",
125                    coap_session_str(async->session),
126                    (unsigned int)(delay / COAP_TICKS_PER_SECOND),
127                    (unsigned int)((delay % COAP_TICKS_PER_SECOND) *
128                                   1000 / COAP_TICKS_PER_SECOND));
129   } else {
130     async->delay = 0;
131     coap_log_debug("   %s: Async request indefinately delayed\n",
132                    coap_session_str(async->session));
133   }
134 }
135 
136 coap_async_t *
coap_find_async(coap_session_t * session,coap_bin_const_t token)137 coap_find_async(coap_session_t *session, coap_bin_const_t token) {
138   coap_async_t *tmp;
139 
140   SEARCH_PAIR(session->context->async_state, tmp,
141               session, session,
142               pdu->actual_token.length, token.length,
143               pdu->actual_token.s, token.s);
144   return tmp;
145 }
146 
147 static void
coap_free_async_sub(coap_context_t * context,coap_async_t * s)148 coap_free_async_sub(coap_context_t *context, coap_async_t *s) {
149   if (s) {
150     LL_DELETE(context->async_state,s);
151     if (s->session) {
152       coap_session_release(s->session);
153     }
154     if (s->pdu) {
155       coap_delete_pdu(s->pdu);
156       s->pdu = NULL;
157     }
158     coap_free_type(COAP_STRING, s);
159   }
160 }
161 
162 void
coap_free_async(coap_session_t * session,coap_async_t * s)163 coap_free_async(coap_session_t *session, coap_async_t *s) {
164   coap_free_async_sub(session->context, s);
165 }
166 
167 void
coap_delete_all_async(coap_context_t * context)168 coap_delete_all_async(coap_context_t *context) {
169   coap_async_t *astate, *tmp;
170 
171   LL_FOREACH_SAFE(context->async_state, astate, tmp) {
172     coap_free_async_sub(context, astate);
173   }
174   context->async_state = NULL;
175 }
176 
177 void
coap_async_set_app_data(coap_async_t * async,void * app_data)178 coap_async_set_app_data(coap_async_t *async, void *app_data) {
179   async->appdata = app_data;
180 }
181 
182 void *
coap_async_get_app_data(const coap_async_t * async)183 coap_async_get_app_data(const coap_async_t *async) {
184   return async->appdata;
185 }
186 
187 #else /* ! COAP_ASYNC_SUPPORT */
188 
189 int
coap_async_is_supported(void)190 coap_async_is_supported(void) {
191   return 0;
192 }
193 
194 coap_async_t *
coap_register_async(coap_session_t * session,const coap_pdu_t * request,coap_tick_t delay)195 coap_register_async(coap_session_t *session,
196                     const coap_pdu_t *request,
197                     coap_tick_t delay) {
198   (void)session;
199   (void)request;
200   (void)delay;
201   return NULL;
202 }
203 
204 void
coap_async_set_delay(coap_async_t * async,coap_tick_t delay)205 coap_async_set_delay(coap_async_t *async, coap_tick_t delay) {
206   (void)async;
207   (void)delay;
208 }
209 
210 void
coap_free_async(coap_session_t * session,coap_async_t * async)211 coap_free_async(coap_session_t *session, coap_async_t *async) {
212   (void)session;
213   (void)async;
214 }
215 
216 coap_async_t *
coap_find_async(coap_session_t * session,coap_bin_const_t token)217 coap_find_async(coap_session_t *session,
218                 coap_bin_const_t token) {
219   (void)session;
220   (void)token;
221   return NULL;
222 }
223 
224 void
coap_async_set_app_data(coap_async_t * async,void * app_data)225 coap_async_set_app_data(coap_async_t *async, void *app_data) {
226   (void)async;
227   (void)app_data;
228 }
229 
230 void *
coap_async_get_app_data(const coap_async_t * async)231 coap_async_get_app_data(const coap_async_t *async) {
232   (void)async;
233   return NULL;
234 }
235 
236 #endif /* ! COAP_ASYNC_SUPPORT */
237