1 //******************************************************************
3 // Copyright 2014 Intel Corporation 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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 #include "ocstackinternal.h"
23 #include "ocobserve.h"
24 #include "ocresource.h"
31 #define MOD_NAME PCF("ocobserve")
33 #define TAG PCF("OCStackObserve")
35 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
37 static struct ResourceObserver * serverObsList = NULL;
39 OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
41 OCStackResult result = OC_STACK_ERROR;
42 ResourceObserver * observer = NULL;
46 case OC_OBSERVER_NOT_INTERESTED:
47 OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
48 //observer is dead, or it is not observing anymore
49 result = DeleteObserver (token);
50 if(result == OC_STACK_OK)
52 OC_LOG(DEBUG, TAG, PCF("removing an observer"));
53 result = OC_STACK_OBSERVER_REMOVED;
56 case OC_OBSERVER_STILL_INTERESTED:
57 //observer is still interested
58 OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
59 notifications, reset the failedCount"));
60 observer = GetObserver(token);
63 observer->forceCON = 0;
64 observer->failedCommCount = 0;
69 result = OC_STACK_OBSERVER_NOT_FOUND;
72 case OC_OBSERVER_FAILED_COMM:
73 //observer is not reachable
74 OC_LOG(DEBUG, TAG, PCF("observer is not reachable"));
75 observer = GetObserver(token);
78 if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
80 result = DeleteObserver (token);
81 OC_LOG(DEBUG, TAG, PCF("removing an observer"));
82 result = OC_STACK_OBSERVER_REMOVED;
86 observer->failedCommCount++;
89 observer->forceCON = 1;
90 OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
100 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
102 OCStackResult result = OC_STACK_ERROR;
103 OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
104 OCObserveReq *obs = request->observe;
106 OC_LOG(INFO, TAG, PCF("Entering ProcessObserveRequest"));
108 // Register new observation
109 request->entityHandlerRequest->resource = (OCResourceHandle)resource;
110 result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
112 if (obs->option == OC_RESOURCE_OBSERVE_REGISTER)
114 // Add subscriber to the server observation list
115 // TODO: we need to check if the obsrever is already there using its OCDevAdd....
116 result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query),
117 obs->token, obs->subAddr, resource, request->qos);
118 if(result == OC_STACK_OK)
120 result = OC_STACK_OBSERVER_ADDED;
122 OC_LOG(DEBUG, TAG, PCF("adding an observer"));
124 else if (obs->option == OC_RESOURCE_OBSERVE_DEREGISTER)
126 // Deregister observation
127 result = DeleteObserver (obs->token);
128 if(result == OC_STACK_OK)
130 OC_LOG(DEBUG, TAG, PCF("removing an observer"));
131 result = OC_STACK_OBSERVER_REMOVED;
137 OC_LOG(ERROR, TAG, PCF("Invalid CoAP observe option"));
138 result = OC_STACK_INVALID_OBSERVE_PARAM;
143 OCStackResult SendObserverNotification (OCResource *resPtr)
146 OCStackResult result = OC_STACK_ERROR;
147 ResourceObserver *resourceObserver = serverObsList;
148 OCEntityHandlerRequest * entityHandlerReq = NULL;
149 unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
150 // TODO: we should allow the server application to define qos for each notification
151 OCQualityOfService qos = OC_NON_CONFIRMABLE;
153 // Increment the sequence number
154 resPtr->sequenceNum += 1;
155 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
157 resPtr->sequenceNum = 1;
160 // Find clients that are observing this resource
161 while (resourceObserver)
163 if (resourceObserver->resource == resPtr)
165 // Invoke the entity handler for the client to process
166 // the query according to the new representation
168 FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
169 NULL, resourceObserver->query);
170 entityHandlerReq->resource = (OCResourceHandle)resPtr;
172 // Even if entity handler for a resource is not successful
173 // we continue calling entity handler for other resources
174 result = resPtr->entityHandler (OC_REQUEST_FLAG, entityHandlerReq);
175 if (OC_STACK_OK == result)
177 OC_LOG_V(INFO, TAG, "OCStack payload: %s",
178 entityHandlerReq->resJSONPayload);
180 // send notifications based on the qos of the request
181 qos = resourceObserver->qos;
182 if(qos == OC_NON_CONFIRMABLE)
184 OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
185 resourceObserver->NONCount);
186 if(resourceObserver->forceCON ||
187 resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
189 resourceObserver->NONCount = 0;
190 // at some point we have to to send CON to check on the
191 // availability of observer
192 OC_LOG(INFO, TAG, PCF("This time we are sending the \
193 notification as CON"));
194 qos = OC_CONFIRMABLE;
198 resourceObserver->NONCount++;
202 OCSendCoAPNotification(resourceObserver->addr, result, qos,
203 resourceObserver->token,
204 (unsigned char *)entityHandlerReq->resJSONPayload,
205 resPtr->sequenceNum);
208 resourceObserver = resourceObserver->next;
212 OC_LOG(INFO, TAG, PCF("Resource has no observers"));
213 return OC_STACK_NO_OBSERVERS;
218 OCStackResult AddObserver (const char *resUri,
222 OCResource *resHandle,
223 OCQualityOfService qos)
225 ResourceObserver *obsNode = NULL;
226 OCCoAPToken *tokPtr = NULL;
228 obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
231 obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1));
232 VERIFY_NON_NULL (obsNode->resUri);
234 memcpy (obsNode->resUri, resUri, sizeof(strlen(resUri)+1));
235 obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
236 VERIFY_NON_NULL (obsNode->query);
237 memcpy (obsNode->query, query, sizeof(strlen(query)+1));
238 obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
239 VERIFY_NON_NULL (obsNode->token);
240 tokPtr = obsNode->token;
241 tokPtr->tokenLength = token->tokenLength;
242 memcpy (tokPtr->token, token->token, tokPtr->tokenLength);
243 obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
244 VERIFY_NON_NULL (obsNode->addr);
245 memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
246 obsNode->resource = resHandle;
247 obsNode->failedCommCount = 0;
248 obsNode->NONCount = 0;
249 obsNode->forceCON = 0;
251 LL_APPEND (serverObsList, obsNode);
256 OCFree(obsNode->resUri);
257 OCFree(obsNode->query);
258 OCFree(obsNode->token);
259 OCFree(obsNode->addr);
261 return OC_STACK_NO_MEMORY;
264 ResourceObserver* GetObserver (const OCCoAPToken * token)
266 ResourceObserver *out = NULL;
270 LL_FOREACH (serverObsList, out)
272 if((out->token->tokenLength == token->tokenLength) &&
273 (memcmp(out->token->token, token->token, token->tokenLength) == 0))
279 OC_LOG(INFO, TAG, PCF("Observer node not found!!"));
283 OCStackResult DeleteObserver (OCCoAPToken * token)
285 ResourceObserver *obsNode = NULL;
287 obsNode = GetObserver (token);
290 LL_DELETE (serverObsList, obsNode);
291 OCFree(obsNode->resUri);
292 OCFree(obsNode->query);
293 OCFree(obsNode->token);
294 OCFree(obsNode->addr);
297 // it is ok if we did not find the observer...
301 void DeleteObserverList()
303 ResourceObserver *out = NULL;
304 ResourceObserver *tmp = NULL;
305 LL_FOREACH_SAFE (serverObsList, out, tmp)
307 DeleteObserver (out->token);
309 serverObsList = NULL;