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