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