annotate OIC_LOG_BUFFER when looking for client callback and observer
[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 "ocresourcehandler.h"
27 #include "ocrandom.h"
28 #include "oic_malloc.h"
29 #include "oic_string.h"
30 #include "ocpayload.h"
31 #include "ocserverrequest.h"
32 #include "logger.h"
33
34 #include <coap/utlist.h>
35 #include <coap/pdu.h>
36
37
38 // Module Name
39 #define MOD_NAME "ocobserve"
40
41 #define TAG  "OIC_RI_OBSERVE"
42
43 #define VERIFY_NON_NULL(arg) { if (!arg) {OIC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
44
45 static struct ResourceObserver * g_serverObsList = NULL;
46 /**
47  * Determine observe QOS based on the QOS of the request.
48  * The qos passed as a parameter overrides what the client requested.
49  * If we want the client preference taking high priority make:
50  *     qos = resourceObserver->qos;
51  *
52  * @param method RESTful method.
53  * @param resourceObserver Observer.
54  * @param appQoS Quality of service.
55  * @return The quality of service of the observer.
56  */
57 static OCQualityOfService DetermineObserverQoS(OCMethod method,
58         ResourceObserver * resourceObserver, OCQualityOfService appQoS)
59 {
60     if (!resourceObserver)
61     {
62         OIC_LOG(ERROR, TAG, "DetermineObserverQoS called with invalid resourceObserver");
63         return OC_NA_QOS;
64     }
65
66     OCQualityOfService decidedQoS = appQoS;
67     if (appQoS == OC_NA_QOS)
68     {
69         decidedQoS = resourceObserver->qos;
70     }
71
72     if (appQoS != OC_HIGH_QOS)
73     {
74         OIC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
75                 resourceObserver->lowQosCount);
76 #ifdef WITH_PRESENCE
77         if ((resourceObserver->forceHighQos \
78                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
79                 && method != OC_REST_PRESENCE)
80 #else
81         if (resourceObserver->forceHighQos \
82                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT)
83 #endif
84         {
85             resourceObserver->lowQosCount = 0;
86             // at some point we have to to send CON to check on the
87             // availability of observer
88             OIC_LOG(INFO, TAG, "This time we are sending the  notification as High qos");
89             decidedQoS = OC_HIGH_QOS;
90         }
91         else
92         {
93             (resourceObserver->lowQosCount)++;
94         }
95     }
96     return decidedQoS;
97 }
98
99 #ifdef WITH_PRESENCE
100 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
101         OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos)
102 #else
103 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
104         OCQualityOfService qos)
105 #endif
106 {
107     OIC_LOG(INFO, TAG, "Entering SendObserverNotification");
108     if (!resPtr)
109     {
110         return OC_STACK_INVALID_PARAM;
111     }
112
113     OCStackResult result = OC_STACK_ERROR;
114     ResourceObserver * resourceObserver = g_serverObsList;
115     uint8_t numObs = 0;
116     OCServerRequest * request = NULL;
117     OCEntityHandlerRequest ehRequest = {0};
118     OCEntityHandlerResult ehResult = OC_EH_ERROR;
119     bool observeErrorFlag = false;
120
121     // Find clients that are observing this resource
122     while (resourceObserver)
123     {
124         if (resourceObserver->resource == resPtr)
125         {
126             numObs++;
127 #ifdef WITH_PRESENCE
128             if (method != OC_REST_PRESENCE)
129             {
130 #endif
131                 qos = DetermineObserverQoS(method, resourceObserver, qos);
132
133                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
134                         0, resPtr->sequenceNum, qos, resourceObserver->query,
135                         NULL, NULL,
136                         resourceObserver->token, resourceObserver->tokenLength,
137                         resourceObserver->resUri, 0, resourceObserver->acceptFormat,
138                         &resourceObserver->devAddr);
139
140                 if (request)
141                 {
142                     request->observeResult = OC_STACK_OK;
143                     if (result == OC_STACK_OK)
144                     {
145                         result = FormOCEntityHandlerRequest(
146                                     &ehRequest,
147                                     (OCRequestHandle) request,
148                                     request->method,
149                                     &request->devAddr,
150                                     (OCResourceHandle) resPtr,
151                                     request->query,
152                                     PAYLOAD_TYPE_REPRESENTATION,
153                                     request->payload,
154                                     request->payloadSize,
155                                     request->numRcvdVendorSpecificHeaderOptions,
156                                     request->rcvdVendorSpecificHeaderOptions,
157                                     OC_OBSERVE_NO_OPTION,
158                                     0,
159                                     request->coapID);
160                         if (result == OC_STACK_OK)
161                         {
162                             ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest,
163                                                 resPtr->entityHandlerCallbackParam);
164                             if (ehResult == OC_EH_ERROR)
165                             {
166                                 FindAndDeleteServerRequest(request);
167                             }
168                         }
169                         OCPayloadDestroy(ehRequest.payload);
170                     }
171                 }
172 #ifdef WITH_PRESENCE
173             }
174             else
175             {
176                 OCEntityHandlerResponse ehResponse = {0};
177
178                 //This is effectively the implementation for the presence entity handler.
179                 OIC_LOG(DEBUG, TAG, "This notification is for Presence");
180                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
181                         0, resPtr->sequenceNum, qos, resourceObserver->query,
182                         NULL, NULL,
183                         resourceObserver->token, resourceObserver->tokenLength,
184                         resourceObserver->resUri, 0, resourceObserver->acceptFormat,
185                         &resourceObserver->devAddr);
186
187                 if (result == OC_STACK_OK)
188                 {
189                     OCPresencePayload* presenceResBuf = OCPresencePayloadCreate(
190                             resPtr->sequenceNum, maxAge, trigger,
191                             resourceType ? resourceType->resourcetypename : NULL);
192
193                     if (!presenceResBuf)
194                     {
195                         return OC_STACK_NO_MEMORY;
196                     }
197
198                     if (result == OC_STACK_OK)
199                     {
200                         ehResponse.ehResult = OC_EH_OK;
201                         ehResponse.payload = (OCPayload*)presenceResBuf;
202                         ehResponse.persistentBufferFlag = 0;
203                         ehResponse.requestHandle = (OCRequestHandle) request;
204                         ehResponse.resourceHandle = (OCResourceHandle) resPtr;
205                         OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri),
206                                 resourceObserver->resUri);
207                         result = OCDoResponse(&ehResponse);
208                     }
209
210                     OCPresencePayloadDestroy(presenceResBuf);
211                 }
212             }
213 #endif
214
215             // Since we are in a loop, set an error flag to indicate at least one error occurred.
216             if (result != OC_STACK_OK)
217             {
218                 observeErrorFlag = true;
219             }
220         }
221         resourceObserver = resourceObserver->next;
222     }
223
224     if (numObs == 0)
225     {
226         OIC_LOG(INFO, TAG, "Resource has no observers");
227         result = OC_STACK_NO_OBSERVERS;
228     }
229     else if (observeErrorFlag)
230     {
231         OIC_LOG(ERROR, TAG, "Observer notification error");
232         result = OC_STACK_ERROR;
233     }
234     return result;
235 }
236
237 OCStackResult SendListObserverNotification (OCResource * resource,
238         OCObservationId  *obsIdList, uint8_t numberOfIds,
239         const OCRepPayload *payload,
240         uint32_t maxAge,
241         OCQualityOfService qos)
242 {
243     (void)maxAge;
244     if (!resource || !obsIdList || !payload)
245     {
246         return OC_STACK_INVALID_PARAM;
247     }
248
249     uint8_t numIds = numberOfIds;
250     ResourceObserver *observer = NULL;
251     uint8_t numSentNotification = 0;
252     OCServerRequest * request = NULL;
253     OCStackResult result = OC_STACK_ERROR;
254     bool observeErrorFlag = false;
255
256     OIC_LOG(INFO, TAG, "Entering SendListObserverNotification");
257     while(numIds)
258     {
259         observer = GetObserverUsingId (*obsIdList);
260         if (observer)
261         {
262             // Found observer - verify if it matches the resource handle
263             if (observer->resource == resource)
264             {
265                 qos = DetermineObserverQoS(OC_REST_GET, observer, qos);
266
267
268                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
269                         0, resource->sequenceNum, qos, observer->query,
270                         NULL, NULL, observer->token, observer->tokenLength,
271                         observer->resUri, 0, observer->acceptFormat,
272                         &observer->devAddr);
273
274                 if (request)
275                 {
276                     request->observeResult = OC_STACK_OK;
277                     if (result == OC_STACK_OK)
278                     {
279                         OCEntityHandlerResponse ehResponse = {0};
280                         ehResponse.ehResult = OC_EH_OK;
281                         ehResponse.payload = (OCPayload*)OCRepPayloadCreate();
282                         if (!ehResponse.payload)
283                         {
284                             FindAndDeleteServerRequest(request);
285                             continue;
286                         }
287                         memcpy(ehResponse.payload, payload, sizeof(*payload));
288                         ehResponse.persistentBufferFlag = 0;
289                         ehResponse.requestHandle = (OCRequestHandle) request;
290                         ehResponse.resourceHandle = (OCResourceHandle) resource;
291                         result = OCDoResponse(&ehResponse);
292                         if (result == OC_STACK_OK)
293                         {
294                             OIC_LOG_V(INFO, TAG, "Observer id %d notified.", *obsIdList);
295
296                             // Increment only if OCDoResponse is successful
297                             numSentNotification++;
298
299                             OICFree(ehResponse.payload);
300                             FindAndDeleteServerRequest(request);
301                         }
302                         else
303                         {
304                             OIC_LOG_V(INFO, TAG, "Error notifying observer id %d.", *obsIdList);
305                         }
306                     }
307                     else
308                     {
309                         FindAndDeleteServerRequest(request);
310                     }
311                 }
312                 // Since we are in a loop, set an error flag to indicate
313                 // at least one error occurred.
314                 if (result != OC_STACK_OK)
315                 {
316                     observeErrorFlag = true;
317                 }
318             }
319         }
320         obsIdList++;
321         numIds--;
322     }
323
324     if (numSentNotification == numberOfIds && !observeErrorFlag)
325     {
326         return OC_STACK_OK;
327     }
328     else if (numSentNotification == 0)
329     {
330         return OC_STACK_NO_OBSERVERS;
331     }
332     else
333     {
334         OIC_LOG(ERROR, TAG, "Observer notification error");
335         return OC_STACK_ERROR;
336     }
337 }
338
339 OCStackResult GenerateObserverId (OCObservationId *observationId)
340 {
341     ResourceObserver *resObs = NULL;
342
343     OIC_LOG(INFO, TAG, "Entering GenerateObserverId");
344     VERIFY_NON_NULL (observationId);
345
346     do
347     {
348         *observationId = OCGetRandomByte();
349         // Check if observation Id already exists
350         resObs = GetObserverUsingId (*observationId);
351     } while (NULL != resObs);
352
353     OIC_LOG_V(INFO, TAG, "GeneratedObservation ID is %u", *observationId);
354
355     return OC_STACK_OK;
356 exit:
357     return OC_STACK_ERROR;
358 }
359
360 OCStackResult AddObserver (const char         *resUri,
361                            const char         *query,
362                            OCObservationId    obsId,
363                            CAToken_t          token,
364                            uint8_t            tokenLength,
365                            OCResource         *resHandle,
366                            OCQualityOfService qos,
367                            OCPayloadFormat    acceptFormat,
368                            const OCDevAddr    *devAddr)
369 {
370     // Check if resource exists and is observable.
371     if (!resHandle)
372     {
373         return OC_STACK_INVALID_PARAM;
374     }
375     if (!(resHandle->resourceProperties & OC_OBSERVABLE))
376     {
377         return OC_STACK_RESOURCE_ERROR;
378     }
379
380     if (!resUri || !token)
381     {
382         return OC_STACK_INVALID_PARAM;
383     }
384
385     ResourceObserver *obsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
386     if (obsNode)
387     {
388         obsNode->observeId = obsId;
389
390         obsNode->resUri = OICStrdup(resUri);
391         VERIFY_NON_NULL (obsNode->resUri);
392
393         obsNode->qos = qos;
394         obsNode->acceptFormat = acceptFormat;
395         if (query)
396         {
397             obsNode->query = OICStrdup(query);
398             VERIFY_NON_NULL (obsNode->query);
399         }
400         // If tokenLength is zero, the return value depends on the
401         // particular library implementation (it may or may not be a null pointer).
402         if (tokenLength)
403         {
404             obsNode->token = (CAToken_t)OICMalloc(tokenLength);
405             VERIFY_NON_NULL (obsNode->token);
406             memcpy(obsNode->token, token, tokenLength);
407         }
408         obsNode->tokenLength = tokenLength;
409
410         obsNode->devAddr = *devAddr;
411         obsNode->resource = resHandle;
412
413         LL_APPEND (g_serverObsList, obsNode);
414
415         return OC_STACK_OK;
416     }
417
418 exit:
419     if (obsNode)
420     {
421         OICFree(obsNode->resUri);
422         OICFree(obsNode->query);
423         OICFree(obsNode);
424     }
425     return OC_STACK_NO_MEMORY;
426 }
427
428 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
429 {
430     ResourceObserver *out = NULL;
431
432     if (observeId)
433     {
434         LL_FOREACH (g_serverObsList, out)
435         {
436             if (out->observeId == observeId)
437             {
438                 return out;
439             }
440         }
441     }
442     OIC_LOG(INFO, TAG, "Observer node not found!!");
443     return NULL;
444 }
445
446 ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLength)
447 {
448     if (token)
449     {
450         OIC_LOG(INFO, TAG, "Looking for token");
451         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
452
453         ResourceObserver *out = NULL;
454         LL_FOREACH (g_serverObsList, out)
455         {
456             /* de-annotate below line if want to see all token in cbList */
457             //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
458             if ((memcmp(out->token, token, tokenLength) == 0))
459             {
460                 OIC_LOG(INFO, TAG, "Found in observer list");
461                 return out;
462             }
463         }
464     }
465     else
466     {
467         OIC_LOG(ERROR, TAG, "Passed in NULL token");
468     }
469
470     OIC_LOG(INFO, TAG, "Observer node not found!!");
471     return NULL;
472 }
473
474 OCStackResult DeleteObserverUsingToken (CAToken_t token, uint8_t tokenLength)
475 {
476     if (!token)
477     {
478         return OC_STACK_INVALID_PARAM;
479     }
480
481     ResourceObserver *obsNode = GetObserverUsingToken (token, tokenLength);
482     if (obsNode)
483     {
484         OIC_LOG_V(INFO, TAG, "deleting observer id  %u with token", obsNode->observeId);
485         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)obsNode->token, tokenLength);
486         LL_DELETE (g_serverObsList, obsNode);
487         OICFree(obsNode->resUri);
488         OICFree(obsNode->query);
489         OICFree(obsNode->token);
490         OICFree(obsNode);
491     }
492     // it is ok if we did not find the observer...
493     return OC_STACK_OK;
494 }
495
496 void DeleteObserverList()
497 {
498     ResourceObserver *out = NULL;
499     ResourceObserver *tmp = NULL;
500     LL_FOREACH_SAFE (g_serverObsList, out, tmp)
501     {
502         if (out)
503         {
504             DeleteObserverUsingToken ((out->token), out->tokenLength);
505         }
506     }
507     g_serverObsList = NULL;
508 }
509
510 /*
511  * CA layer expects observe registration/de-reg/notiifcations to be passed as a header
512  * option, which breaks the protocol abstraction requirement between RI & CA, and
513  * has to be fixed in the future. The function below adds the header option for observe.
514  * It should be noted that the observe header option is assumed to be the first option
515  * in the list of user defined header options and hence it is inserted at the front
516  * of the header options list and number of options adjusted accordingly.
517  */
518 OCStackResult
519 CreateObserveHeaderOption (CAHeaderOption_t **caHdrOpt,
520                            OCHeaderOption *ocHdrOpt,
521                            uint8_t numOptions,
522                            uint8_t observeFlag)
523 {
524     if (!caHdrOpt)
525     {
526         return OC_STACK_INVALID_PARAM;
527     }
528
529     if (numOptions > 0 && !ocHdrOpt)
530     {
531         OIC_LOG (INFO, TAG, "options are NULL though number is non zero");
532         return OC_STACK_INVALID_PARAM;
533     }
534
535     CAHeaderOption_t *tmpHdrOpt = NULL;
536
537     tmpHdrOpt = (CAHeaderOption_t *) OICCalloc ((numOptions+1), sizeof(CAHeaderOption_t));
538     if (NULL == tmpHdrOpt)
539     {
540         return OC_STACK_NO_MEMORY;
541     }
542     tmpHdrOpt[0].protocolID = CA_COAP_ID;
543     tmpHdrOpt[0].optionID = COAP_OPTION_OBSERVE;
544     tmpHdrOpt[0].optionLength = sizeof(uint8_t);
545     tmpHdrOpt[0].optionData[0] = observeFlag;
546     for (uint8_t i = 0; i < numOptions; i++)
547     {
548         memcpy (&(tmpHdrOpt[i+1]), &(ocHdrOpt[i]), sizeof(CAHeaderOption_t));
549     }
550
551     *caHdrOpt = tmpHdrOpt;
552     return OC_STACK_OK;
553 }
554
555 /*
556  * CA layer passes observe information to the RI layer as a header option, which
557  * breaks the protocol abstraction requirement between RI & CA, and has to be fixed
558  * in the future. The function below removes the observe header option and processes it.
559  * It should be noted that the observe header option is always assumed to be the first
560  * option in the list of user defined header options and hence it is deleted from the
561  * front of the header options list and the number of options is adjusted accordingly.
562  */
563 OCStackResult
564 GetObserveHeaderOption (uint32_t * observationOption,
565                         CAHeaderOption_t *options,
566                         uint8_t * numOptions)
567 {
568     if (!observationOption)
569     {
570         return OC_STACK_INVALID_PARAM;
571     }
572
573     if (!options || !numOptions)
574     {
575         OIC_LOG (INFO, TAG, "No options present");
576         return OC_STACK_OK;
577     }
578
579     for(uint8_t i = 0; i < *numOptions; i++)
580     {
581         if (options[i].protocolID == CA_COAP_ID &&
582                 options[i].optionID == COAP_OPTION_OBSERVE)
583         {
584             *observationOption = options[i].optionData[0];
585             for(uint8_t c = i; c < *numOptions-1; c++)
586             {
587                 options[i] = options[i+1];
588             }
589             (*numOptions)--;
590             return OC_STACK_OK;
591         }
592     }
593     return OC_STACK_OK;
594 }
595