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