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