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