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