[IOT-2334][IOT-2335] Fixed presence sample app crash issue
[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 <coap/coap.h>
24 #include "logger.h"
25 #include "trace.h"
26 #include "oic_malloc.h"
27 #include <string.h>
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32 #ifdef HAVE_ARDUINO_TIME_H
33 #include "Time.h"
34 #endif
35
36 #include "cacommon.h"
37 #include "cainterface.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             CAMessageType_t type,
47             CAToken_t token, uint8_t tokenLength,
48             CAHeaderOption_t *options, uint8_t numOptions,
49             CAPayload_t payload, size_t payloadSize,
50             CAPayloadFormat_t payloadFormat,
51             OCDoHandle *handle, OCMethod method,
52             OCDevAddr *devAddr, char *requestUri,
53             char *resourceTypeName, uint32_t ttl)
54 {
55     if (!clientCB || !cbData || !handle || tokenLength > CA_MAX_TOKEN_LEN)
56     {
57         return OC_STACK_INVALID_PARAM;
58     }
59
60     OIC_TRACE_BEGIN(%s:AddClientCB, TAG);
61
62     ClientCB *cbNode = NULL;
63
64 #ifdef WITH_PRESENCE
65     if (method == OC_REST_PRESENCE)
66     {   // Retrieve the presence callback structure for this specific requestUri.
67         cbNode = GetClientCB(NULL, 0, NULL, requestUri);
68     }
69
70     if (!cbNode)// If it does not already exist, create new node.
71 #endif // WITH_PRESENCE
72     {
73         cbNode = (ClientCB*) OICMalloc(sizeof(ClientCB));
74         if (!cbNode)
75         {
76             *clientCB = NULL;
77             goto exit;
78         }
79         else
80         {
81             OIC_LOG(INFO, TAG, "Adding client callback with token");
82             OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
83             OIC_TRACE_BUFFER("OIC_RI_CLIENTCB:AddClientCB:token:",
84                              (const uint8_t *)token, tokenLength);
85             cbNode->callBack = cbData->cb;
86             cbNode->context = cbData->context;
87             cbNode->deleteCallback = cbData->cd;
88             if (!options || !numOptions)
89             {
90                 OIC_LOG (INFO, TAG, "No options present");
91                 cbNode->options = NULL;
92                 cbNode->numOptions = 0;
93             }
94             else
95             {
96                 cbNode->options = (CAHeaderOption_t *) OICCalloc(numOptions,
97                         sizeof(CAHeaderOption_t));
98                 if (!cbNode->options)
99                 {
100                     OIC_LOG(ERROR, TAG, "Out of memory");
101                     OICFree(cbNode);
102
103                     return OC_STACK_NO_MEMORY;
104                 }
105                 memcpy(cbNode->options, options,
106                         sizeof(CAHeaderOption_t) * numOptions);
107
108                 cbNode->numOptions = numOptions;
109             }
110             if (!payload || !payloadSize)
111             {
112                 OIC_LOG (INFO, TAG, "No payload present");
113                 cbNode->payload = NULL;
114                 cbNode->payloadSize = 0;
115             }
116             else
117             {
118                 cbNode->payload = (CAPayload_t) OICCalloc(1, payloadSize);
119                 if (!cbNode->payload)
120                 {
121                     OIC_LOG(ERROR, TAG, "Out of memory");
122                     if (cbNode->options)
123                     {
124                         OICFree(cbNode->options);
125                     }
126                     OICFree(cbNode);
127
128                     return OC_STACK_NO_MEMORY;
129                 }
130                 memcpy(cbNode->payload, payload, payloadSize);
131                 cbNode->payloadSize = payloadSize;
132             }
133             cbNode->payloadFormat = payloadFormat;
134             cbNode->type = type;
135             //Note: token memory is allocated in the caller OCDoResource
136             //but freed in DeleteClientCB
137             cbNode->token = token;
138             cbNode->tokenLength = tokenLength;
139             cbNode->handle = *handle;
140             cbNode->method = method;
141             cbNode->sequenceNumber = 0;
142 #ifdef WITH_PRESENCE
143             cbNode->presence = NULL;
144             cbNode->filterResourceType = NULL;
145 #endif // WITH_PRESENCE
146
147             if (method == OC_REST_PRESENCE ||
148                 method == OC_REST_OBSERVE  ||
149                 method == OC_REST_OBSERVE_ALL)
150             {
151                 cbNode->TTL = 0;
152             }
153             else
154             {
155                 cbNode->TTL = ttl;
156             }
157             cbNode->requestUri = requestUri;    // I own it now
158             cbNode->devAddr = devAddr;          // I own it now
159             OIC_LOG_V(INFO, TAG, "Added Callback for uri : %s", requestUri);
160             OIC_TRACE_MARK(%s:AddClientCB:uri:%s, TAG, requestUri);
161             LL_APPEND(cbList, cbNode);
162             *clientCB = cbNode;
163         }
164     }
165 #ifdef WITH_PRESENCE
166     else
167     {
168         // Ensure that the handle the SDK hands back up to the application layer for the
169         // OCDoResource call matches the found ClientCB Node.
170         *clientCB = cbNode;
171
172         if (cbData->cd)
173         {
174             cbData->cd(cbData->context);
175         }
176
177         CADestroyToken(token);
178         OICFree(*handle);
179         OICFree(requestUri);
180         OICFree(devAddr);
181         *handle = cbNode->handle;
182     }
183
184     if (method == OC_REST_PRESENCE && resourceTypeName)
185     {
186         OIC_TRACE_END();
187         // Amend the found or created node by adding a new resourceType to it.
188         return InsertResourceTypeFilter(cbNode,(char *)resourceTypeName);
189         // I own resourceTypName now.
190     }
191     else
192     {
193         OICFree(resourceTypeName);
194     }
195 #else
196     OICFree(resourceTypeName);
197 #endif
198
199     OIC_TRACE_END();
200     return OC_STACK_OK;
201
202 exit:
203     OIC_TRACE_END();
204     return OC_STACK_NO_MEMORY;
205 }
206
207 void DeleteClientCB(ClientCB * cbNode)
208 {
209     OIC_TRACE_BEGIN(%s:DeleteClientCB, TAG);
210     if (cbNode)
211     {
212         LL_DELETE(cbList, cbNode);
213         OIC_LOG (INFO, TAG, "Deleting token");
214         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)cbNode->token, cbNode->tokenLength);
215         OIC_TRACE_BUFFER("OIC_RI_CLIENTCB:DeleteClientCB:token:",
216                          (const uint8_t *)cbNode->token, cbNode->tokenLength);
217         CADestroyToken (cbNode->token);
218         if (cbNode->options)
219         {
220             OICFree(cbNode->options);
221         }
222         if(cbNode->payload)
223         {
224             OICFree(cbNode->payload);
225         }
226         OICFree(cbNode->devAddr);
227         OICFree(cbNode->handle);
228         if (cbNode->requestUri)
229         {
230             OIC_LOG_V (INFO, TAG, "Deleting callback with uri %s", cbNode->requestUri);
231             OIC_TRACE_MARK(%s:DeleteClientCB:uri:%s, TAG, cbNode->requestUri);
232             OICFree(cbNode->requestUri);
233         }
234         if (cbNode->deleteCallback)
235         {
236             cbNode->deleteCallback(cbNode->context);
237         }
238
239 #ifdef WITH_PRESENCE
240         if (cbNode->presence)
241         {
242             OICFree(cbNode->presence->timeOut);
243             OICFree(cbNode->presence);
244         }
245         if (cbNode->method == OC_REST_PRESENCE)
246         {
247             OCResourceType * pointer = cbNode->filterResourceType;
248             OCResourceType * next = NULL;
249             while(pointer)
250             {
251                 next = pointer->next;
252                 OICFree(pointer->resourcetypename);
253                 OICFree(pointer);
254                 pointer = next;
255             }
256         }
257 #endif // WITH_PRESENCE
258         OICFree(cbNode);
259         cbNode = NULL;
260     }
261     OIC_TRACE_END();
262 }
263
264 /*
265  * This function checks if the node is past its time to live and
266  * deletes it if timed-out. Calling this function with a  presence or observe
267  * callback with ttl set to 0 will not delete anything as presence nodes have
268  * their own mechanisms for timeouts. A null argument will cause the function to
269  * silently return.
270  */
271 static void CheckAndDeleteTimedOutCB(ClientCB* cbNode)
272 {
273     if (!cbNode)
274     {
275         return;
276     }
277     if (cbNode->TTL == 0)
278     {
279         return;
280     }
281     coap_tick_t now;
282     coap_ticks(&now);
283
284     if (cbNode->TTL < now)
285     {
286         OIC_LOG(INFO, TAG, "Deleting timed-out callback");
287         DeleteClientCB(cbNode);
288     }
289 }
290
291 ClientCB* GetClientCB(const CAToken_t token, uint8_t tokenLength,
292                       OCDoHandle handle, const char * requestUri)
293 {
294     ClientCB* out = NULL;
295
296     if (token && tokenLength <= CA_MAX_TOKEN_LEN && tokenLength > 0)
297     {
298         OIC_LOG (INFO, TAG,  "Looking for token");
299         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
300         LL_FOREACH(cbList, out)
301         {
302             /* de-annotate below line if want to see all token in cbList */
303             //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
304             if (memcmp(out->token, token, tokenLength) == 0)
305             {
306                 OIC_LOG(INFO, TAG, "Found in callback list");
307                 return out;
308             }
309             CheckAndDeleteTimedOutCB(out);
310         }
311     }
312     else if (handle)
313     {
314         OIC_LOG (INFO, TAG,  "Looking for handle");
315         LL_FOREACH(cbList, out)
316         {
317             if (out->handle == handle)
318             {
319                 OIC_LOG(INFO, TAG, "Found in callback list");
320                 return out;
321             }
322             CheckAndDeleteTimedOutCB(out);
323         }
324     }
325     else if (requestUri)
326     {
327         OIC_LOG_V(INFO, TAG, "Looking for uri %s", requestUri);
328         LL_FOREACH(cbList, out)
329         {
330             /* de-annotate below line if want to see all uri in cbList */
331             //OIC_LOG_V(INFO, TAG, "%s", out->requestUri);
332             if (out->requestUri && strcmp(out->requestUri, requestUri ) == 0)
333             {
334                 OIC_LOG(INFO, TAG, "Found in callback list");
335                 return out;
336             }
337             CheckAndDeleteTimedOutCB(out);
338         }
339     }
340     OIC_LOG(INFO, TAG, "Callback Not found !!");
341     return NULL;
342 }
343
344 #ifdef WITH_PRESENCE
345 OCStackResult InsertResourceTypeFilter(ClientCB * cbNode, char * resourceTypeName)
346 {
347     OCResourceType * newResourceType = NULL;
348     if (cbNode && resourceTypeName)
349     {
350         // Form a new resourceType member.
351         newResourceType = (OCResourceType *) OICMalloc(sizeof(OCResourceType));
352         if (!newResourceType)
353         {
354             return OC_STACK_NO_MEMORY;
355         }
356
357         newResourceType->next = NULL;
358         newResourceType->resourcetypename = resourceTypeName;
359
360         LL_APPEND(cbNode->filterResourceType, newResourceType);
361         return OC_STACK_OK;
362     }
363     return OC_STACK_ERROR;
364 }
365 #endif // WITH_PRESENCE
366
367 void DeleteClientCBList()
368 {
369     ClientCB* out;
370     ClientCB* tmp;
371     LL_FOREACH_SAFE(cbList, out, tmp)
372     {
373         DeleteClientCB(out);
374     }
375     cbList = NULL;
376 }
377
378 void FindAndDeleteClientCB(ClientCB * cbNode)
379 {
380     ClientCB* tmp;
381     if (cbNode)
382     {
383         LL_FOREACH(cbList, tmp)
384         {
385             if (cbNode == tmp)
386             {
387                 DeleteClientCB(tmp);
388                 break;
389             }
390         }
391     }
392 }