Merge "[SSM] Modify repo init method and fix Resource data reader"
[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 "occoap.h"
28 #include "utlist.h"
29 #include "debug.h"
30 #include "ocrandom.h"
31 #include "ocmalloc.h"
32 #include "ocserverrequest.h"
33
34 // Module Name
35 #define MOD_NAME PCF("ocobserve")
36
37 #define TAG  PCF("OCStackObserve")
38
39 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
40
41 static struct ResourceObserver * serverObsList = NULL;
42
43 // send notifications based on the qos of the request
44 // The qos passed as a parameter overrides what the client requested
45 // If we want the client preference taking high priority make:
46 // qos = resourceObserver->qos;
47 OCQualityOfService DetermineObserverQoS(OCMethod method, ResourceObserver * resourceObserver,
48         OCQualityOfService appQoS)
49 {
50     OCQualityOfService decidedQoS = appQoS;
51     if(appQoS == OC_NA_QOS)
52     {
53         decidedQoS = resourceObserver->qos;
54     }
55
56     if(appQoS != OC_HIGH_QOS)
57     {
58         OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
59                 resourceObserver->lowQosCount);
60         #ifdef WITH_PRESENCE
61         if((resourceObserver->forceHighQos \
62                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
63                 && method != OC_REST_PRESENCE)
64         #else
65         if(resourceObserver->forceHighQos \
66                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT)
67         #endif
68             {
69             resourceObserver->lowQosCount = 0;
70             // at some point we have to to send CON to check on the
71             // availability of observer
72             OC_LOG(INFO, TAG, PCF("This time we are sending the  notification as High qos"));
73             decidedQoS = OC_HIGH_QOS;
74             }
75         else
76         {
77             (resourceObserver->lowQosCount)++;
78         }
79     }
80     return decidedQoS;
81 }
82
83 #ifdef WITH_PRESENCE
84 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
85         OCResourceType *resourceType, OCQualityOfService qos)
86 #else
87 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
88         OCQualityOfService qos)
89 #endif
90 {
91     OC_LOG(INFO, TAG, PCF("Entering SendObserverNotification"));
92     OCStackResult result = OC_STACK_ERROR;
93     ResourceObserver * resourceObserver = serverObsList;
94     uint8_t numObs = 0;
95     OCServerRequest * request = NULL;
96     OCEntityHandlerRequest ehRequest = {0};
97     OCEntityHandlerResult ehResult = OC_EH_ERROR;
98
99     // Find clients that are observing this resource
100     while (resourceObserver)
101     {
102         if (resourceObserver->resource == resPtr)
103         {
104             numObs++;
105             #ifdef WITH_PRESENCE
106             if(method != OC_REST_PRESENCE)
107             {
108             #endif
109                 qos = DetermineObserverQoS(method, resourceObserver, qos);
110                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
111                         0, resPtr->sequenceNum, qos, resourceObserver->query,
112                         NULL, NULL,
113                         &resourceObserver->token, resourceObserver->addr,
114                         resourceObserver->resUri, 0);
115                 request->observeResult = OC_STACK_OK;
116                 if(request && result == OC_STACK_OK)
117                 {
118                     result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
119                                 request->method, (OCResourceHandle) resPtr, request->query,
120                                 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
121                                 request->rcvdVendorSpecificHeaderOptions, OC_OBSERVE_NO_OPTION, 0);
122                     if(result == OC_STACK_OK)
123                     {
124                         ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest);
125                         if(ehResult == OC_EH_ERROR)
126                         {
127                             FindAndDeleteServerRequest(request);
128                         }
129                     }
130                 }
131             #ifdef WITH_PRESENCE
132             }
133             else
134             {
135                 OCEntityHandlerResponse ehResponse = {0};
136                 unsigned char presenceResBuf[MAX_RESPONSE_LENGTH] = {0};
137                 //This is effectively the implementation for the presence entity handler.
138                 OC_LOG(DEBUG, TAG, PCF("This notification is for Presence"));
139                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
140                         0, OC_OBSERVE_NO_OPTION, OC_LOW_QOS,
141                         NULL, NULL, NULL, &resourceObserver->token,
142                         resourceObserver->addr, resourceObserver->resUri, 0);
143                 if(result == OC_STACK_OK)
144                 {
145                     // we create the payload here
146                     if(resourceType && resourceType->resourcetypename)
147                     {
148                         sprintf((char *)presenceResBuf, "%u:%u:%s",
149                                 resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
150                     }
151                     else
152                     {
153                         sprintf((char *)presenceResBuf, "%u:%u", resPtr->sequenceNum, maxAge);
154                     }
155                     memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
156                     ehResponse.ehResult = OC_EH_OK;
157                     ehResponse.payload = presenceResBuf;
158                     ehResponse.payloadSize = strlen((const char *)presenceResBuf) + 1;
159                     ehResponse.persistentBufferFlag = 0;
160                     ehResponse.requestHandle = (OCRequestHandle) request;
161                     ehResponse.resourceHandle = (OCResourceHandle) resPtr;
162                     strcpy((char *)ehResponse.resourceUri, (const char *)resourceObserver->resUri);
163                     result = OCDoResponse(&ehResponse);
164                 }
165             }
166             #endif
167         }
168         resourceObserver = resourceObserver->next;
169     }
170     if (numObs == 0)
171     {
172         OC_LOG(INFO, TAG, PCF("Resource has no observers"));
173         result = OC_STACK_NO_OBSERVERS;
174     }
175     return result;
176 }
177
178 OCStackResult SendListObserverNotification (OCResource * resource,
179         OCObservationId  *obsIdList, uint8_t numberOfIds,
180         unsigned char *notificationJSONPayload, uint32_t maxAge,
181         OCQualityOfService qos)
182 {
183     uint8_t numIds = numberOfIds;
184     ResourceObserver *observation = NULL;
185     uint8_t numSentNotification = 0;
186     OCServerRequest * request = NULL;
187     OCStackResult result = OC_STACK_ERROR;
188     OCEntityHandlerResponse ehResponse;
189     memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
190
191     OC_LOG(INFO, TAG, PCF("Entering SendListObserverNotification"));
192     while(numIds)
193     {
194         OC_LOG_V(INFO, TAG, "Need to notify observation id %d", *obsIdList);
195         observation = NULL;
196         observation = GetObserverUsingId (*obsIdList);
197         if(observation)
198         {
199             // Found observation - verify if it matches the resource handle
200             if (observation->resource == resource)
201             {
202                 qos = DetermineObserverQoS(OC_REST_GET, observation, qos);
203
204                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
205                         0, resource->sequenceNum, qos, observation->query,
206                         NULL, NULL, &observation->token,
207                         observation->addr, observation->resUri, 0);
208                 request->observeResult = OC_STACK_OK;
209                 if(request && result == OC_STACK_OK)
210                 {
211                     memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
212                     ehResponse.ehResult = OC_EH_OK;
213                     ehResponse.payload = (unsigned char *) OCMalloc(MAX_RESPONSE_LENGTH);
214                     if(!ehResponse.payload)
215                     {
216                         FindAndDeleteServerRequest(request);
217                         continue;
218                     }
219                     strcpy((char *)ehResponse.payload, (const char *)notificationJSONPayload);
220                     ehResponse.payloadSize = strlen((const char *)ehResponse.payload) + 1;
221                     ehResponse.persistentBufferFlag = 0;
222                     ehResponse.requestHandle = (OCRequestHandle) request;
223                     ehResponse.resourceHandle = (OCResourceHandle) resource;
224                     result = OCDoResponse(&ehResponse);
225                     if(result == OC_STACK_OK)
226                     {
227                         OCFree(ehResponse.payload);
228                         FindAndDeleteServerRequest(request);
229                     }
230                 }
231                 else
232                 {
233                     FindAndDeleteServerRequest(request);
234                 }
235
236                 numSentNotification++;
237             }
238         }
239         obsIdList++;
240         numIds--;
241     }
242     if(numSentNotification == numberOfIds)
243     {
244         return OC_STACK_OK;
245     }
246     else if(numSentNotification == 0)
247     {
248         return OC_STACK_NO_OBSERVERS;
249     }
250     else
251     {
252         //TODO: we need to signal that not every one in the
253         // list got an update, should we also indicate who did not receive on?
254         return OC_STACK_OK;
255     }
256 }
257
258 OCStackResult GenerateObserverId (OCObservationId *observationId)
259 {
260     ResourceObserver *resObs = NULL;
261
262     OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
263     VERIFY_NON_NULL (observationId);
264
265     do
266     {
267         *observationId = OCGetRandomByte();
268         // Check if observation Id already exists
269         resObs = GetObserverUsingId (*observationId);
270     } while (NULL != resObs);
271
272     OC_LOG_V(INFO, TAG, "Observation ID is %u", *observationId);
273
274     return OC_STACK_OK;
275 exit:
276     return OC_STACK_ERROR;
277 }
278
279 OCStackResult AddObserver (const char         *resUri,
280                            const char         *query,
281                            OCObservationId    obsId,
282                            OCCoAPToken        *token,
283                            OCDevAddr          *addr,
284                            OCResource         *resHandle,
285                            OCQualityOfService qos)
286 {
287     ResourceObserver *obsNode = NULL;
288
289     obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
290     if (obsNode)
291     {
292         memset(obsNode, 0, sizeof(ResourceObserver));
293         obsNode->observeId = obsId;
294
295         obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
296         VERIFY_NON_NULL (obsNode->resUri);
297         memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
298
299         obsNode->qos = qos;
300         if(query)
301         {
302             obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
303             VERIFY_NON_NULL (obsNode->query);
304             memcpy (obsNode->query, query, strlen(query)+1);
305         }
306
307         obsNode->token.tokenLength = token->tokenLength;
308         memcpy (obsNode->token.token, token->token, token->tokenLength);
309
310         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
311         VERIFY_NON_NULL (obsNode->addr);
312         memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
313
314         obsNode->resource = resHandle;
315
316         LL_APPEND (serverObsList, obsNode);
317         return OC_STACK_OK;
318     }
319
320 exit:
321     if (obsNode)
322     {
323         OCFree(obsNode->resUri);
324         OCFree(obsNode->query);
325         OCFree(obsNode->addr);
326         OCFree(obsNode);
327     }
328     return OC_STACK_NO_MEMORY;
329 }
330
331 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
332 {
333     ResourceObserver *out = NULL;
334
335     if (observeId)
336     {
337         LL_FOREACH (serverObsList, out)
338         {
339             if (out->observeId == observeId)
340             {
341                 return out;
342             }
343         }
344     }
345     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
346     return NULL;
347 }
348
349 ResourceObserver* GetObserverUsingToken (const OCCoAPToken * token)
350 {
351     ResourceObserver *out = NULL;
352
353     if(token)
354     {
355         LL_FOREACH (serverObsList, out)
356         {
357             OC_LOG(INFO, TAG,PCF("comparing tokens"));
358             OC_LOG_BUFFER(INFO, TAG, token->token, token->tokenLength);
359             OC_LOG_BUFFER(INFO, TAG, out->token.token, out->token.tokenLength);
360             if((out->token.tokenLength == token->tokenLength) &&
361                (memcmp(out->token.token, token->token, token->tokenLength) == 0))
362             {
363                 return out;
364             }
365         }
366     }
367     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
368     return NULL;
369 }
370
371 OCStackResult DeleteObserverUsingToken (OCCoAPToken * token)
372 {
373     ResourceObserver *obsNode = NULL;
374
375     obsNode = GetObserverUsingToken (token);
376     if (obsNode)
377     {
378         OC_LOG_V(INFO, TAG, PCF("deleting tokens"));
379         OC_LOG_BUFFER(INFO, TAG, obsNode->token.token, obsNode->token.tokenLength);
380         LL_DELETE (serverObsList, obsNode);
381         OCFree(obsNode->resUri);
382         OCFree(obsNode->query);
383         OCFree(obsNode->addr);
384         OCFree(obsNode);
385     }
386     // it is ok if we did not find the observer...
387     return OC_STACK_OK;
388 }
389
390 void DeleteObserverList()
391 {
392     ResourceObserver *out = NULL;
393     ResourceObserver *tmp = NULL;
394     LL_FOREACH_SAFE (serverObsList, out, tmp)
395     {
396         DeleteObserverUsingToken (&(out->token));
397     }
398     serverObsList = NULL;
399 }