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