To come on this changeset: All convergences between and server and client observation...
[platform/upstream/iotivity.git] / csdk / stack / src / ocobserve.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation 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 "ocstackinternal.h"
24 #include "ocobserve.h"
25 #include "occoap.h"
26 #include "utlist.h"
27 #include "debug.h"
28
29 // Module Name
30 #define MOD_NAME PCF("ocobserve")
31
32 #define TAG  PCF("OCStackObserve")
33
34 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
35
36 static struct ObserveResourceServer *serverObsList = NULL;
37
38 OCStackResult AddObserver (const char   *resUri,
39                            const char   *query,
40                            uint8_t      *token,
41                            size_t       tokenLength,
42                            OCDevAddr    *addr,
43                            OCResource   *resHandle);
44 OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength);
45
46 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
47 {
48     OCStackResult result;
49     OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
50     OCObserveReq *obs = request->observe;
51
52     OC_LOG(INFO, TAG, "Entering ProcessObserveRequest");
53     if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_REGISTER) == 0) {
54         if (NULL == resource)
55         {
56             return OC_STACK_ERROR;
57         }
58         // Register new observation
59         request->entityHandlerRequest->resource = (OCResourceHandle)resource;
60         result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
61         if (OC_STACK_OK == result)
62         {
63             // Add subscriber to the server observation list
64             result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query), 
65                                    obs->token->token, obs->token->tokenLength, obs->subAddr, resource);
66         } 
67         return result;
68     } else if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
69         // Deregister observation
70         result = DeleteObserver (obs->token->token, obs->token->tokenLength);
71         return result;
72     } else {
73         // Invalid option
74         OC_LOG(ERROR, TAG, "Invalid CoAP observe option");
75         return OC_STACK_INVALID_OBSERVE_PARAM;
76     }
77 }
78
79 OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr) 
80 {
81     uint8_t numObs = 0;
82     OCStackResult result;
83     ObserveResourceServer *obsRes = serverObsList;
84     OCEntityHandlerRequest entityHandlerReq;
85     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
86     /* 
87      * TODO: In the current releast all observes are set as non-confirmable since the
88      * entity handler does not have a way to specify the message QoS - add a parameter. 
89      * Sending all observes NON does not confirm with the observe draft (ver14).
90      */
91     OCQualityOfService qos = OC_NON_CONFIRMABLE;
92
93     // Increment the sequence number
94     resPtr->sequenceNum += 1;
95     if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
96         resPtr->sequenceNum = 1;
97
98     // Find clients that are observing this resource
99     while (obsRes) {
100         if (obsRes->resource == handle) {
101             // Invoke the entity handler for the client to process the query according to
102             // the new representation
103             numObs++;
104             entityHandlerReq.resource = handle;
105             entityHandlerReq.query = obsRes->query;
106             entityHandlerReq.method = OC_REST_GET;
107             entityHandlerReq.reqJSONPayload = NULL;
108             entityHandlerReq.resJSONPayload = bufRes;
109             entityHandlerReq.resJSONPayloadLen = MAX_RESPONSE_LENGTH;
110             // Even if entity handler for a resource is not successful we continue calling
111             // entity handler for other resources 
112             result = resPtr->entityHandler (OC_REQUEST_FLAG, &entityHandlerReq);
113             if (OC_STACK_OK == result)
114             {
115                 OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->token,
116                                    (const char *)entityHandlerReq.resJSONPayload,
117                                     resPtr->sequenceNum);
118             }
119         }
120         obsRes = obsRes->next;
121     }
122     if (numObs == 0)
123     {
124         OC_LOG(INFO, TAG, "Resource has no observers");
125         return OC_STACK_NO_OBSERVERS;
126     }
127     return OC_STACK_OK;
128 }
129
130 OCStackResult AddObserver (const char   *resUri,
131                            const char   *query,
132                            uint8_t      *token,
133                            size_t       tokenLength,
134                            OCDevAddr    *addr,
135                            OCResource   *resHandle)
136 {
137     ObserveResourceServer *obsNode;
138     OCCoAPToken *tokPtr;
139
140     obsNode = (ObserveResourceServer *) OCMalloc(sizeof(ObserveResourceServer));
141     if (obsNode) {
142         obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1));
143         VERIFY_NON_NULL (obsNode->resUri);
144         memcpy (obsNode->resUri, resUri, sizeof(strlen(resUri)+1));
145         obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
146         VERIFY_NON_NULL (obsNode->query);
147         memcpy (obsNode->query, query, sizeof(strlen(query)+1));
148         obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
149         VERIFY_NON_NULL (obsNode->token);
150         tokPtr = obsNode->token;
151         memcpy (tokPtr->token, token, sizeof(OCCoAPToken));
152         tokPtr->tokenLength = tokenLength;
153         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
154         VERIFY_NON_NULL (obsNode->addr);
155         memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
156         obsNode->resource = resHandle;
157
158         LL_APPEND (serverObsList, obsNode);
159         return OC_STACK_OK;
160     }
161
162 exit:
163     OCFree(obsNode->resUri);
164     OCFree(obsNode->query);
165     OCFree(obsNode->token);
166     OCFree(obsNode->addr);
167     OCFree(obsNode);
168     return OC_STACK_NO_MEMORY;
169 }
170
171 ObserveResourceServer* GetObserver (const uint8_t *token, const size_t tokenLength)
172 {
173     ObserveResourceServer *out = NULL;
174
175     if(token) 
176     {
177         LL_FOREACH (serverObsList, out) 
178         {
179             if((out->token->tokenLength == tokenLength) &&
180                (memcmp(out->token->token, token, tokenLength) == 0)) {
181                 return out;
182             }
183         }
184     }
185     OC_LOG(INFO, MOD_NAME, PCF("Observer node not found!!"));
186     return NULL;
187 }
188
189 OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength)
190 {
191     ObserveResourceServer *obsNode = NULL;
192
193     obsNode = GetObserver (token, tokenLength);
194     if (obsNode) {
195         LL_DELETE (serverObsList, obsNode);
196         OCFree(obsNode->resUri);
197         OCFree(obsNode->query);
198         OCFree(obsNode->token);
199         OCFree(obsNode->addr);
200         OCFree(obsNode);
201         return OC_STACK_OK;
202     }
203     return OC_STACK_ERROR;
204 }
205
206 void DeleteObserverList() 
207 {
208     ObserveResourceServer *out;
209     ObserveResourceServer *tmp;
210     LL_FOREACH_SAFE (serverObsList, out, tmp) 
211     {
212         DeleteObserver (out->token->token, out->token->tokenLength);
213     }
214     serverObsList = NULL;
215 }