1 /* async.c -- state management for asynchronous messages
2 *
3 * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
7 */
8
9 /**
10 * @file async.c
11 * @brief state management for asynchronous messages
12 */
13
14 #include "coap_internal.h"
15
16 #ifndef WITHOUT_ASYNC
17
18 /* utlist-style macros for searching pairs in linked lists */
19 #define SEARCH_PAIR(head,out,field1,val1,field2,val2) \
20 SEARCH_PAIR2(head,out,field1,val1,field2,val2,next)
21
22 #define SEARCH_PAIR2(head,out,field1,val1,field2,val2,next) \
23 do { \
24 LL_FOREACH2(head,out,next) { \
25 if ((out)->field1 == (val1) && (out)->field2 == (val2)) break; \
26 } \
27 } while(0)
28
29 coap_async_state_t *
coap_register_async(coap_context_t * context,coap_session_t * session,coap_pdu_t * request,unsigned char flags,void * data)30 coap_register_async(coap_context_t *context, coap_session_t *session,
31 coap_pdu_t *request, unsigned char flags, void *data) {
32 coap_async_state_t *s;
33 coap_tid_t id = request->tid;
34
35 SEARCH_PAIR(context->async_state,s,session,session,id,id);
36
37 if (s != NULL) {
38 /* We must return NULL here as the caller must know that he is
39 * responsible for releasing @p data. */
40 coap_log(LOG_DEBUG,
41 "asynchronous state for transaction %d already registered\n", id);
42 return NULL;
43 }
44
45 /* store information for handling the asynchronous task */
46 s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t));
47 if (!s) {
48 coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
49 return NULL;
50 }
51
52 memset(s, 0, sizeof(coap_async_state_t));
53
54 /* set COAP_ASYNC_CONFIRM according to request's type */
55 s->flags = flags & ~COAP_ASYNC_CONFIRM;
56 if (request->type == COAP_MESSAGE_CON)
57 s->flags |= COAP_ASYNC_CONFIRM;
58
59 s->appdata = data;
60 s->session = coap_session_reference( session );
61 s->id = id;
62
63 if (request->token_length) {
64 /* A token can be up to 8 bytes */
65 s->tokenlen = (request->token_length > 8) ? 8 : request->token_length;
66 memcpy(s->token, request->token, s->tokenlen);
67 }
68
69 coap_touch_async(s);
70
71 LL_PREPEND(context->async_state, s);
72
73 return s;
74 }
75
76 coap_async_state_t *
coap_find_async(coap_context_t * context,coap_session_t * session,coap_tid_t id)77 coap_find_async(coap_context_t *context, coap_session_t *session, coap_tid_t id) {
78 coap_async_state_t *tmp;
79 SEARCH_PAIR(context->async_state,tmp,session,session,id,id);
80 return tmp;
81 }
82
83 int
coap_remove_async(coap_context_t * context,coap_session_t * session,coap_tid_t id,coap_async_state_t ** s)84 coap_remove_async(coap_context_t *context, coap_session_t *session,
85 coap_tid_t id, coap_async_state_t **s) {
86 coap_async_state_t *tmp = coap_find_async(context, session, id);
87
88 if (tmp)
89 LL_DELETE(context->async_state,tmp);
90
91 *s = tmp;
92 return tmp != NULL;
93 }
94
95 void
coap_free_async(coap_async_state_t * s)96 coap_free_async(coap_async_state_t *s) {
97 if (s) {
98 if (s->session) {
99 coap_session_release(s->session);
100 }
101 if ((s->flags & COAP_ASYNC_RELEASE_DATA) != 0) {
102 coap_free(s->appdata);
103 }
104 coap_free(s);
105 }
106 }
107
108 #else
109 void does_not_exist(void); /* make some compilers happy */
110 #endif /* WITHOUT_ASYNC */
111