Merge "Adding PCF() wrappers to OC_LOG() calls that were missing in the stack."
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocobserve.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 <string.h>
22 #include "ocstack.h"
23 #include "ocstackconfig.h"
24 #include "ocstackinternal.h"
25 #include "ocobserve.h"
26 #include "ocresource.h"
27 #include "occoap.h"
28 #include "utlist.h"
29 #include "debug.h"
30 #include "ocrandom.h"
31 #include "ocmalloc.h"
32
33 // Module Name
34 #define MOD_NAME PCF("ocobserve")
35
36 #define TAG  PCF("OCStackObserve")
37
38 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
39
40 static struct ResourceObserver * serverObsList = NULL;
41 extern uint32_t SERVER_DISCOVERABLE;
42
43 OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
44 {
45     OCStackResult result = OC_STACK_ERROR;
46     ResourceObserver * observer = NULL;
47     OCEntityHandlerRequest ehRequest;
48     OCObservationInfo observationInfo;
49     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
50
51     switch(status)
52     {
53     case OC_OBSERVER_NOT_INTERESTED:
54         OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
55         observer = GetObserverUsingToken (token);
56         if(observer)
57         {
58             FormOCEntityHandlerRequest(&ehRequest, OC_REST_CANCEL_OBSERVE, bufRes, 
59                                         NULL, NULL, NULL);
60             ehRequest.obsInfo = &observationInfo;
61             ehRequest.obsInfo->action = OC_OBSERVE_DEREGISTER;
62             ehRequest.obsInfo->obsId = observer->observeId;
63             observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
64         }
65         //observer is dead, or it is not observing anymore
66         result = DeleteObserverUsingToken (token);
67         if(result != OC_STACK_OK)
68         {
69             result = OC_STACK_OBSERVER_NOT_REMOVED;
70         }
71         else
72         {
73             OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
74         }
75         break;
76     case OC_OBSERVER_STILL_INTERESTED:
77         //observer is still interested
78         OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
79                 notifications, reset the failedCount"));
80         observer = GetObserverUsingToken(token);
81         if(observer)
82         {
83             observer->forceHighQos = 0;
84             observer->failedCommCount = 0;
85             result = OC_STACK_OK;
86         }
87         else
88         {
89             result = OC_STACK_OBSERVER_NOT_FOUND;
90         }
91         break;
92     case OC_OBSERVER_FAILED_COMM:
93         //observer is not reachable
94         OC_LOG(DEBUG, TAG, PCF("observer is not reachable"));
95         observer = GetObserverUsingToken(token);
96         if(observer)
97         {
98             if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
99             {
100                 FormOCEntityHandlerRequest(&ehRequest, OC_REST_CANCEL_OBSERVE, bufRes, 
101                                             NULL, NULL, NULL);
102                 ehRequest.obsInfo = &observationInfo;
103                 ehRequest.obsInfo->action = OC_OBSERVE_DEREGISTER;
104                 ehRequest.obsInfo->obsId = observer->observeId;
105                 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
106
107                 result = DeleteObserverUsingToken (token);
108                 if(result != OC_STACK_OK)
109                 {
110                     result = OC_STACK_OBSERVER_NOT_REMOVED;
111                 }
112                 else
113                 {
114                     OC_LOG(DEBUG, TAG, PCF("removing an observer"));
115                 }
116             }
117             else
118             {
119                 observer->failedCommCount++;
120                 result = OC_STACK_OBSERVER_NOT_REMOVED;
121             }
122             observer->forceHighQos = 1;
123             OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
124         }
125         break;
126     default:
127         break;
128     }
129
130     return result;
131 }
132
133 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
134 {
135     OCStackResult stackRet = OC_STACK_ERROR;
136     OCEntityHandlerResult ehRet = OC_EH_ERROR;
137     OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
138     OCObserveReq *obs = request->observe;
139     OCObservationInfo observationInfo;
140     OCObservationId obsId;
141     ResourceObserver *resObs = NULL;
142
143     OC_LOG(INFO, TAG, PCF("Entering ProcessObserveRequest"));
144
145     request->entityHandlerRequest->resource = (OCResourceHandle)resource;
146     request->entityHandlerRequest->obsInfo = &observationInfo;
147
148     if (obs->option == OC_RESOURCE_OBSERVE_REGISTER)
149     {
150         // Request to register new observation
151         observationInfo.action = OC_OBSERVE_REGISTER;
152         // Generate observation Id for the request
153         while (1)
154         {
155             if (OC_STACK_OK != GenerateObserverId (&obsId))
156                 return OC_STACK_ERROR;
157
158             // Check if observation Id already exists
159             resObs = GetObserverUsingId (obsId);
160             if (NULL == resObs)
161             {
162                 OC_LOG_V(INFO, TAG, "Observation ID is %d", obsId);
163                 break;
164             }
165         }
166
167         observationInfo.obsId = obsId;
168         // Register the observation request with entity handler
169         ehRet = resource->entityHandler ((OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG),
170                                          request->entityHandlerRequest);
171         if (ehRet == OC_EH_OK)
172         {
173             // Add subscriber to the server observation list
174             stackRet = AddObserver ((const char*)(request->resourceUrl),
175                                     (const char *)(ehReq->query),
176                                     obsId, obs->token, obs->subAddr,
177                                     resource, request->qos);
178             if(stackRet != OC_STACK_OK)
179             {
180                 obs->result = OC_STACK_OBSERVER_NOT_ADDED;
181                 stackRet = OC_STACK_OBSERVER_NOT_ADDED;
182                 // If the observation was not added in the stack notify the entity handler
183                 observationInfo.action = OC_OBSERVE_DEREGISTER;
184                 // If the entity handler is unable to deregister, stack cannot do anything,
185                 // hence the return value from entity handler is not being checked
186                 resource->entityHandler (OC_OBSERVE_FLAG, request->entityHandlerRequest);
187             }
188             else
189             {
190                 OC_LOG(DEBUG, TAG, PCF("Added observer successfully"));
191             }
192         }
193         else
194         {
195             stackRet = OC_STACK_OBSERVER_NOT_ADDED;
196         }
197     }
198     else if (obs->option == OC_RESOURCE_OBSERVE_DEREGISTER)
199     {
200         // Request to deregister observation
201         observationInfo.action = OC_OBSERVE_DEREGISTER;
202
203         // Get observation Id using token
204         resObs = GetObserverUsingToken (obs->token);
205         if (NULL == resObs)
206         {
207             // Stack does not contain this observation request
208             // Either token is incorrect or observation list is corrupted
209             return OC_STACK_ERROR;
210         }
211         observationInfo.action = OC_OBSERVE_DEREGISTER;
212         observationInfo.obsId = resObs->observeId;
213         // Deregister the observation with entity handler. Ignoring return value
214         // from entity handler and deleting the observation from stack
215         resource->entityHandler ((OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG),
216                                  request->entityHandlerRequest);
217         stackRet = DeleteObserverUsingToken (obs->token);
218         if(stackRet != OC_STACK_OK)
219         {
220             obs->result = OC_STACK_OBSERVER_NOT_REMOVED;
221             stackRet = OC_STACK_OBSERVER_NOT_REMOVED;
222         }
223         else
224         {
225             OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
226         }
227     }
228     else
229     {
230         // Invalid observe option
231         OC_LOG(ERROR, TAG, PCF("Invalid CoAP observe option"));
232         obs->result = OC_STACK_INVALID_OBSERVE_PARAM;
233     }
234     return stackRet;
235 }
236
237 OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
238                 OCResourceType *resourceType, OCQualityOfService qos)
239 {
240     uint8_t numObs = 0;
241     OCStackResult stackRet = OC_STACK_ERROR;
242     OCEntityHandlerResult ehRet = OC_EH_ERROR;
243     ResourceObserver *resourceObserver = serverObsList;
244     OCEntityHandlerRequest entityHandlerReq;
245     unsigned char* jsonPayload = NULL;
246     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
247
248     // Find clients that are observing this resource
249     while (resourceObserver)
250     {
251         if (resourceObserver->resource == resPtr)
252         {
253             numObs++;
254             #ifdef WITH_PRESENCE
255             if(method != OC_REST_PRESENCE)
256             {
257             #endif
258                 // Invoke the entity handler for the client to process
259                 // the query according to the new representation
260                 FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
261                         NULL, resourceObserver->query, NULL);
262                 entityHandlerReq.resource = (OCResourceHandle)resPtr;
263
264                 // Even if entity handler for a resource is not successful
265                 // we continue calling entity handler for other resources
266                 ehRet = BuildObsJSONResponse((OCResource *) resPtr, &entityHandlerReq);
267                 jsonPayload = (unsigned char *)(entityHandlerReq.resJSONPayload);
268             #ifdef WITH_PRESENCE
269             }
270             else
271             {
272                 //we know it is the default entity handler
273                 OC_LOG(DEBUG, TAG, PCF("This notification is for Presence"));
274
275                 // we create the payload here
276                 if(resourceType)
277                 {
278                     sprintf((char *)bufRes, "%u:%u:%s",
279                             resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
280                 }
281                 else
282                 {
283                     sprintf((char *)bufRes, "%u:%u", resPtr->sequenceNum, maxAge);
284                 }
285
286                 jsonPayload = bufRes;
287                 ehRet = OC_EH_OK;
288             }
289
290             #endif
291             if (OC_EH_OK == ehRet)
292             {
293                 stackRet = OC_STACK_OK;
294                 OC_LOG_V(INFO, TAG, "OCStack payload: %s",
295                         jsonPayload);
296
297                 // send notifications based on the qos of the request
298                 // The qos passed as a parameter overrides what the client requested
299                 // If we want the client preference taking high priority add:
300                 // qos = resourceObserver->qos;
301                 if(qos == OC_NA_QOS){
302                     qos = resourceObserver->qos;
303                 }
304                 if(qos != OC_HIGH_QOS)
305                 {
306                     OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
307                             resourceObserver->lowQosCount);
308                     #ifdef WITH_PRESENCE
309                     if((resourceObserver->forceHighQos \
310                             || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
311                             && method != OC_REST_PRESENCE)
312                     #else
313                     if(resourceObserver->forceCON \
314                             || resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
315                     #endif
316                     {
317                         resourceObserver->lowQosCount = 0;
318                         // at some point we have to to send CON to check on the
319                         // availability of observer
320                         OC_LOG(INFO, TAG, PCF("This time we are sending the \
321                                 notification as High qos"));
322                         qos = OC_HIGH_QOS;
323                     }
324                     else
325                     {
326                         resourceObserver->lowQosCount++;
327                     }
328                 }
329                 stackRet = OCSendCoAPNotification(resourceObserver->resUri, resourceObserver->addr,
330                         qos, &(resourceObserver->token), jsonPayload, resPtr, maxAge);
331             }
332             else
333             {
334                 stackRet = OC_STACK_ERROR;
335             }
336         }
337         resourceObserver = resourceObserver->next;
338     }
339     if (numObs == 0)
340     {
341         OC_LOG(INFO, TAG, PCF("Resource has no observers"));
342         stackRet = OC_STACK_NO_OBSERVERS;
343     }
344     return stackRet;
345 }
346
347 OCStackResult GenerateObserverId (OCObservationId *observationId)
348 {
349     OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
350
351     VERIFY_NON_NULL (observationId);
352     *observationId = OCGetRandomByte();
353     return OC_STACK_OK;
354
355 exit:
356     return OC_STACK_ERROR;
357 }
358
359 OCStackResult AddObserver (const char         *resUri,
360                            const char         *query,
361                            OCObservationId    obsId,
362                            OCCoAPToken        *token,
363                            OCDevAddr          *addr,
364                            OCResource         *resHandle,
365                            OCQualityOfService qos)
366 {
367     ResourceObserver *obsNode = NULL;
368
369     obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
370     if (obsNode)
371     {
372         memset(obsNode, 0, sizeof(ResourceObserver));
373         obsNode->observeId = obsId;
374
375         obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
376         VERIFY_NON_NULL (obsNode->resUri);
377         memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
378
379         obsNode->qos = qos;
380         if(query)
381         {
382             obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
383             VERIFY_NON_NULL (obsNode->query);
384             memcpy (obsNode->query, query, strlen(query)+1);
385         }
386
387         obsNode->token.tokenLength = token->tokenLength;
388         memcpy (&(obsNode->token.token), token->token, token->tokenLength);
389
390         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
391         VERIFY_NON_NULL (obsNode->addr);
392         memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
393
394         obsNode->resource = resHandle;
395
396         LL_APPEND (serverObsList, obsNode);
397         return OC_STACK_OK;
398     }
399
400 exit:
401     if (obsNode)
402     {
403         OCFree(obsNode->resUri);
404         OCFree(obsNode->query);
405         OCFree(obsNode->addr);
406         OCFree(obsNode);
407     }
408     return OC_STACK_NO_MEMORY;
409 }
410
411 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
412 {
413     ResourceObserver *out = NULL;
414
415     if (observeId)
416     {
417         LL_FOREACH (serverObsList, out)
418         {
419             if (out->observeId == observeId)
420             {
421                 return out;
422             }
423         }
424     }
425     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
426     return NULL;
427 }
428
429 ResourceObserver* GetObserverUsingToken (const OCCoAPToken * token)
430 {
431     ResourceObserver *out = NULL;
432
433     if(token)
434     {
435         LL_FOREACH (serverObsList, out)
436         {
437             OC_LOG(INFO, TAG,PCF("comparing tokens"));
438             OC_LOG_BUFFER(INFO, TAG, token->token, token->tokenLength);
439             OC_LOG_BUFFER(INFO, TAG, out->token.token, out->token.tokenLength);
440             if((out->token.tokenLength == token->tokenLength) &&
441                (memcmp(out->token.token, token->token, token->tokenLength) == 0))
442             {
443                 return out;
444             }
445         }
446     }
447     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
448     return NULL;
449 }
450
451 OCStackResult DeleteObserverUsingToken (OCCoAPToken * token)
452 {
453     ResourceObserver *obsNode = NULL;
454
455     obsNode = GetObserverUsingToken (token);
456     if (obsNode)
457     {
458         OC_LOG_V(INFO, TAG, PCF("deleting tokens"));
459         OC_LOG_BUFFER(INFO, TAG, obsNode->token.token, obsNode->token.tokenLength);
460         LL_DELETE (serverObsList, obsNode);
461         OCFree(obsNode->resUri);
462         OCFree(obsNode->query);
463         OCFree(obsNode->addr);
464         OCFree(obsNode);
465     }
466     // it is ok if we did not find the observer...
467     return OC_STACK_OK;
468 }
469
470 void DeleteObserverList()
471 {
472     ResourceObserver *out = NULL;
473     ResourceObserver *tmp = NULL;
474     LL_FOREACH_SAFE (serverObsList, out, tmp)
475     {
476         DeleteObserverUsingToken (&(out->token));
477     }
478     serverObsList = NULL;
479 }