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