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 "ocresource.h"
34 #define MOD_NAME PCF("ocobserve")
36 #define TAG PCF("OCStackObserve")
38 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
40 static struct ResourceObserver * serverObsList = NULL;
41 extern uint32_t SERVER_DISCOVERABLE;
43 OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
45 OCStackResult result = OC_STACK_ERROR;
46 ResourceObserver * observer = NULL;
47 OCEntityHandlerRequest ehRequest;
48 OCObservationInfo observationInfo;
49 unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
53 case OC_OBSERVER_NOT_INTERESTED:
54 OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
55 observer = GetObserverUsingToken (token);
58 FormOCEntityHandlerRequest(&ehRequest, OC_REST_CANCEL_OBSERVE, bufRes,
60 ehRequest.obsInfo = &observationInfo;
61 ehRequest.obsInfo->action = OC_OBSERVE_DEREGISTER;
62 ehRequest.obsInfo->obsId = observer->observeId;
63 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
65 //observer is dead, or it is not observing anymore
66 result = DeleteObserverUsingToken (token);
67 if(result != OC_STACK_OK)
69 result = OC_STACK_OBSERVER_NOT_REMOVED;
73 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
76 case OC_OBSERVER_STILL_INTERESTED:
77 //observer is still interested
78 OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
79 notifications, reset the failedCount"));
80 observer = GetObserverUsingToken(token);
83 observer->forceHighQos = 0;
84 observer->failedCommCount = 0;
89 result = OC_STACK_OBSERVER_NOT_FOUND;
92 case OC_OBSERVER_FAILED_COMM:
93 //observer is not reachable
94 OC_LOG(DEBUG, TAG, PCF("observer is not reachable"));
95 observer = GetObserverUsingToken(token);
98 if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
100 FormOCEntityHandlerRequest(&ehRequest, OC_REST_CANCEL_OBSERVE, bufRes,
102 ehRequest.obsInfo = &observationInfo;
103 ehRequest.obsInfo->action = OC_OBSERVE_DEREGISTER;
104 ehRequest.obsInfo->obsId = observer->observeId;
105 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
107 result = DeleteObserverUsingToken (token);
108 if(result != OC_STACK_OK)
110 result = OC_STACK_OBSERVER_NOT_REMOVED;
114 OC_LOG(DEBUG, TAG, PCF("removing an observer"));
119 observer->failedCommCount++;
120 result = OC_STACK_OBSERVER_NOT_REMOVED;
122 observer->forceHighQos = 1;
123 OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
133 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
135 OCStackResult stackRet = OC_STACK_ERROR;
136 OCEntityHandlerResult ehRet = OC_EH_ERROR;
137 OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
138 OCObserveReq *obs = request->observe;
139 OCObservationInfo observationInfo;
140 OCObservationId obsId;
141 ResourceObserver *resObs = NULL;
143 OC_LOG(INFO, TAG, PCF("Entering ProcessObserveRequest"));
145 request->entityHandlerRequest->resource = (OCResourceHandle)resource;
146 request->entityHandlerRequest->obsInfo = &observationInfo;
148 if (obs->option == OC_RESOURCE_OBSERVE_REGISTER)
150 // Request to register new observation
151 observationInfo.action = OC_OBSERVE_REGISTER;
152 // Generate observation Id for the request
155 if (OC_STACK_OK != GenerateObserverId (&obsId))
156 return OC_STACK_ERROR;
158 // Check if observation Id already exists
159 resObs = GetObserverUsingId (obsId);
162 OC_LOG_V(INFO, TAG, "Observation ID is %d", obsId);
167 observationInfo.obsId = obsId;
168 // Register the observation request with entity handler
169 ehRet = resource->entityHandler ((OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG),
170 request->entityHandlerRequest);
171 if (ehRet == OC_EH_OK)
173 // Add subscriber to the server observation list
174 stackRet = AddObserver ((const char*)(request->resourceUrl),
175 (const char *)(ehReq->query),
176 obsId, obs->token, obs->subAddr,
177 resource, request->qos);
178 if(stackRet != OC_STACK_OK)
180 obs->result = OC_STACK_OBSERVER_NOT_ADDED;
181 stackRet = OC_STACK_OBSERVER_NOT_ADDED;
182 // If the observation was not added in the stack notify the entity handler
183 observationInfo.action = OC_OBSERVE_DEREGISTER;
184 // If the entity handler is unable to deregister, stack cannot do anything,
185 // hence the return value from entity handler is not being checked
186 resource->entityHandler (OC_OBSERVE_FLAG, request->entityHandlerRequest);
190 OC_LOG(DEBUG, TAG, PCF("Added observer successfully"));
195 stackRet = OC_STACK_OBSERVER_NOT_ADDED;
198 else if (obs->option == OC_RESOURCE_OBSERVE_DEREGISTER)
200 // Request to deregister observation
201 observationInfo.action = OC_OBSERVE_DEREGISTER;
203 // Get observation Id using token
204 resObs = GetObserverUsingToken (obs->token);
207 // Stack does not contain this observation request
208 // Either token is incorrect or observation list is corrupted
209 return OC_STACK_ERROR;
211 observationInfo.action = OC_OBSERVE_DEREGISTER;
212 observationInfo.obsId = resObs->observeId;
213 // Deregister the observation with entity handler. Ignoring return value
214 // from entity handler and deleting the observation from stack
215 resource->entityHandler ((OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG),
216 request->entityHandlerRequest);
217 stackRet = DeleteObserverUsingToken (obs->token);
218 if(stackRet != OC_STACK_OK)
220 obs->result = OC_STACK_OBSERVER_NOT_REMOVED;
221 stackRet = OC_STACK_OBSERVER_NOT_REMOVED;
225 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
230 // Invalid observe option
231 OC_LOG(ERROR, TAG, PCF("Invalid CoAP observe option"));
232 obs->result = OC_STACK_INVALID_OBSERVE_PARAM;
237 OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
238 OCResourceType *resourceType, OCQualityOfService qos)
241 OCStackResult stackRet = OC_STACK_ERROR;
242 OCEntityHandlerResult ehRet = OC_EH_ERROR;
243 ResourceObserver *resourceObserver = serverObsList;
244 OCEntityHandlerRequest entityHandlerReq;
245 unsigned char* jsonPayload = NULL;
246 unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
248 // Find clients that are observing this resource
249 while (resourceObserver)
251 if (resourceObserver->resource == resPtr)
255 if(method != OC_REST_PRESENCE)
258 // Invoke the entity handler for the client to process
259 // the query according to the new representation
260 FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
261 NULL, resourceObserver->query, NULL);
262 entityHandlerReq.resource = (OCResourceHandle)resPtr;
264 // Even if entity handler for a resource is not successful
265 // we continue calling entity handler for other resources
266 ehRet = BuildObsJSONResponse((OCResource *) resPtr, &entityHandlerReq);
267 jsonPayload = (unsigned char *)(entityHandlerReq.resJSONPayload);
272 //we know it is the default entity handler
273 OC_LOG(DEBUG, TAG, PCF("This notification is for Presence"));
275 // we create the payload here
278 sprintf((char *)bufRes, "%u:%u:%s",
279 resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
283 sprintf((char *)bufRes, "%u:%u", resPtr->sequenceNum, maxAge);
286 jsonPayload = bufRes;
291 if (OC_EH_OK == ehRet)
293 stackRet = OC_STACK_OK;
294 OC_LOG_V(INFO, TAG, "OCStack payload: %s",
297 // send notifications based on the qos of the request
298 // The qos passed as a parameter overrides what the client requested
299 // If we want the client preference taking high priority add:
300 // qos = resourceObserver->qos;
301 if(qos == OC_NA_QOS){
302 qos = resourceObserver->qos;
304 if(qos != OC_HIGH_QOS)
306 OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
307 resourceObserver->lowQosCount);
309 if((resourceObserver->forceHighQos \
310 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
311 && method != OC_REST_PRESENCE)
313 if(resourceObserver->forceCON \
314 || resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
317 resourceObserver->lowQosCount = 0;
318 // at some point we have to to send CON to check on the
319 // availability of observer
320 OC_LOG(INFO, TAG, PCF("This time we are sending the \
321 notification as High qos"));
326 resourceObserver->lowQosCount++;
329 stackRet = OCSendCoAPNotification(resourceObserver->resUri, resourceObserver->addr,
330 qos, &(resourceObserver->token), jsonPayload, resPtr, maxAge);
334 stackRet = OC_STACK_ERROR;
337 resourceObserver = resourceObserver->next;
341 OC_LOG(INFO, TAG, PCF("Resource has no observers"));
342 stackRet = OC_STACK_NO_OBSERVERS;
347 OCStackResult GenerateObserverId (OCObservationId *observationId)
349 OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
351 VERIFY_NON_NULL (observationId);
352 *observationId = OCGetRandomByte();
356 return OC_STACK_ERROR;
359 OCStackResult AddObserver (const char *resUri,
361 OCObservationId obsId,
364 OCResource *resHandle,
365 OCQualityOfService qos)
367 ResourceObserver *obsNode = NULL;
369 obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
372 memset(obsNode, 0, sizeof(ResourceObserver));
373 obsNode->observeId = obsId;
375 obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
376 VERIFY_NON_NULL (obsNode->resUri);
377 memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
382 obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
383 VERIFY_NON_NULL (obsNode->query);
384 memcpy (obsNode->query, query, strlen(query)+1);
387 obsNode->token.tokenLength = token->tokenLength;
388 memcpy (&(obsNode->token.token), token->token, token->tokenLength);
390 obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
391 VERIFY_NON_NULL (obsNode->addr);
392 memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
394 obsNode->resource = resHandle;
396 LL_APPEND (serverObsList, obsNode);
403 OCFree(obsNode->resUri);
404 OCFree(obsNode->query);
405 OCFree(obsNode->addr);
408 return OC_STACK_NO_MEMORY;
411 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
413 ResourceObserver *out = NULL;
417 LL_FOREACH (serverObsList, out)
419 if (out->observeId == observeId)
425 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
429 ResourceObserver* GetObserverUsingToken (const OCCoAPToken * token)
431 ResourceObserver *out = NULL;
435 LL_FOREACH (serverObsList, out)
437 OC_LOG(INFO, TAG,PCF("comparing tokens"));
438 OC_LOG_BUFFER(INFO, TAG, token->token, token->tokenLength);
439 OC_LOG_BUFFER(INFO, TAG, out->token.token, out->token.tokenLength);
440 if((out->token.tokenLength == token->tokenLength) &&
441 (memcmp(out->token.token, token->token, token->tokenLength) == 0))
447 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
451 OCStackResult DeleteObserverUsingToken (OCCoAPToken * token)
453 ResourceObserver *obsNode = NULL;
455 obsNode = GetObserverUsingToken (token);
458 OC_LOG_V(INFO, TAG, PCF("deleting tokens"));
459 OC_LOG_BUFFER(INFO, TAG, obsNode->token.token, obsNode->token.tokenLength);
460 LL_DELETE (serverObsList, obsNode);
461 OCFree(obsNode->resUri);
462 OCFree(obsNode->query);
463 OCFree(obsNode->addr);
466 // it is ok if we did not find the observer...
470 void DeleteObserverList()
472 ResourceObserver *out = NULL;
473 ResourceObserver *tmp = NULL;
474 LL_FOREACH_SAFE (serverObsList, out, tmp)
476 DeleteObserverUsingToken (&(out->token));
478 serverObsList = NULL;