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