1ab99158db8161548e48f3db87aff77465beddef
[platform/upstream/iotivity.git] / csdk / stack / src / ocobserve.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation 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 "ocstack.h"
22 #include "ocstackinternal.h"
23 #include "ocobserve.h"
24 #include "ocresource.h"
25 #include "occoap.h"
26 #include "utlist.h"
27 #include "debug.h"
28 #include <string.h>
29
30 // Module Name
31 #define MOD_NAME PCF("ocobserve")
32
33 #define TAG  PCF("OCStackObserve")
34
35 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
36
37 static struct ResourceObserver * serverObsList = NULL;
38
39 OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
40 {
41     OCStackResult result = OC_STACK_ERROR;
42     ResourceObserver * observer = NULL;
43
44     switch(status)
45     {
46     case OC_OBSERVER_NOT_INTERESTED:
47         OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
48         //observer is dead, or it is not observing anymore
49         result = DeleteObserver (token);
50         if(result == OC_STACK_OK)
51         {
52             OC_LOG(DEBUG, TAG, PCF("removing an observer"));
53             result = OC_STACK_OBSERVER_REMOVED;
54         }
55         break;
56     case OC_OBSERVER_STILL_INTERESTED:
57         //observer is still interested
58         OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
59                 notifications, reset the failedCount"));
60         observer = GetObserver(token);
61         if(observer)
62         {
63             observer->forceCON = 0;
64             observer->failedCommCount = 0;
65             result = OC_STACK_OK;
66         }
67         else
68         {
69             result = OC_STACK_OBSERVER_NOT_FOUND;
70         }
71         break;
72     case OC_OBSERVER_FAILED_COMM:
73         //observer is not reachable
74         OC_LOG(DEBUG, TAG, PCF("observer is not reachable"));
75         observer = GetObserver(token);
76         if(observer)
77         {
78             if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
79             {
80                 result = DeleteObserver (token);
81                 OC_LOG(DEBUG, TAG, PCF("removing an observer"));
82                 result = OC_STACK_OBSERVER_REMOVED;
83             }
84             else
85             {
86                 observer->failedCommCount++;
87                 result = OC_STACK_OK;
88             }
89             observer->forceCON = 1;
90             OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
91         }
92         break;
93     default:
94         break;
95     }
96
97     return result;
98 }
99
100 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
101 {
102     OCStackResult result = OC_STACK_ERROR;
103     OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
104     OCObserveReq *obs = request->observe;
105
106     OC_LOG(INFO, TAG, PCF("Entering ProcessObserveRequest"));
107
108     // Register new observation
109     request->entityHandlerRequest->resource = (OCResourceHandle)resource;
110     result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
111
112     if (obs->option == OC_RESOURCE_OBSERVE_REGISTER)
113     {
114         // Add subscriber to the server observation list
115         // TODO: we need to check if the obsrever is already there using its OCDevAdd....
116         result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query),
117                 obs->token, obs->subAddr, resource, request->qos);
118         if(result == OC_STACK_OK)
119         {
120             result = OC_STACK_OBSERVER_ADDED;
121         }
122         OC_LOG(DEBUG, TAG, PCF("adding an observer"));
123     }
124     else if (obs->option == OC_RESOURCE_OBSERVE_DEREGISTER)
125     {
126         // Deregister observation
127         result = DeleteObserver (obs->token);
128         if(result == OC_STACK_OK)
129         {
130             OC_LOG(DEBUG, TAG, PCF("removing an observer"));
131             result = OC_STACK_OBSERVER_REMOVED;
132         }
133     }
134     else
135     {
136         // Invalid option
137         OC_LOG(ERROR, TAG, PCF("Invalid CoAP observe option"));
138         result = OC_STACK_INVALID_OBSERVE_PARAM;
139     }
140     return result;
141 }
142
143 OCStackResult SendObserverNotification (OCResource *resPtr)
144 {
145     uint8_t numObs = 0;
146     OCStackResult result = OC_STACK_ERROR;
147     ResourceObserver *resourceObserver = serverObsList;
148     OCEntityHandlerRequest * entityHandlerReq = NULL;
149     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
150     // TODO: we should allow the server application to define qos for each notification
151     OCQualityOfService qos = OC_NON_CONFIRMABLE;
152
153     // Increment the sequence number
154     resPtr->sequenceNum += 1;
155     if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
156     {
157         resPtr->sequenceNum = 1;
158     }
159
160     // Find clients that are observing this resource
161     while (resourceObserver)
162     {
163         if (resourceObserver->resource == resPtr)
164         {
165             // Invoke the entity handler for the client to process
166             // the query according to the new representation
167             numObs++;
168             FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
169                     NULL, resourceObserver->query);
170             entityHandlerReq->resource = (OCResourceHandle)resPtr;
171
172             // Even if entity handler for a resource is not successful
173             // we continue calling entity handler for other resources
174             result = resPtr->entityHandler (OC_REQUEST_FLAG, entityHandlerReq);
175             if (OC_STACK_OK == result)
176             {
177                 OC_LOG_V(INFO, TAG, "OCStack payload: %s",
178                         entityHandlerReq->resJSONPayload);
179
180                 // send notifications based on the qos of the request
181                 qos = resourceObserver->qos;
182                 if(qos == OC_NON_CONFIRMABLE)
183                 {
184                     OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
185                             resourceObserver->NONCount);
186                     if(resourceObserver->forceCON ||
187                             resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
188                     {
189                         resourceObserver->NONCount = 0;
190                         // at some point we have to to send CON to check on the
191                         // availability of observer
192                         OC_LOG(INFO, TAG, PCF("This time we are sending the \
193                                 notification as CON"));
194                         qos = OC_CONFIRMABLE;
195                     }
196                     else
197                     {
198                         resourceObserver->NONCount++;
199                     }
200                 }
201
202                 OCSendCoAPNotification(resourceObserver->addr, result, qos,
203                         resourceObserver->token,
204                         (unsigned char *)entityHandlerReq->resJSONPayload,
205                         resPtr->sequenceNum);
206             }
207         }
208         resourceObserver = resourceObserver->next;
209     }
210     if (numObs == 0)
211     {
212         OC_LOG(INFO, TAG, PCF("Resource has no observers"));
213         return OC_STACK_NO_OBSERVERS;
214     }
215     return OC_STACK_OK;
216 }
217
218 OCStackResult AddObserver (const char   *resUri,
219                            const char   *query,
220                            OCCoAPToken * token,
221                            OCDevAddr    *addr,
222                            OCResource   *resHandle,
223                            OCQualityOfService qos)
224 {
225     ResourceObserver *obsNode = NULL;
226     OCCoAPToken *tokPtr = NULL;
227
228     obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
229     if (obsNode)
230     {
231         obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1));
232         VERIFY_NON_NULL (obsNode->resUri);
233         obsNode->qos = qos;
234         memcpy (obsNode->resUri, resUri, sizeof(strlen(resUri)+1));
235         obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
236         VERIFY_NON_NULL (obsNode->query);
237         memcpy (obsNode->query, query, sizeof(strlen(query)+1));
238         obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
239         VERIFY_NON_NULL (obsNode->token);
240         tokPtr = obsNode->token;
241         tokPtr->tokenLength = token->tokenLength;
242         memcpy (tokPtr->token, token->token, tokPtr->tokenLength);
243         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
244         VERIFY_NON_NULL (obsNode->addr);
245         memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
246         obsNode->resource = resHandle;
247         obsNode->failedCommCount = 0;
248         obsNode->NONCount = 0;
249         obsNode->forceCON = 0;
250
251         LL_APPEND (serverObsList, obsNode);
252         return OC_STACK_OK;
253     }
254
255 exit:
256     OCFree(obsNode->resUri);
257     OCFree(obsNode->query);
258     OCFree(obsNode->token);
259     OCFree(obsNode->addr);
260     OCFree(obsNode);
261     return OC_STACK_NO_MEMORY;
262 }
263
264 ResourceObserver* GetObserver (const OCCoAPToken * token)
265 {
266     ResourceObserver *out = NULL;
267
268     if(token) 
269     {
270         LL_FOREACH (serverObsList, out) 
271         {
272             if((out->token->tokenLength == token->tokenLength) &&
273                (memcmp(out->token->token, token->token, token->tokenLength) == 0))
274             {
275                 return out;
276             }
277         }
278     }
279     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
280     return NULL;
281 }
282
283 OCStackResult DeleteObserver (OCCoAPToken * token)
284 {
285     ResourceObserver *obsNode = NULL;
286
287     obsNode = GetObserver (token);
288     if (obsNode)
289     {
290         LL_DELETE (serverObsList, obsNode);
291         OCFree(obsNode->resUri);
292         OCFree(obsNode->query);
293         OCFree(obsNode->token);
294         OCFree(obsNode->addr);
295         OCFree(obsNode);
296     }
297     // it is ok if we did not find the observer...
298     return OC_STACK_OK;
299 }
300
301 void DeleteObserverList()
302 {
303     ResourceObserver *out = NULL;
304     ResourceObserver *tmp = NULL;
305     LL_FOREACH_SAFE (serverObsList, out, tmp) 
306     {
307         DeleteObserver (out->token);
308     }
309     serverObsList = NULL;
310 }