1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
23 #include "ocstackconfig.h"
24 #include "ocstackinternal.h"
25 #include "ocobserve.h"
26 #include "ocresourcehandler.h"
32 #include "ocserverrequest.h"
35 #define MOD_NAME PCF("ocobserve")
37 #define TAG PCF("OCStackObserve")
39 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
41 static struct ResourceObserver * serverObsList = NULL;
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)
50 OCQualityOfService decidedQoS = appQoS;
51 if(appQoS == OC_NA_QOS)
53 decidedQoS = resourceObserver->qos;
56 if(appQoS != OC_HIGH_QOS)
58 OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
59 resourceObserver->lowQosCount);
61 if((resourceObserver->forceHighQos \
62 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
63 && method != OC_REST_PRESENCE)
65 if(resourceObserver->forceHighQos \
66 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT)
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;
77 (resourceObserver->lowQosCount)++;
84 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
85 OCResourceType *resourceType, OCQualityOfService qos)
87 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
88 OCQualityOfService qos)
91 OC_LOG(INFO, TAG, PCF("Entering SendObserverNotification"));
92 OCStackResult result = OC_STACK_ERROR;
93 ResourceObserver * resourceObserver = serverObsList;
95 OCServerRequest * request = NULL;
96 OCEntityHandlerRequest ehRequest = {0};
97 OCEntityHandlerResult ehResult = OC_EH_ERROR;
99 // Find clients that are observing this resource
100 while (resourceObserver)
102 if (resourceObserver->resource == resPtr)
106 if(method != OC_REST_PRESENCE)
109 qos = DetermineObserverQoS(method, resourceObserver, qos);
112 result = AddServerCARequest(&request, 0, 0, 0, 1, OC_REST_GET,
113 0, resPtr->sequenceNum, qos, resourceObserver->query,
115 &resourceObserver->token, resourceObserver->addr,
116 resourceObserver->resUri, 0,
117 &(resourceObserver->addressInfo), resourceObserver->connectivityType,
118 resourceObserver->CAToken);
120 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
121 0, resPtr->sequenceNum, qos, resourceObserver->query,
123 &resourceObserver->token, resourceObserver->addr,
124 resourceObserver->resUri, 0);
127 request->observeResult = OC_STACK_OK;
128 if(request && result == OC_STACK_OK)
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)
136 ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest);
137 if(ehResult == OC_EH_ERROR)
139 FindAndDeleteServerRequest(request);
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"));
152 result = AddServerCARequest(&request, 0, 0, 0, 1, OC_REST_GET,
153 0, resPtr->sequenceNum, qos, resourceObserver->query,
155 &resourceObserver->token, resourceObserver->addr,
156 resourceObserver->resUri, 0,
157 &(resourceObserver->addressInfo), resourceObserver->connectivityType,
158 resourceObserver->CAToken);
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);
166 if(result == OC_STACK_OK)
168 // we create the payload here
169 if(resourceType && resourceType->resourcetypename)
171 snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u:%s",
172 resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
176 snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u",
177 resPtr->sequenceNum, maxAge);
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);
191 resourceObserver = resourceObserver->next;
195 OC_LOG(INFO, TAG, PCF("Resource has no observers"));
196 result = OC_STACK_NO_OBSERVERS;
201 OCStackResult SendListObserverNotification (OCResource * resource,
202 OCObservationId *obsIdList, uint8_t numberOfIds,
203 unsigned char *notificationJSONPayload, uint32_t maxAge,
204 OCQualityOfService qos)
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};
213 OC_LOG(INFO, TAG, PCF("Entering SendListObserverNotification"));
216 OC_LOG_V(INFO, TAG, "Need to notify observation id %d", *obsIdList);
218 observation = GetObserverUsingId (*obsIdList);
221 // Found observation - verify if it matches the resource handle
222 if (observation->resource == resource)
224 qos = DetermineObserverQoS(OC_REST_GET, observation, qos);
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);
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);
241 request->observeResult = OC_STACK_OK;
242 if(request && result == OC_STACK_OK)
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)
249 FindAndDeleteServerRequest(request);
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)
260 OCFree(ehResponse.payload);
261 FindAndDeleteServerRequest(request);
266 FindAndDeleteServerRequest(request);
269 numSentNotification++;
275 if(numSentNotification == numberOfIds)
279 else if(numSentNotification == 0)
281 return OC_STACK_NO_OBSERVERS;
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?
291 OCStackResult GenerateObserverId (OCObservationId *observationId)
293 ResourceObserver *resObs = NULL;
295 OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
296 VERIFY_NON_NULL (observationId);
300 *observationId = OCGetRandomByte();
301 // Check if observation Id already exists
302 resObs = GetObserverUsingId (*observationId);
303 } while (NULL != resObs);
305 OC_LOG_V(INFO, TAG, "Observation ID is %u", *observationId);
309 return OC_STACK_ERROR;
313 OCStackResult AddCAObserver (const char *resUri,
315 OCObservationId obsId,
318 OCResource *resHandle,
319 OCQualityOfService qos,
320 CAAddress_t *addressInfo,
321 CAConnectivityType_t connectivityType,
324 ResourceObserver *obsNode = NULL;
326 obsNode = (ResourceObserver *) OCCalloc(1, sizeof(ResourceObserver));
329 obsNode->observeId = obsId;
331 obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
332 VERIFY_NON_NULL (obsNode->resUri);
333 memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
338 obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
339 VERIFY_NON_NULL (obsNode->query);
340 memcpy (obsNode->query, query, strlen(query)+1);
345 obsNode->token.tokenLength = token->tokenLength;
346 memcpy (obsNode->token.token, token->token, token->tokenLength);
351 obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
352 VERIFY_NON_NULL (obsNode->addr);
353 memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
356 obsNode->addressInfo = *addressInfo;
357 obsNode->connectivityType = connectivityType;
360 strncpy(obsNode->CAToken, CAtoken, CA_MAX_TOKEN_LEN);
363 obsNode->resource = resHandle;
365 LL_APPEND (serverObsList, obsNode);
372 OCFree(obsNode->resUri);
373 OCFree(obsNode->query);
374 OCFree(obsNode->addr);
377 return OC_STACK_NO_MEMORY;
381 OCStackResult AddObserver (const char *resUri,
383 OCObservationId obsId,
386 OCResource *resHandle,
387 OCQualityOfService qos)
389 ResourceObserver *obsNode = NULL;
391 obsNode = (ResourceObserver *) OCCalloc(1, sizeof(ResourceObserver));
394 obsNode->observeId = obsId;
396 obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
397 VERIFY_NON_NULL (obsNode->resUri);
398 memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
403 obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
404 VERIFY_NON_NULL (obsNode->query);
405 memcpy (obsNode->query, query, strlen(query)+1);
408 obsNode->token.tokenLength = token->tokenLength;
409 memcpy (obsNode->token.token, token->token, token->tokenLength);
411 obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
412 VERIFY_NON_NULL (obsNode->addr);
413 memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
415 obsNode->resource = resHandle;
417 LL_APPEND (serverObsList, obsNode);
424 OCFree(obsNode->resUri);
425 OCFree(obsNode->query);
426 OCFree(obsNode->addr);
429 return OC_STACK_NO_MEMORY;
432 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
434 ResourceObserver *out = NULL;
438 LL_FOREACH (serverObsList, out)
440 if (out->observeId == observeId)
446 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
451 ResourceObserver* GetObserverUsingToken (const char * token)
453 ResourceObserver* GetObserverUsingToken (const OCCoAPToken * token)
456 ResourceObserver *out = NULL;
460 LL_FOREACH (serverObsList, out)
463 if((strlen(token) == strlen(out->CAToken)) &&
464 (memcmp(out->CAToken, token, strlen(token)) == 0))
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))
480 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
485 OCStackResult DeleteObserverUsingToken (char * token)
487 OCStackResult DeleteObserverUsingToken (OCCoAPToken * token)
490 ResourceObserver *obsNode = NULL;
492 obsNode = GetObserverUsingToken (token);
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);
503 // it is ok if we did not find the observer...
507 void DeleteObserverList()
509 ResourceObserver *out = NULL;
510 ResourceObserver *tmp = NULL;
511 LL_FOREACH_SAFE (serverObsList, out, tmp)
514 DeleteObserverUsingToken (out->CAToken);
516 DeleteObserverUsingToken (&(out->token));
519 serverObsList = NULL;
524 CreateObserveHeaderOption (CAHeaderOption_t **caHdrOpt,
525 OCHeaderOption *ocHdrOpt,
529 CAHeaderOption_t *tmpHdrOpt = NULL;
531 tmpHdrOpt = (CAHeaderOption_t *) OCMalloc ((numOptions+1)*sizeof(CAHeaderOption_t));
532 if (NULL == tmpHdrOpt)
534 return OC_STACK_NO_MEMORY;
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++)
544 memcpy (&(tmpHdrOpt[i+1]), &(ocHdrOpt[i]), sizeof(CAHeaderOption_t));
547 *caHdrOpt = tmpHdrOpt;
552 GetObserveHeaderOption (uint32_t * observationOption,
553 CAHeaderOption_t *options,
554 uint8_t * numOptions)
556 *observationOption = OC_OBSERVE_NO_OPTION;
559 for(i = 0; i < *numOptions; i++)
561 if(options[i].protocolID == CA_COAP_ID &&
562 options[i].optionID == COAP_OPTION_OBSERVE)
564 *observationOption = options[i].optionData[0];
565 for(c = i; c < *numOptions-1; c++)
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);