Update snapshot(2018-01-04)
[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 "octhread.h"
33 #include "logger.h"
34
35 #include <coap/utlist.h>
36 #include <coap/pdu.h>
37 #include <coap/coap.h>
38
39 // Module Name
40 #define MOD_NAME "ocobserve"
41
42 #define TAG  "OIC_RI_OBSERVE"
43
44 #define VERIFY_NON_NULL(arg) { if (!arg) {OIC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
45
46 static struct ResourceObserver * g_serverObsList = NULL;
47 static oc_mutex g_serverObsListMutex = NULL;
48
49 static ResourceObserver* GetObserverUsingIdAsOwner (const OCObservationId observeId);
50
51 static ResourceObserver* CloneObserverNode (ResourceObserver* observer)
52 {
53     ResourceObserver* dupObsNode = NULL;
54     if (observer)
55     {
56         dupObsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
57         VERIFY_NON_NULL(dupObsNode);
58         memcpy(dupObsNode, observer, sizeof(ResourceObserver));
59
60         if (observer->resUri)
61         {
62             dupObsNode->resUri = OICStrdup(observer->resUri);
63             VERIFY_NON_NULL(dupObsNode->resUri);
64         }
65
66         if (observer->query)
67         {
68             dupObsNode->query = OICStrdup(observer->query);
69             VERIFY_NON_NULL(dupObsNode->query);
70         }
71
72         if (observer->token)
73         {
74             dupObsNode->token = (CAToken_t)OICMalloc(observer->tokenLength);
75             VERIFY_NON_NULL(dupObsNode->token);
76             memcpy(dupObsNode->token, observer->token, observer->tokenLength);
77         }
78
79         dupObsNode->next = NULL;
80     }
81
82     return dupObsNode;
83
84 exit:
85     FreeObserver(dupObsNode);
86     return NULL;
87 }
88
89 static void FreeObserverList (ResourceObserver* list)
90 {
91     ResourceObserver* head = list;
92     ResourceObserver* del = NULL;
93     while (NULL != head)
94     {
95         del = head;
96         head = head->next;
97
98         OICFree(del->resUri);
99         OICFree(del->query);
100         OICFree(del->token);
101         OICFree(del);
102     }
103 }
104
105 static ResourceObserver* CloneObserverList (ResourceObserver* obsList)
106 {
107     ResourceObserver* dupList = NULL;
108     ResourceObserver* out = NULL;
109
110     LL_FOREACH(obsList, out)
111     {
112         ResourceObserver *obsNode = CloneObserverNode(out);
113         if (NULL == obsNode)
114         {
115             FreeObserverList(dupList);
116             dupList = NULL;
117             break;
118         }
119
120         LL_APPEND(dupList, obsNode);
121     }
122
123     return dupList;
124 }
125
126 /**
127  * Determine observe QOS based on the QOS of the request.
128  * The qos passed as a parameter overrides what the client requested.
129  * If we want the client preference taking high priority make:
130  *     qos = resourceObserver->qos;
131  *
132  * @param method RESTful method.
133  * @param resourceObserver Observer.
134  * @param appQoS Quality of service.
135  * @return The quality of service of the observer.
136  */
137 static OCQualityOfService DetermineObserverQoS(OCMethod method,
138         ResourceObserver * resourceObserver, OCQualityOfService appQoS)
139 {
140     if (!resourceObserver)
141     {
142         OIC_LOG(ERROR, TAG, "DetermineObserverQoS called with invalid resourceObserver");
143         return OC_NA_QOS;
144     }
145
146     OCQualityOfService decidedQoS = appQoS;
147     if (appQoS == OC_NA_QOS)
148     {
149         decidedQoS = resourceObserver->qos;
150     }
151
152     if (appQoS != OC_HIGH_QOS)
153     {
154         OIC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
155                 resourceObserver->lowQosCount);
156 #ifdef WITH_PRESENCE
157         if ((resourceObserver->forceHighQos \
158                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
159                 && method != OC_REST_PRESENCE)
160 #else
161         if (resourceObserver->forceHighQos \
162                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT)
163 #endif
164         {
165             resourceObserver->lowQosCount = 0;
166             // at some point we have to to send CON to check on the
167             // availability of observer
168             OIC_LOG(INFO, TAG, "This time we are sending the  notification as High qos");
169             decidedQoS = OC_HIGH_QOS;
170         }
171         else
172         {
173             (resourceObserver->lowQosCount)++;
174         }
175     }
176     return decidedQoS;
177 }
178
179 /**
180  * Create a get request and pass to entityhandler to notify specific observer.
181  *
182  * @param observer Observer that need to be notified.
183  * @param qos Quality of service of resource.
184  *
185  * @return ::OC_STACK_OK on success, some other value upon failure.
186  */
187 static OCStackResult SendObserveNotification(ResourceObserver *observer,
188                                              OCQualityOfService qos)
189 {
190     OCStackResult result = OC_STACK_ERROR;
191     OCServerRequest * request = NULL;
192     OCEntityHandlerRequest ehRequest = {0};
193     OCEntityHandlerResult ehResult = OC_EH_ERROR;
194
195     result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
196                               0, observer->resource->sequenceNum, qos,
197                               observer->query, NULL, NULL,
198                               observer->token, observer->tokenLength,
199                               observer->resUri, 0, observer->acceptFormat,
200                               &observer->devAddr);
201
202     if (request)
203     {
204         request->observeResult = OC_STACK_OK;
205         if (result == OC_STACK_OK)
206         {
207             result = FormOCEntityHandlerRequest(
208                         &ehRequest,
209                         (OCRequestHandle) request->requestId,
210                         request->method,
211                         &request->devAddr,
212                         (OCResourceHandle) observer->resource,
213                         request->query,
214                         PAYLOAD_TYPE_REPRESENTATION,
215                         request->payload,
216                         request->payloadSize,
217                         request->numRcvdVendorSpecificHeaderOptions,
218                         request->rcvdVendorSpecificHeaderOptions,
219                         OC_OBSERVE_NO_OPTION,
220                         0,
221                         request->coapID);
222             if (result == OC_STACK_OK)
223             {
224                 ehResult = observer->resource->entityHandler(OC_REQUEST_FLAG, &ehRequest,
225                                     observer->resource->entityHandlerCallbackParam);
226
227                 // Clear server request on error case
228                 if (!OCResultToSuccess(EntityHandlerCodeToOCStackCode(ehResult)))
229                 {
230                     FindAndDeleteServerRequest(request);
231                 }
232                 // Reset Observer TTL.
233                 observer->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
234             }
235             OCPayloadDestroy(ehRequest.payload);
236         }
237     }
238
239     return result;
240 }
241
242 #ifdef WITH_PRESENCE
243 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
244         OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos)
245 #else
246 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
247         OCQualityOfService qos)
248 #endif
249 {
250     OIC_LOG(INFO, TAG, "Entering SendObserverNotification");
251     if (!resPtr)
252     {
253         return OC_STACK_INVALID_PARAM;
254     }
255
256     OCStackResult result = OC_STACK_ERROR;
257     ResourceObserver * resourceObserver = NULL;
258     uint8_t numObs = 0;
259     OCServerRequest * request = NULL;
260     bool observeErrorFlag = false;
261
262     // Find clients that are observing this resource
263     oc_mutex_lock(g_serverObsListMutex);
264     resourceObserver = g_serverObsList;
265     while (resourceObserver)
266     {
267         if (resourceObserver->resource == resPtr)
268         {
269             numObs++;
270 #ifdef WITH_PRESENCE
271             if (method != OC_REST_PRESENCE)
272             {
273 #endif
274                 qos = DetermineObserverQoS(method, resourceObserver, qos);
275                 result = SendObserveNotification(resourceObserver, qos);
276 #ifdef WITH_PRESENCE
277             }
278             else
279             {
280                 OCEntityHandlerResponse ehResponse = {0};
281
282                 //This is effectively the implementation for the presence entity handler.
283                 OIC_LOG(DEBUG, TAG, "This notification is for Presence");
284                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
285                         0, resPtr->sequenceNum, qos, resourceObserver->query,
286                         NULL, NULL,
287                         resourceObserver->token, resourceObserver->tokenLength,
288                         resourceObserver->resUri, 0, resourceObserver->acceptFormat,
289                         &resourceObserver->devAddr);
290
291                 if (result == OC_STACK_OK)
292                 {
293                     OCPresencePayload* presenceResBuf = OCPresencePayloadCreate(
294                             resPtr->sequenceNum, maxAge, trigger,
295                             resourceType ? resourceType->resourcetypename : NULL);
296
297                     if (!presenceResBuf)
298                     {
299                         oc_mutex_unlock(g_serverObsListMutex);
300                         return OC_STACK_NO_MEMORY;
301                     }
302
303                     if (result == OC_STACK_OK)
304                     {
305                         ehResponse.ehResult = OC_EH_OK;
306                         ehResponse.payload = (OCPayload*)presenceResBuf;
307                         ehResponse.persistentBufferFlag = 0;
308                         ehResponse.requestHandle = (OCRequestHandle) request->requestId;
309                         ehResponse.resourceHandle = (OCResourceHandle) resPtr;
310                         OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri),
311                                 resourceObserver->resUri);
312                         result = OCDoResponse(&ehResponse);
313                         if (result != OC_STACK_OK)
314                         {
315                             OIC_LOG(ERROR, TAG, "Failed to send presence notification!");
316                             FindAndDeleteServerRequest(request);
317                         }
318                     }
319
320                     OCPresencePayloadDestroy(presenceResBuf);
321                 }
322             }
323 #endif
324
325             // Since we are in a loop, set an error flag to indicate at least one error occurred.
326             if (result != OC_STACK_OK)
327             {
328                 observeErrorFlag = true;
329             }
330         }
331         resourceObserver = resourceObserver->next;
332     }
333
334     oc_mutex_unlock(g_serverObsListMutex);
335
336     if (numObs == 0)
337     {
338         OIC_LOG(INFO, TAG, "Resource has no observers");
339         result = OC_STACK_NO_OBSERVERS;
340     }
341     else if (observeErrorFlag)
342     {
343         OIC_LOG(ERROR, TAG, "Observer notification error");
344         result = OC_STACK_ERROR;
345     }
346     return result;
347 }
348
349 OCStackResult SendListObserverNotification (OCResource * resource,
350         OCObservationId  *obsIdList, uint8_t numberOfIds,
351         const OCRepPayload *payload,
352         uint32_t maxAge,
353         OCQualityOfService qos)
354 {
355     (void)maxAge;
356     if (!resource || !obsIdList || !payload)
357     {
358         return OC_STACK_INVALID_PARAM;
359     }
360
361     uint8_t numIds = numberOfIds;
362     ResourceObserver *observer = NULL;
363     uint8_t numSentNotification = 0;
364     OCServerRequest * request = NULL;
365     OCStackResult result = OC_STACK_ERROR;
366     bool observeErrorFlag = false;
367
368     OIC_LOG(INFO, TAG, "Entering SendListObserverNotification");
369     while(numIds)
370     {
371         oc_mutex_lock(g_serverObsListMutex);
372         observer = GetObserverUsingIdAsOwner (*obsIdList);
373         if (observer)
374         {
375             // Found observer - verify if it matches the resource handle
376             if (observer->resource == resource)
377             {
378                 qos = DetermineObserverQoS(OC_REST_GET, observer, qos);
379
380
381                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
382                         0, resource->sequenceNum, qos, observer->query,
383                         NULL, NULL, observer->token, observer->tokenLength,
384                         observer->resUri, 0, observer->acceptFormat,
385                         &observer->devAddr);
386
387                 if (request)
388                 {
389                     request->observeResult = OC_STACK_OK;
390                     if (result == OC_STACK_OK)
391                     {
392                         OCEntityHandlerResponse ehResponse = {0};
393                         ehResponse.ehResult = OC_EH_OK;
394                         ehResponse.payload = (OCPayload*)OCRepPayloadCreate();
395                         if (!ehResponse.payload)
396                         {
397                             FindAndDeleteServerRequest(request);
398                             oc_mutex_unlock(g_serverObsListMutex);
399                             continue;
400                         }
401                         memcpy(ehResponse.payload, payload, sizeof(*payload));
402                         ehResponse.persistentBufferFlag = 0;
403                         ehResponse.requestHandle = (OCRequestHandle) request->requestId;
404                         ehResponse.resourceHandle = (OCResourceHandle) resource;
405                         result = OCDoResponse(&ehResponse);
406                         if (result == OC_STACK_OK)
407                         {
408                             OIC_LOG_V(INFO, TAG, "Observer id %d notified.", *obsIdList);
409
410                             // Increment only if OCDoResponse is successful
411                             numSentNotification++;
412                         }
413                         else
414                         {
415                             OIC_LOG_V(INFO, TAG, "Error notifying observer id %d.", *obsIdList);
416                             FindAndDeleteServerRequest(request);
417                         }
418
419                         // Reset Observer TTL.
420                         observer->TTL =
421                                 GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
422
423                         OICFree(ehResponse.payload);
424                     }
425                     else
426                     {
427                         FindAndDeleteServerRequest(request);
428                     }
429                 }
430
431                 // Since we are in a loop, set an error flag to indicate
432                 // at least one error occurred.
433                 if (result != OC_STACK_OK)
434                 {
435                     observeErrorFlag = true;
436                 }
437             }
438         }
439
440         oc_mutex_unlock(g_serverObsListMutex);
441         obsIdList++;
442         numIds--;
443     }
444
445     if (numSentNotification == numberOfIds && !observeErrorFlag)
446     {
447         return OC_STACK_OK;
448     }
449     else if (numSentNotification == 0)
450     {
451         return OC_STACK_NO_OBSERVERS;
452     }
453     else
454     {
455         OIC_LOG(ERROR, TAG, "Observer notification error");
456         return OC_STACK_ERROR;
457     }
458 }
459
460 OCStackResult GenerateObserverId (OCObservationId *observationId)
461 {
462     bool found = false;
463
464     OIC_LOG(INFO, TAG, "Entering GenerateObserverId");
465     VERIFY_NON_NULL (observationId);
466
467     do
468     {
469         do
470         {
471             *observationId = OCGetRandomByte();
472         } while (0 == *observationId); //Make sure *observationId is not 0
473         // Check if observation Id already exists
474         found = IsObserverAvailable (*observationId);
475     } while (found);
476
477     OIC_LOG_V(INFO, TAG, "GeneratedObservation ID is %u", *observationId);
478
479     return OC_STACK_OK;
480 exit:
481     return OC_STACK_ERROR;
482 }
483
484 OCStackResult AddObserver (const char         *resUri,
485                            const char         *query,
486                            OCObservationId    obsId,
487                            CAToken_t          token,
488                            uint8_t            tokenLength,
489                            OCResource         *resHandle,
490                            OCQualityOfService qos,
491                            OCPayloadFormat    acceptFormat,
492                            const OCDevAddr    *devAddr)
493 {
494     // Check if resource exists and is observable.
495     if (!resHandle)
496     {
497         return OC_STACK_INVALID_PARAM;
498     }
499     if (!(resHandle->resourceProperties & OC_OBSERVABLE))
500     {
501         return OC_STACK_RESOURCE_ERROR;
502     }
503
504     if (!resUri || !token)
505     {
506         return OC_STACK_INVALID_PARAM;
507     }
508
509     ResourceObserver *obsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
510     if (obsNode)
511     {
512         obsNode->observeId = obsId;
513
514         obsNode->resUri = OICStrdup(resUri);
515         VERIFY_NON_NULL (obsNode->resUri);
516
517         obsNode->qos = qos;
518         obsNode->acceptFormat = acceptFormat;
519         if (query)
520         {
521             obsNode->query = OICStrdup(query);
522             VERIFY_NON_NULL (obsNode->query);
523         }
524         // If tokenLength is zero, the return value depends on the
525         // particular library implementation (it may or may not be a null pointer).
526         if (tokenLength)
527         {
528             obsNode->token = (CAToken_t)OICMalloc(tokenLength);
529             VERIFY_NON_NULL (obsNode->token);
530             memcpy(obsNode->token, token, tokenLength);
531         }
532         obsNode->tokenLength = tokenLength;
533
534         obsNode->devAddr = *devAddr;
535         obsNode->resource = resHandle;
536
537 #ifdef WITH_PRESENCE
538         if ((strcmp(resUri, OC_RSRVD_PRESENCE_URI) == 0))
539         {
540             obsNode->TTL = 0;
541         }
542         else
543 #endif
544         {
545             obsNode->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
546         }
547
548         oc_mutex_lock(g_serverObsListMutex);
549         LL_APPEND (g_serverObsList, obsNode);
550         oc_mutex_unlock(g_serverObsListMutex);
551
552         return OC_STACK_OK;
553     }
554
555 exit:
556     if (obsNode)
557     {
558         OICFree(obsNode->resUri);
559         OICFree(obsNode->query);
560         OICFree(obsNode);
561     }
562     return OC_STACK_NO_MEMORY;
563 }
564
565 /*
566  * This function checks if the node is past its time to live and
567  * deletes it if timed-out. Calling this function with a  presence callback
568  * with ttl set to 0 will not delete anything as presence nodes have
569  * their own mechanisms for timeouts. A null argument will cause the function to
570  * silently return.
571  */
572 static void CheckTimedOutObserver(ResourceObserver* observer)
573 {
574     if (!observer || observer->TTL == 0)
575     {
576         return;
577     }
578
579     coap_tick_t now;
580     coap_ticks(&now);
581
582     if (observer->TTL < now)
583     {
584         // Send confirmable notification message to observer.
585         OIC_LOG(INFO, TAG, "Sending High-QoS notification to observer");
586         SendObserveNotification(observer, OC_HIGH_QOS);
587     }
588 }
589
590 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
591 {
592     ResourceObserver *out = NULL;
593
594     if (observeId)
595     {
596         oc_mutex_lock(g_serverObsListMutex);
597         LL_FOREACH (g_serverObsList, out)
598         {
599             if (out->observeId == observeId)
600             {
601                 oc_mutex_unlock(g_serverObsListMutex);
602                 return CloneObserverNode(out);
603             }
604             CheckTimedOutObserver(out);
605         }
606         oc_mutex_unlock(g_serverObsListMutex);
607     }
608     OIC_LOG(INFO, TAG, "Observer node not found!!");
609     return NULL;
610 }
611
612 static ResourceObserver* GetObserverUsingIdAsOwner (const OCObservationId observeId)
613 {
614     ResourceObserver *out = NULL;
615
616     if (observeId)
617     {
618         LL_FOREACH (g_serverObsList, out)
619         {
620             if (out->observeId == observeId)
621             {
622                 return out;
623             }
624             CheckTimedOutObserver(out);
625         }
626     }
627     OIC_LOG(INFO, TAG, "Observer node not found!!");
628     return NULL;
629 }
630
631 bool IsObserverAvailable (const OCObservationId observeId)
632 {
633     ResourceObserver *out = NULL;
634
635     if (observeId)
636     {
637         oc_mutex_lock(g_serverObsListMutex);
638         LL_FOREACH (g_serverObsList, out)
639         {
640             if (out->observeId == observeId)
641             {
642                 oc_mutex_unlock(g_serverObsListMutex);
643                 return true;
644             }
645         }
646         oc_mutex_unlock(g_serverObsListMutex);
647     }
648
649     return false;
650 }
651
652 ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLength)
653 {
654     if (token)
655     {
656         OIC_LOG(INFO, TAG, "Looking for token");
657         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
658
659         ResourceObserver *out = NULL;
660         oc_mutex_lock(g_serverObsListMutex);
661         LL_FOREACH (g_serverObsList, out)
662         {
663             /* de-annotate below line if want to see all token in cbList */
664             //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
665             if ((memcmp(out->token, token, tokenLength) == 0))
666             {
667                 OIC_LOG(INFO, TAG, "Found in observer list");
668                 ResourceObserver *observer = CloneObserverNode(out);
669                 oc_mutex_unlock(g_serverObsListMutex);
670                 return observer;
671             }
672             CheckTimedOutObserver(out);
673         }
674         oc_mutex_unlock(g_serverObsListMutex);
675     }
676     else
677     {
678         OIC_LOG(ERROR, TAG, "Passed in NULL token");
679     }
680
681     OIC_LOG(INFO, TAG, "Observer node not found!!");
682     return NULL;
683 }
684
685 static ResourceObserver* GetObserverUsingTokenAsOwner (const CAToken_t token, uint8_t tokenLength)
686 {
687     if (token)
688     {
689         OIC_LOG(INFO, TAG, "Looking for token");
690         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
691
692         ResourceObserver *out = NULL;
693         LL_FOREACH (g_serverObsList, out)
694         {
695             /* de-annotate below line if want to see all token in cbList */
696             //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
697             if ((memcmp(out->token, token, tokenLength) == 0))
698             {
699                 OIC_LOG(INFO, TAG, "Found in observer list");
700                 return out;
701             }
702             CheckTimedOutObserver(out);
703         }
704     }
705     else
706     {
707         OIC_LOG(ERROR, TAG, "Passed in NULL token");
708     }
709
710     OIC_LOG(INFO, TAG, "Observer node not found!!");
711     return NULL;
712 }
713
714 OCStackResult DeleteObserverUsingToken (CAToken_t token, uint8_t tokenLength)
715 {
716     if (!token)
717     {
718         return OC_STACK_INVALID_PARAM;
719     }
720
721     oc_mutex_lock(g_serverObsListMutex);
722     ResourceObserver *obsNode = GetObserverUsingTokenAsOwner (token, tokenLength);
723     if (obsNode)
724     {
725         OIC_LOG_V(INFO, TAG, "deleting observer id  %u with token", obsNode->observeId);
726         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)obsNode->token, tokenLength);
727
728         LL_DELETE (g_serverObsList, obsNode);
729         FreeObserver(obsNode);
730     }
731     oc_mutex_unlock(g_serverObsListMutex);
732
733     // it is ok if we did not find the observer...
734     return OC_STACK_OK;
735 }
736
737 OCStackResult DeleteObserverUsingDevAddr(const OCDevAddr *devAddr)
738 {
739     if (!devAddr)
740     {
741         return OC_STACK_INVALID_PARAM;
742     }
743
744     oc_mutex_lock(g_serverObsListMutex);
745     ResourceObserver* obsDupList = CloneObserverList(g_serverObsList);
746     oc_mutex_unlock(g_serverObsListMutex);
747
748     ResourceObserver *out = NULL;
749     ResourceObserver *tmp = NULL;
750     LL_FOREACH_SAFE(obsDupList, out, tmp)
751     {
752         if (out)
753         {
754             if ((strcmp(out->devAddr.addr, devAddr->addr) == 0)
755                     && out->devAddr.port == devAddr->port)
756             {
757                 OIC_LOG_V(INFO, TAG, "deleting observer id  %u with %s:%u",
758                           out->observeId, out->devAddr.addr, out->devAddr.port);
759                 OCStackFeedBack(out->token, out->tokenLength, OC_OBSERVER_NOT_INTERESTED);
760             }
761         }
762     }
763
764     FreeObserverList(obsDupList);
765     return OC_STACK_OK;
766 }
767
768 void DeleteObserverList()
769 {
770     oc_mutex_lock(g_serverObsListMutex);
771
772     ResourceObserver* head = g_serverObsList;
773     ResourceObserver* del = NULL;
774     while (NULL != head)
775     {
776         del = head;
777         head = head->next;
778
779         OIC_LOG_V(INFO, TAG, "deleting observer id  %u with token", del->observeId);
780         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)del->token, del->tokenLength);
781
782         FreeObserver(del);
783     }
784
785     g_serverObsList = NULL;
786     oc_mutex_unlock(g_serverObsListMutex);
787 }
788
789 /*
790  * CA layer expects observe registration/de-reg/notiifcations to be passed as a header
791  * option, which breaks the protocol abstraction requirement between RI & CA, and
792  * has to be fixed in the future. The function below adds the header option for observe.
793  * It should be noted that the observe header option is assumed to be the first option
794  * in the list of user defined header options and hence it is inserted at the front
795  * of the header options list and number of options adjusted accordingly.
796  */
797 OCStackResult
798 CreateObserveHeaderOption (CAHeaderOption_t **caHdrOpt,
799                            OCHeaderOption *ocHdrOpt,
800                            uint8_t numOptions,
801                            uint8_t observeFlag)
802 {
803     if (!caHdrOpt)
804     {
805         return OC_STACK_INVALID_PARAM;
806     }
807
808     if (numOptions > 0 && !ocHdrOpt)
809     {
810         OIC_LOG (INFO, TAG, "options are NULL though number is non zero");
811         return OC_STACK_INVALID_PARAM;
812     }
813
814     CAHeaderOption_t *tmpHdrOpt = NULL;
815
816     tmpHdrOpt = (CAHeaderOption_t *) OICCalloc ((numOptions+1), sizeof(CAHeaderOption_t));
817     if (NULL == tmpHdrOpt)
818     {
819         return OC_STACK_NO_MEMORY;
820     }
821     tmpHdrOpt[0].protocolID = CA_COAP_ID;
822     tmpHdrOpt[0].optionID = COAP_OPTION_OBSERVE;
823     tmpHdrOpt[0].optionLength = sizeof(uint8_t);
824     tmpHdrOpt[0].optionData[0] = observeFlag;
825     for (uint8_t i = 0; i < numOptions; i++)
826     {
827         memcpy (&(tmpHdrOpt[i+1]), &(ocHdrOpt[i]), sizeof(CAHeaderOption_t));
828     }
829
830     *caHdrOpt = tmpHdrOpt;
831     return OC_STACK_OK;
832 }
833
834 /*
835  * CA layer passes observe information to the RI layer as a header option, which
836  * breaks the protocol abstraction requirement between RI & CA, and has to be fixed
837  * in the future. The function below removes the observe header option and processes it.
838  * It should be noted that the observe header option is always assumed to be the first
839  * option in the list of user defined header options and hence it is deleted from the
840  * front of the header options list and the number of options is adjusted accordingly.
841  */
842 OCStackResult
843 GetObserveHeaderOption (uint32_t * observationOption,
844                         CAHeaderOption_t *options,
845                         uint8_t * numOptions)
846 {
847     if (!observationOption)
848     {
849         return OC_STACK_INVALID_PARAM;
850     }
851
852     if (!options || !numOptions)
853     {
854         OIC_LOG (INFO, TAG, "No options present");
855         return OC_STACK_OK;
856     }
857
858     for(uint8_t i = 0; i < *numOptions; i++)
859     {
860         if (options[i].protocolID == CA_COAP_ID &&
861                 options[i].optionID == COAP_OPTION_OBSERVE)
862         {
863             *observationOption = options[i].optionData[0];
864             for(uint8_t c = i; c < *numOptions-1; c++)
865             {
866                 options[i] = options[i+1];
867             }
868             (*numOptions)--;
869             return OC_STACK_OK;
870         }
871     }
872     return OC_STACK_OK;
873 }
874
875 OCStackResult InitializeObseverList()
876 {
877     OIC_LOG(DEBUG, TAG, "InitializeObseverList IN");
878
879     if (NULL == g_serverObsListMutex)
880     {
881         g_serverObsListMutex = oc_mutex_new();
882     }
883
884     OIC_LOG(DEBUG, TAG, "InitializeObseverList OUT");
885     return OC_STACK_OK;
886 }
887
888 void TerminateObserverList()
889 {
890     OIC_LOG(DEBUG, TAG, "TerminateObserverList IN");
891
892     DeleteObserverList();
893
894     if (NULL != g_serverObsListMutex)
895     {
896         oc_mutex_free(g_serverObsListMutex);
897         g_serverObsListMutex = NULL;
898     }
899
900     OIC_LOG(DEBUG, TAG, "TerminateObserverList OUT");
901 }
902
903 void FreeObserver (ResourceObserver* obsNode)
904 {
905     if (NULL != obsNode)
906     {
907         OICFree(obsNode->resUri);
908         OICFree(obsNode->query);
909         OICFree(obsNode->token);
910         OICFree(obsNode);
911     }
912 }