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