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