778433aae9e9a8c06c0aee89ebcaf14e0f9c4276
[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
111                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
112                         0, resPtr->sequenceNum, qos, resourceObserver->query,
113                         NULL, NULL,
114                         &resourceObserver->token, resourceObserver->addr,
115                         resourceObserver->resUri, 0,
116                         &(resourceObserver->addressInfo), resourceObserver->connectivityType);
117
118                 request->observeResult = OC_STACK_OK;
119                 if(request && result == OC_STACK_OK)
120                 {
121                     result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
122                                 request->method, (OCResourceHandle) resPtr, request->query,
123                                 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
124                                 request->rcvdVendorSpecificHeaderOptions, OC_OBSERVE_NO_OPTION, 0);
125                     if(result == OC_STACK_OK)
126                     {
127                         ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest);
128                         if(ehResult == OC_EH_ERROR)
129                         {
130                             FindAndDeleteServerRequest(request);
131                         }
132                     }
133                 }
134             #ifdef WITH_PRESENCE
135             }
136             else
137             {
138                 OCEntityHandlerResponse ehResponse = {0};
139                 unsigned char presenceResBuf[MAX_RESPONSE_LENGTH] = {0};
140                 //This is effectively the implementation for the presence entity handler.
141                 OC_LOG(DEBUG, TAG, PCF("This notification is for Presence"));
142                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
143                         0, resPtr->sequenceNum, qos, resourceObserver->query,
144                         NULL, NULL,
145                         &resourceObserver->token, resourceObserver->addr,
146                         resourceObserver->resUri, 0,
147                         &(resourceObserver->addressInfo), resourceObserver->connectivityType);
148
149                 if(result == OC_STACK_OK)
150                 {
151                     // we create the payload here
152                     if(resourceType && resourceType->resourcetypename)
153                     {
154                         snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u:%s",
155                                 resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
156                     }
157                     else
158                     {
159                         snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u",
160                                 resPtr->sequenceNum, maxAge);
161                     }
162                     ehResponse.ehResult = OC_EH_OK;
163                     ehResponse.payload = presenceResBuf;
164                     ehResponse.payloadSize = strlen((const char *)presenceResBuf) + 1;
165                     ehResponse.persistentBufferFlag = 0;
166                     ehResponse.requestHandle = (OCRequestHandle) request;
167                     ehResponse.resourceHandle = (OCResourceHandle) resPtr;
168                     strcpy((char *)ehResponse.resourceUri, (const char *)resourceObserver->resUri);
169                     result = OCDoResponse(&ehResponse);
170                 }
171             }
172             #endif
173         }
174         resourceObserver = resourceObserver->next;
175     }
176     if (numObs == 0)
177     {
178         OC_LOG(INFO, TAG, PCF("Resource has no observers"));
179         result = OC_STACK_NO_OBSERVERS;
180     }
181     return result;
182 }
183
184 OCStackResult SendListObserverNotification (OCResource * resource,
185         OCObservationId  *obsIdList, uint8_t numberOfIds,
186         unsigned char *notificationJSONPayload, uint32_t maxAge,
187         OCQualityOfService qos)
188 {
189     uint8_t numIds = numberOfIds;
190     ResourceObserver *observation = NULL;
191     uint8_t numSentNotification = 0;
192     OCServerRequest * request = NULL;
193     OCStackResult result = OC_STACK_ERROR;
194     OCEntityHandlerResponse ehResponse = {0};
195
196     OC_LOG(INFO, TAG, PCF("Entering SendListObserverNotification"));
197     while(numIds)
198     {
199         OC_LOG_V(INFO, TAG, "Need to notify observation id %d", *obsIdList);
200         observation = NULL;
201         observation = GetObserverUsingId (*obsIdList);
202         if(observation)
203         {
204             // Found observation - verify if it matches the resource handle
205             if (observation->resource == resource)
206             {
207                 qos = DetermineObserverQoS(OC_REST_GET, observation, qos);
208
209
210                 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
211                         0, resource->sequenceNum, qos, observation->query,
212                         NULL, NULL, &observation->token,
213                         observation->addr, observation->resUri, 0,
214                         &(observation->addressInfo), observation->connectivityType);
215
216                 request->observeResult = OC_STACK_OK;
217                 if(request && result == OC_STACK_OK)
218                 {
219                     memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
220                     ehResponse.ehResult = OC_EH_OK;
221                     ehResponse.payload = (unsigned char *) OCMalloc(MAX_RESPONSE_LENGTH);
222                     if(!ehResponse.payload)
223                     {
224                         FindAndDeleteServerRequest(request);
225                         continue;
226                     }
227                     strcpy((char *)ehResponse.payload, (const char *)notificationJSONPayload);
228                     ehResponse.payloadSize = strlen((const char *)ehResponse.payload) + 1;
229                     ehResponse.persistentBufferFlag = 0;
230                     ehResponse.requestHandle = (OCRequestHandle) request;
231                     ehResponse.resourceHandle = (OCResourceHandle) resource;
232                     result = OCDoResponse(&ehResponse);
233                     if(result == OC_STACK_OK)
234                     {
235                         OCFree(ehResponse.payload);
236                         FindAndDeleteServerRequest(request);
237                     }
238                 }
239                 else
240                 {
241                     FindAndDeleteServerRequest(request);
242                 }
243
244                 numSentNotification++;
245             }
246         }
247         obsIdList++;
248         numIds--;
249     }
250     if(numSentNotification == numberOfIds)
251     {
252         return OC_STACK_OK;
253     }
254     else if(numSentNotification == 0)
255     {
256         return OC_STACK_NO_OBSERVERS;
257     }
258     else
259     {
260         //TODO: we need to signal that not every one in the
261         // list got an update, should we also indicate who did not receive on?
262         return OC_STACK_OK;
263     }
264 }
265
266 OCStackResult GenerateObserverId (OCObservationId *observationId)
267 {
268     ResourceObserver *resObs = NULL;
269
270     OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
271     VERIFY_NON_NULL (observationId);
272
273     do
274     {
275         *observationId = OCGetRandomByte();
276         // Check if observation Id already exists
277         resObs = GetObserverUsingId (*observationId);
278     } while (NULL != resObs);
279
280     OC_LOG_V(INFO, TAG, "Observation ID is %u", *observationId);
281
282     return OC_STACK_OK;
283 exit:
284     return OC_STACK_ERROR;
285 }
286
287 OCStackResult AddObserver (const char         *resUri,
288                            const char         *query,
289                            OCObservationId    obsId,
290                            CAToken_t          *token,
291                            OCDevAddr          *addr,
292                            OCResource         *resHandle,
293                            OCQualityOfService qos,
294                            CAAddress_t          *addressInfo,
295                            CAConnectivityType_t connectivityType)
296 {
297     ResourceObserver *obsNode = NULL;
298
299     obsNode = (ResourceObserver *) OCCalloc(1, sizeof(ResourceObserver));
300     if (obsNode)
301     {
302         obsNode->observeId = obsId;
303
304         obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
305         VERIFY_NON_NULL (obsNode->resUri);
306         memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
307
308         obsNode->qos = qos;
309         if(query)
310         {
311             obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
312             VERIFY_NON_NULL (obsNode->query);
313             memcpy (obsNode->query, query, strlen(query)+1);
314         }
315
316         obsNode->token = (CAToken_t)OCMalloc(CA_MAX_TOKEN_LEN+1);
317         VERIFY_NON_NULL (obsNode->token);
318         memset(obsNode->token, 0, CA_MAX_TOKEN_LEN + 1);
319         memcpy(obsNode->token, *token, CA_MAX_TOKEN_LEN);
320
321         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
322         VERIFY_NON_NULL (obsNode->addr);
323         memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
324         obsNode->addressInfo = *addressInfo;
325         obsNode->connectivityType = connectivityType;
326         obsNode->resource = resHandle;
327         LL_APPEND (serverObsList, obsNode);
328         return OC_STACK_OK;
329     }
330
331 exit:
332     if (obsNode)
333     {
334         OCFree(obsNode->resUri);
335         OCFree(obsNode->query);
336         OCFree(obsNode->addr);
337         OCFree(obsNode);
338     }
339     return OC_STACK_NO_MEMORY;
340 }
341
342 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
343 {
344     ResourceObserver *out = NULL;
345
346     if (observeId)
347     {
348         LL_FOREACH (serverObsList, out)
349         {
350             if (out->observeId == observeId)
351             {
352                 return out;
353             }
354         }
355     }
356     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
357     return NULL;
358 }
359
360 ResourceObserver* GetObserverUsingToken (const CAToken_t * token)
361 {
362     ResourceObserver *out = NULL;
363
364     if(token)
365     {
366         LL_FOREACH (serverObsList, out)
367         {
368             OC_LOG(INFO, TAG,PCF("comparing tokens"));
369             OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, CA_MAX_TOKEN_LEN);
370             OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, CA_MAX_TOKEN_LEN);
371             if((memcmp(out->token, *token, CA_MAX_TOKEN_LEN) == 0))
372             {
373                 return out;
374             }
375         }
376     }
377     OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
378     return NULL;
379 }
380
381 OCStackResult DeleteObserverUsingToken (CAToken_t * token)
382 {
383     ResourceObserver *obsNode = NULL;
384
385     obsNode = GetObserverUsingToken (token);
386     if (obsNode)
387     {
388         OC_LOG_V(INFO, TAG, PCF("deleting tokens"));
389         OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)obsNode->token, CA_MAX_TOKEN_LEN);
390         LL_DELETE (serverObsList, obsNode);
391         OCFree(obsNode->resUri);
392         OCFree(obsNode->query);
393         OCFree(obsNode->addr);
394         OCFree(obsNode);
395     }
396     // it is ok if we did not find the observer...
397     return OC_STACK_OK;
398 }
399
400 void DeleteObserverList()
401 {
402     ResourceObserver *out = NULL;
403     ResourceObserver *tmp = NULL;
404     LL_FOREACH_SAFE (serverObsList, out, tmp)
405     {
406         DeleteObserverUsingToken (&(out->token));
407     }
408     serverObsList = NULL;
409 }
410
411 OCStackResult
412 CreateObserveHeaderOption (CAHeaderOption_t **caHdrOpt,
413                            OCHeaderOption *ocHdrOpt,
414                            uint8_t numOptions,
415                            uint8_t observeFlag)
416 {
417     CAHeaderOption_t *tmpHdrOpt = NULL;
418
419     tmpHdrOpt = (CAHeaderOption_t *) OCMalloc ((numOptions+1)*sizeof(CAHeaderOption_t));
420     if (NULL == tmpHdrOpt)
421     {
422         return OC_STACK_NO_MEMORY;
423     }
424     tmpHdrOpt[0].protocolID = CA_COAP_ID;
425     // TODO-CA: COAP_OPTION_OBSERVE is defined in CoAP header files which will be abstracted
426     // from resource model. We have to define a new macro for this in the stack layer.
427     tmpHdrOpt[0].optionID = COAP_OPTION_OBSERVE;
428     tmpHdrOpt[0].optionLength = sizeof(uint32_t);
429     tmpHdrOpt[0].optionData[0] = observeFlag;
430     for (uint8_t i = 0; i < numOptions; i++)
431     {
432         memcpy (&(tmpHdrOpt[i+1]), &(ocHdrOpt[i]), sizeof(CAHeaderOption_t));
433     }
434
435     *caHdrOpt = tmpHdrOpt;
436     return OC_STACK_OK;
437 }
438
439 OCStackResult
440 GetObserveHeaderOption (uint32_t * observationOption,
441                         CAHeaderOption_t *options,
442                         uint8_t * numOptions)
443 {
444     *observationOption = OC_OBSERVE_NO_OPTION;
445     uint8_t i = 0;
446     uint8_t c = 0;
447     for(i = 0; i < *numOptions; i++)
448     {
449         if(options[i].protocolID == CA_COAP_ID &&
450                 options[i].optionID == COAP_OPTION_OBSERVE)
451         {
452             *observationOption = options[i].optionData[0];
453             for(c = i; c < *numOptions-1; c++)
454             {
455                 options[i].protocolID = options[i+1].protocolID;
456                 options[i].optionID = options[i+1].optionID;
457                 options[i].optionLength = options[i+1].optionLength;
458                 memcpy(options[i].optionData, options[i+1].optionData, options[i+1].optionLength);
459             }
460             (*numOptions)--;
461             return OC_STACK_OK;
462         }
463     }
464     return OC_STACK_OK;
465 }