82f46ce401d84421bcb59d2050d9b0ca8b099c03
[platform/upstream/iotivity.git] / resource / csdk / stack / src / occlientcb.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "iotivity_config.h"
22 #include "occlientcb.h"
23 #include "logger.h"
24 #include "trace.h"
25 #include "oic_malloc.h"
26 #include <string.h>
27
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31 #ifdef HAVE_ARDUINO_TIME_H
32 #include "Time.h"
33 #endif
34
35 #include "cacommon.h"
36 #include "cainterface.h"
37 #include <coap/coap.h>
38
39 /// Module Name
40 #define TAG "OIC_RI_CLIENTCB"
41
42 struct ClientCB *cbList = NULL;
43
44 OCStackResult
45 AddClientCB (ClientCB** clientCB, OCCallbackData* cbData,
46              CAToken_t token, uint8_t tokenLength,
47              OCDoHandle *handle, OCMethod method,
48              OCDevAddr *devAddr, char * requestUri,
49              char * resourceTypeName, uint32_t ttl)
50 {
51     if (!clientCB || !cbData || !handle || tokenLength > CA_MAX_TOKEN_LEN)
52     {
53         return OC_STACK_INVALID_PARAM;
54     }
55
56     OIC_TRACE_BEGIN(%s:AddClientCB, TAG);
57
58     ClientCB *cbNode = NULL;
59
60 #ifdef WITH_PRESENCE
61     if (method == OC_REST_PRESENCE)
62     {   // Retrieve the presence callback structure for this specific requestUri.
63         cbNode = GetClientCB(NULL, 0, NULL, requestUri);
64     }
65
66     if (!cbNode)// If it does not already exist, create new node.
67 #endif // WITH_PRESENCE
68     {
69         cbNode = (ClientCB*) OICMalloc(sizeof(ClientCB));
70         if (!cbNode)
71         {
72             *clientCB = NULL;
73             goto exit;
74         }
75         else
76         {
77             OIC_LOG(INFO, TAG, "Adding client callback with token");
78             OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
79             OIC_TRACE_BUFFER("OIC_RI_CLIENTCB:AddClientCB:token",
80                              (const uint8_t *) token, tokenLength);
81             cbNode->callBack = cbData->cb;
82             cbNode->context = cbData->context;
83             cbNode->deleteCallback = cbData->cd;
84             //Note: token memory is allocated in the caller OCDoResource
85             //but freed in DeleteClientCB
86             cbNode->token = token;
87             cbNode->tokenLength = tokenLength;
88             cbNode->handle = *handle;
89             cbNode->method = method;
90             cbNode->sequenceNumber = 0;
91 #ifdef WITH_PRESENCE
92             cbNode->presence = NULL;
93             cbNode->filterResourceType = NULL;
94 #endif // WITH_PRESENCE
95
96             if (
97 #ifdef WITH_PRESENCE
98                 method == OC_REST_PRESENCE ||
99 #endif
100                 method == OC_REST_OBSERVE  ||
101                 method == OC_REST_OBSERVE_ALL)
102             {
103                 cbNode->TTL = 0;
104             }
105             else
106             {
107                 cbNode->TTL = ttl;
108             }
109             cbNode->requestUri = requestUri;    // I own it now
110             cbNode->devAddr = devAddr;          // I own it now
111             OIC_LOG_V(INFO, TAG, "Added Callback for uri : %s", requestUri);
112             OIC_TRACE_MARK(%s:AddClientCB:uri:%s, TAG, requestUri);
113             LL_APPEND(cbList, cbNode);
114             *clientCB = cbNode;
115         }
116     }
117 #ifdef WITH_PRESENCE
118     else
119     {
120         // Ensure that the handle the SDK hands back up to the application layer for the
121         // OCDoResource call matches the found ClientCB Node.
122         *clientCB = cbNode;
123
124         if (cbData->cd)
125         {
126             cbData->cd(cbData->context);
127         }
128
129         OICFree(token);
130         OICFree(*handle);
131         OICFree(requestUri);
132         OICFree(devAddr);
133         *handle = cbNode->handle;
134     }
135
136     if (method == OC_REST_PRESENCE && resourceTypeName)
137     {
138         OIC_TRACE_END();
139         // Amend the found or created node by adding a new resourceType to it.
140         return InsertResourceTypeFilter(cbNode,(char *)resourceTypeName);
141         // I own resourceTypName now.
142     }
143     else
144     {
145         OICFree(resourceTypeName);
146     }
147 #else
148     OICFree(resourceTypeName);
149 #endif
150
151     OIC_TRACE_END();
152     return OC_STACK_OK;
153
154 exit:
155     OIC_TRACE_END();
156     return OC_STACK_NO_MEMORY;
157 }
158
159 void DeleteClientCB(ClientCB * cbNode)
160 {
161     OIC_TRACE_BEGIN(%s:DeleteClientCB, TAG);
162     if (cbNode)
163     {
164         LL_DELETE(cbList, cbNode);
165         OIC_LOG (INFO, TAG, "Deleting token");
166         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)cbNode->token, cbNode->tokenLength);
167         OIC_TRACE_BUFFER("OIC_RI_CLIENTCB:DeleteClientCB:token",
168                          (const uint8_t *)cbNode->token, cbNode->tokenLength);
169         CADestroyToken (cbNode->token);
170         OICFree(cbNode->devAddr);
171         OICFree(cbNode->handle);
172         if (cbNode->requestUri)
173         {
174             OIC_LOG_V (INFO, TAG, "Deleting callback with uri %s", cbNode->requestUri);
175             OIC_TRACE_MARK(%s:DeleteClientCB:uri:%s, TAG, cbNode->requestUri);
176             OICFree(cbNode->requestUri);
177         }
178         if (cbNode->deleteCallback)
179         {
180             cbNode->deleteCallback(cbNode->context);
181         }
182
183 #ifdef WITH_PRESENCE
184         if (cbNode->presence)
185         {
186             OICFree(cbNode->presence->timeOut);
187             OICFree(cbNode->presence);
188         }
189         if (cbNode->method == OC_REST_PRESENCE)
190         {
191             OCResourceType * pointer = cbNode->filterResourceType;
192             OCResourceType * next = NULL;
193             while(pointer)
194             {
195                 next = pointer->next;
196                 OICFree(pointer->resourcetypename);
197                 OICFree(pointer);
198                 pointer = next;
199             }
200         }
201 #endif // WITH_PRESENCE
202         OICFree(cbNode);
203         cbNode = NULL;
204     }
205     OIC_TRACE_END();
206 }
207
208 /*
209  * This function checks if the node is past its time to live and
210  * deletes it if timed-out. Calling this function with a  presence or observe
211  * callback with ttl set to 0 will not delete anything as presence nodes have
212  * their own mechanisms for timeouts. A null argument will cause the function to
213  * silently return.
214  */
215 static void CheckAndDeleteTimedOutCB(ClientCB* cbNode)
216 {
217     if (!cbNode)
218     {
219         return;
220     }
221     if (cbNode->TTL == 0)
222     {
223         return;
224     }
225     coap_tick_t now;
226     coap_ticks(&now);
227
228     if (cbNode->TTL < now)
229     {
230         OIC_LOG(INFO, TAG, "Deleting timed-out callback");
231         DeleteClientCB(cbNode);
232     }
233 }
234
235 ClientCB* GetClientCB(const CAToken_t token, uint8_t tokenLength,
236                       OCDoHandle handle, const char * requestUri)
237 {
238     ClientCB* out = NULL;
239
240     if (token && tokenLength <= CA_MAX_TOKEN_LEN && tokenLength > 0)
241     {
242         OIC_LOG (INFO, TAG,  "Looking for token");
243         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
244         LL_FOREACH(cbList, out)
245         {
246             /* de-annotate below line if want to see all token in cbList */
247             //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
248             if (memcmp(out->token, token, tokenLength) == 0)
249             {
250                 OIC_LOG(INFO, TAG, "Found in callback list");
251                 return out;
252             }
253             CheckAndDeleteTimedOutCB(out);
254         }
255     }
256     else if (handle)
257     {
258         OIC_LOG (INFO, TAG,  "Looking for handle");
259         LL_FOREACH(cbList, out)
260         {
261             if (out->handle == handle)
262             {
263                 OIC_LOG(INFO, TAG, "Found in callback list");
264                 return out;
265             }
266             CheckAndDeleteTimedOutCB(out);
267         }
268     }
269     else if (requestUri)
270     {
271         OIC_LOG_V(INFO, TAG, "Looking for uri %s", requestUri);
272         LL_FOREACH(cbList, out)
273         {
274             /* de-annotate below line if want to see all uri in cbList */
275             //OIC_LOG_V(INFO, TAG, "%s", out->requestUri);
276             if (out->requestUri && strcmp(out->requestUri, requestUri ) == 0)
277             {
278                 OIC_LOG(INFO, TAG, "Found in callback list");
279                 return out;
280             }
281             CheckAndDeleteTimedOutCB(out);
282         }
283     }
284     OIC_LOG(INFO, TAG, "Callback Not found !!");
285     return NULL;
286 }
287
288 #ifdef WITH_PRESENCE
289 OCStackResult InsertResourceTypeFilter(ClientCB * cbNode, char * resourceTypeName)
290 {
291     OCResourceType * newResourceType = NULL;
292     if (cbNode && resourceTypeName)
293     {
294         // Form a new resourceType member.
295         newResourceType = (OCResourceType *) OICMalloc(sizeof(OCResourceType));
296         if (!newResourceType)
297         {
298             return OC_STACK_NO_MEMORY;
299         }
300
301         newResourceType->next = NULL;
302         newResourceType->resourcetypename = resourceTypeName;
303
304         LL_APPEND(cbNode->filterResourceType, newResourceType);
305         return OC_STACK_OK;
306     }
307     return OC_STACK_ERROR;
308 }
309 #endif // WITH_PRESENCE
310
311 void DeleteClientCBList()
312 {
313     ClientCB* out;
314     ClientCB* tmp;
315     LL_FOREACH_SAFE(cbList, out, tmp)
316     {
317         DeleteClientCB(out);
318     }
319     cbList = NULL;
320 }
321
322 void FindAndDeleteClientCB(ClientCB * cbNode)
323 {
324     ClientCB* tmp;
325     if (cbNode)
326     {
327         LL_FOREACH(cbList, tmp)
328         {
329             if (cbNode == tmp)
330             {
331                 DeleteClientCB(tmp);
332                 break;
333             }
334         }
335     }
336 }