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