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);
110 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
111 0, resPtr->sequenceNum, qos, resourceObserver->query,
113 &resourceObserver->token, resourceObserver->addr,
114 resourceObserver->resUri, 0);
115 request->observeResult = OC_STACK_OK;
116 if(request && result == OC_STACK_OK)
118 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
119 request->method, (OCResourceHandle) resPtr, request->query,
120 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
121 request->rcvdVendorSpecificHeaderOptions, OC_OBSERVE_NO_OPTION, 0);
122 if(result == OC_STACK_OK)
124 ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest);
125 if(ehResult == OC_EH_ERROR)
127 FindAndDeleteServerRequest(request);
135 OCEntityHandlerResponse ehResponse = {0};
136 unsigned char presenceResBuf[MAX_RESPONSE_LENGTH] = {0};
137 //This is effectively the implementation for the presence entity handler.
138 OC_LOG(DEBUG, TAG, PCF("This notification is for Presence"));
139 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
140 0, OC_OBSERVE_NO_OPTION, OC_LOW_QOS,
141 NULL, NULL, NULL, &resourceObserver->token,
142 resourceObserver->addr, resourceObserver->resUri, 0);
143 if(result == OC_STACK_OK)
145 // we create the payload here
146 if(resourceType && resourceType->resourcetypename)
148 sprintf((char *)presenceResBuf, "%u:%u:%s",
149 resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
153 sprintf((char *)presenceResBuf, "%u:%u", resPtr->sequenceNum, maxAge);
155 memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
156 ehResponse.ehResult = OC_EH_OK;
157 ehResponse.payload = presenceResBuf;
158 ehResponse.payloadSize = strlen((const char *)presenceResBuf) + 1;
159 ehResponse.persistentBufferFlag = 0;
160 ehResponse.requestHandle = (OCRequestHandle) request;
161 ehResponse.resourceHandle = (OCResourceHandle) resPtr;
162 strcpy((char *)ehResponse.resourceUri, (const char *)resourceObserver->resUri);
163 result = OCDoResponse(&ehResponse);
168 resourceObserver = resourceObserver->next;
172 OC_LOG(INFO, TAG, PCF("Resource has no observers"));
173 result = OC_STACK_NO_OBSERVERS;
178 OCStackResult SendListObserverNotification (OCResource * resource,
179 OCObservationId *obsIdList, uint8_t numberOfIds,
180 unsigned char *notificationJSONPayload, uint32_t maxAge,
181 OCQualityOfService qos)
183 uint8_t numIds = numberOfIds;
184 ResourceObserver *observation = NULL;
185 uint8_t numSentNotification = 0;
186 OCServerRequest * request = NULL;
187 OCStackResult result = OC_STACK_ERROR;
188 OCEntityHandlerResponse ehResponse;
189 memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
191 OC_LOG(INFO, TAG, PCF("Entering SendListObserverNotification"));
194 OC_LOG_V(INFO, TAG, "Need to notify observation id %d", *obsIdList);
196 observation = GetObserverUsingId (*obsIdList);
199 // Found observation - verify if it matches the resource handle
200 if (observation->resource == resource)
202 qos = DetermineObserverQoS(OC_REST_GET, observation, qos);
204 result = AddServerRequest(&request, 0, 0, 0, 1, OC_REST_GET,
205 0, resource->sequenceNum, qos, observation->query,
206 NULL, NULL, &observation->token,
207 observation->addr, observation->resUri, 0);
208 request->observeResult = OC_STACK_OK;
209 if(request && result == OC_STACK_OK)
211 memset(&ehResponse, 0, sizeof(OCEntityHandlerResponse));
212 ehResponse.ehResult = OC_EH_OK;
213 ehResponse.payload = (unsigned char *) OCMalloc(MAX_RESPONSE_LENGTH);
214 if(!ehResponse.payload)
216 FindAndDeleteServerRequest(request);
219 strcpy((char *)ehResponse.payload, (const char *)notificationJSONPayload);
220 ehResponse.payloadSize = strlen((const char *)ehResponse.payload) + 1;
221 ehResponse.persistentBufferFlag = 0;
222 ehResponse.requestHandle = (OCRequestHandle) request;
223 ehResponse.resourceHandle = (OCResourceHandle) resource;
224 result = OCDoResponse(&ehResponse);
225 if(result == OC_STACK_OK)
227 OCFree(ehResponse.payload);
228 FindAndDeleteServerRequest(request);
233 FindAndDeleteServerRequest(request);
236 numSentNotification++;
242 if(numSentNotification == numberOfIds)
246 else if(numSentNotification == 0)
248 return OC_STACK_NO_OBSERVERS;
252 //TODO: we need to signal that not every one in the
253 // list got an update, should we also indicate who did not receive on?
258 OCStackResult GenerateObserverId (OCObservationId *observationId)
260 ResourceObserver *resObs = NULL;
262 OC_LOG(INFO, TAG, PCF("Entering GenerateObserverId"));
263 VERIFY_NON_NULL (observationId);
267 *observationId = OCGetRandomByte();
268 // Check if observation Id already exists
269 resObs = GetObserverUsingId (*observationId);
270 } while (NULL != resObs);
272 OC_LOG_V(INFO, TAG, "Observation ID is %u", *observationId);
276 return OC_STACK_ERROR;
279 OCStackResult AddObserver (const char *resUri,
281 OCObservationId obsId,
284 OCResource *resHandle,
285 OCQualityOfService qos)
287 ResourceObserver *obsNode = NULL;
289 obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
292 memset(obsNode, 0, sizeof(ResourceObserver));
293 obsNode->observeId = obsId;
295 obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
296 VERIFY_NON_NULL (obsNode->resUri);
297 memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
302 obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
303 VERIFY_NON_NULL (obsNode->query);
304 memcpy (obsNode->query, query, strlen(query)+1);
307 obsNode->token.tokenLength = token->tokenLength;
308 memcpy (obsNode->token.token, token->token, token->tokenLength);
310 obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
311 VERIFY_NON_NULL (obsNode->addr);
312 memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
314 obsNode->resource = resHandle;
316 LL_APPEND (serverObsList, obsNode);
323 OCFree(obsNode->resUri);
324 OCFree(obsNode->query);
325 OCFree(obsNode->addr);
328 return OC_STACK_NO_MEMORY;
331 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
333 ResourceObserver *out = NULL;
337 LL_FOREACH (serverObsList, out)
339 if (out->observeId == observeId)
345 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
349 ResourceObserver* GetObserverUsingToken (const OCCoAPToken * token)
351 ResourceObserver *out = NULL;
355 LL_FOREACH (serverObsList, out)
357 OC_LOG(INFO, TAG,PCF("comparing tokens"));
358 OC_LOG_BUFFER(INFO, TAG, token->token, token->tokenLength);
359 OC_LOG_BUFFER(INFO, TAG, out->token.token, out->token.tokenLength);
360 if((out->token.tokenLength == token->tokenLength) &&
361 (memcmp(out->token.token, token->token, token->tokenLength) == 0))
367 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
371 OCStackResult DeleteObserverUsingToken (OCCoAPToken * token)
373 ResourceObserver *obsNode = NULL;
375 obsNode = GetObserverUsingToken (token);
378 OC_LOG_V(INFO, TAG, PCF("deleting tokens"));
379 OC_LOG_BUFFER(INFO, TAG, obsNode->token.token, obsNode->token.tokenLength);
380 LL_DELETE (serverObsList, obsNode);
381 OCFree(obsNode->resUri);
382 OCFree(obsNode->query);
383 OCFree(obsNode->addr);
386 // it is ok if we did not find the observer...
390 void DeleteObserverList()
392 ResourceObserver *out = NULL;
393 ResourceObserver *tmp = NULL;
394 LL_FOREACH_SAFE (serverObsList, out, tmp)
396 DeleteObserverUsingToken (&(out->token));
398 serverObsList = NULL;