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