[IOT-1817] RD should notify observers of /oic/res when resources are
[platform/upstream/iotivity.git] / resource / csdk / resource-directory / src / rd_server.c
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics 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 #include "rd_server.h"
21
22 #include "rd_database.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "payload_logging.h"
28 #include "ocpayload.h"
29 #include "octypes.h"
30 #include "oic_string.h"
31
32 #define TAG PCF("OIC_RD_SERVER")
33
34 #ifdef RD_SERVER
35
36 // This is temporary hardcoded value for bias factor.
37 static const int OC_RD_DISC_SEL = 100;
38
39 static OCResourceHandle rdHandle;
40
41 static OCStackResult sendResponse(const OCEntityHandlerRequest *ehRequest, OCRepPayload *rdPayload,
42     OCEntityHandlerResult ehResult)
43 {
44     OCEntityHandlerResponse response = { 0 };
45     response.requestHandle = ehRequest->requestHandle;
46     response.resourceHandle = ehRequest->resource;
47     response.ehResult = ehResult;
48     response.payload = (OCPayload*)(rdPayload);
49     return OCDoResponse(&response);
50 }
51
52 /**
53  * This internal method handles RD discovery request.
54  * Responds with the RD discovery payload message.
55  */
56 static OCEntityHandlerResult handleGetRequest(const OCEntityHandlerRequest *ehRequest)
57 {
58     if (!ehRequest)
59     {
60         OIC_LOG(DEBUG, TAG, "Invalid request pointer.");
61         return OC_EH_ERROR;
62     }
63
64     OCEntityHandlerResult ehResult = OC_EH_OK;
65     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_GET from client with query: %s.", ehRequest->query);
66
67     OCRepPayload *rdPayload =  (OCRepPayload *)OCRepPayloadCreate();
68     if (!rdPayload)
69     {
70         return OC_STACK_NO_MEMORY;
71     }
72
73     const char *id = OCGetServerInstanceIDString();
74     if (id)
75     {
76         OCRepPayloadSetPropString(rdPayload, OC_RSRVD_DEVICE_ID, id);
77     }
78     OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_RD_DISCOVERY_SEL, OC_RD_DISC_SEL);
79
80     OCRepPayloadAddResourceType(rdPayload, OC_RSRVD_RESOURCE_TYPE_RD);
81     OCRepPayloadAddResourceType(rdPayload, OC_RSRVD_RESOURCE_TYPE_RDPUBLISH);
82
83     OCRepPayloadAddInterface(rdPayload, OC_RSRVD_INTERFACE_DEFAULT);
84
85     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
86
87     if (OC_STACK_OK != sendResponse(ehRequest, rdPayload, OC_EH_OK))
88     {
89         OIC_LOG(ERROR, TAG, "Sending response failed.");
90         ehResult = OC_EH_ERROR;
91     }
92
93     return ehResult;
94 }
95
96 /**
97  * This internal method handles RD publish request.
98  * Responds with the RD success message.
99  */
100 static OCEntityHandlerResult handlePublishRequest(const OCEntityHandlerRequest *ehRequest)
101 {
102     OCEntityHandlerResult ehResult = OC_EH_OK;
103
104     if (!ehRequest)
105     {
106         OIC_LOG(DEBUG, TAG, "Invalid request pointer");
107         return OC_EH_ERROR;
108     }
109
110     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_POST from client with query: %s.", ehRequest->query);
111
112     OCRepPayload *payload = (OCRepPayload *)ehRequest->payload;
113     OCRepPayload *resPayload = NULL;
114     if (payload)
115     {
116         OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) payload);
117         if (OC_STACK_OK == OCRDDatabaseInit(NULL))
118         {
119             if (OC_STACK_OK == OCRDDatabaseStoreResources(payload, &ehRequest->devAddr))
120             {
121                 OIC_LOG_V(DEBUG, TAG, "Stored resources.");
122                 resPayload = payload;
123                 ehResult = OC_EH_OK;
124             }
125             else
126             {
127                 resPayload = (OCRepPayload *)OCRepPayloadCreate();
128                 ehResult = OC_EH_ERROR;
129             }
130         }
131
132         // Send Response
133         if (OC_STACK_OK != sendResponse(ehRequest, resPayload, ehResult))
134         {
135             OIC_LOG(ERROR, TAG, "Sending response failed.");
136         }
137
138         if (OC_EH_OK == ehResult)
139         {
140             OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
141             assert(handle);
142             OCStackResult result = OCNotifyAllObservers(handle, OC_NA_QOS);
143             if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
144             {
145                 OIC_LOG(ERROR, TAG, "Notifying observers failed.");
146             }
147         }
148     }
149
150     return ehResult;
151 }
152
153 static OCEntityHandlerResult handleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
154 {
155     OCEntityHandlerResult ehResult = OC_EH_ERROR;
156     char *key = NULL;
157     char *value = NULL;
158     char *queryDup = NULL;
159     char *restOfQuery = NULL;
160     char *keyValuePair = NULL;
161     char *di = NULL;
162     size_t nIns = 0;
163     uint8_t *ins = NULL;
164
165     if (!ehRequest)
166     {
167         OIC_LOG(DEBUG, TAG, "Invalid request pointer");
168         return OC_EH_ERROR;
169     }
170
171     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_DELETE from client with query: %s.", ehRequest->query);
172
173     if (OC_STACK_OK != OCRDDatabaseInit(NULL))
174     {
175         goto exit;
176     }
177
178 #define OC_RSRVD_INS_KEY OC_RSRVD_INS OC_KEY_VALUE_DELIMITER /* "ins=" */
179     keyValuePair = strstr(ehRequest->query, OC_RSRVD_INS_KEY);
180     while (keyValuePair)
181     {
182         ++nIns;
183         keyValuePair = strstr(keyValuePair + sizeof(OC_RSRVD_INS_KEY), OC_RSRVD_INS_KEY);
184     }
185     if (nIns)
186     {
187         ins = OICMalloc(nIns * sizeof(uint8_t));
188         if (!ins)
189         {
190             OIC_LOG_V(ERROR, TAG, "ins is NULL");
191             goto exit;
192         }
193     }
194
195     nIns = 0;
196     queryDup = OICStrdup(ehRequest->query);
197     if (NULL == queryDup)
198     {
199         OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
200         goto exit;
201     }
202     keyValuePair = strtok_r(queryDup, OC_QUERY_SEPARATOR, &restOfQuery);
203     while (keyValuePair)
204     {
205         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
206         if (!key || !value)
207         {
208             OIC_LOG_V(ERROR, TAG, "Invalid query parameter!");
209             goto exit;
210         }
211         else if (0 == strncasecmp(key, OC_RSRVD_DEVICE_ID, sizeof(OC_RSRVD_DEVICE_ID) - 1))
212         {
213             di = value;
214         }
215         else if (0 == strncasecmp(key, OC_RSRVD_INS, sizeof(OC_RSRVD_INS) - 1))
216         {
217             char *endptr = NULL;
218             long int i = strtol(value, &endptr, 0);
219             if ( '\0' != *endptr || i < 0 || i > UINT8_MAX)
220             {
221                 OIC_LOG_V(ERROR, TAG, "Invalid ins query parameter: %s", value);
222                 goto exit;
223             }
224             ins[nIns++] = i;
225         }
226
227         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
228     }
229     if (!di)
230     {
231         OIC_LOG_V(ERROR, TAG, "Missing required di query parameter!");
232         goto exit;
233     }
234
235     if (OC_STACK_OK == OCRDDatabaseDeleteResources(di, ins, nIns))
236     {
237         OIC_LOG_V(DEBUG, TAG, "Deleted resource(s).");
238         ehResult = OC_EH_OK;
239     }
240
241     if (OC_EH_OK == ehResult)
242     {
243         OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
244         assert(handle);
245         OCStackResult result = OCNotifyAllObservers(handle, OC_NA_QOS);
246         if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
247         {
248             OIC_LOG(ERROR, TAG, "Notifying observers failed.");
249         }
250     }
251
252 exit:
253     OICFree(ins);
254     OICFree(queryDup);
255     if (OC_STACK_OK != sendResponse(ehRequest, NULL, ehResult))
256     {
257         OIC_LOG(ERROR, TAG, "Sending response failed.");
258     }
259     return ehResult;
260 }
261
262 /*
263  * This internal method is the entity handler for RD resources and
264  * will handle REST request (GET/PUT/POST/DEL) for them.
265  */
266 static OCEntityHandlerResult rdEntityHandler(OCEntityHandlerFlag flag,
267         OCEntityHandlerRequest *ehRequest, OC_ANNOTATE_UNUSED void *callbackParameter)
268 {
269     OCEntityHandlerResult ehRet = OC_EH_ERROR;
270
271     if (!ehRequest)
272     {
273         return ehRet;
274     }
275
276     if (flag & OC_REQUEST_FLAG)
277     {
278         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG.");
279         switch (ehRequest->method)
280         {
281             case OC_REST_GET:
282             case OC_REST_DISCOVER:
283                 ehRet = handleGetRequest(ehRequest);
284                 break;
285             case OC_REST_POST:
286                 ehRet = handlePublishRequest(ehRequest);
287                 break;
288             case OC_REST_DELETE:
289                 ehRet = handleDeleteRequest(ehRequest);
290                 break;
291             case OC_REST_PUT:
292             case OC_REST_OBSERVE:
293             case OC_REST_OBSERVE_ALL:
294             case OC_REST_PRESENCE:
295             case OC_REST_NOMETHOD:
296                 break;
297         }
298     }
299
300     return ehRet;
301 }
302
303 /**
304  * Registers RD resource
305  */
306 OCStackResult OCRDStart()
307 {
308     OCStackResult result = OCCreateResource(&rdHandle,
309                                 OC_RSRVD_RESOURCE_TYPE_RD,
310                                 OC_RSRVD_INTERFACE_DEFAULT,
311                                 OC_RSRVD_RD_URI,
312                                 rdEntityHandler,
313                                 NULL,
314                                 (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE));
315
316     if (OC_STACK_OK == result)
317     {
318         OIC_LOG(DEBUG, TAG, "Resource Directory resource created.");
319     }
320     else
321     {
322         OIC_LOG(ERROR, TAG, "Failed creating Resource Directory resource.");
323         return result;
324     }
325     result = OCBindResourceTypeToResource(rdHandle,
326                     OC_RSRVD_RESOURCE_TYPE_RDPUBLISH);
327     if (OC_STACK_OK == result)
328     {
329         OIC_LOG(DEBUG, TAG, "Resource Directory resource Publish created.");
330     }
331     else
332     {
333         OIC_LOG(ERROR, TAG, "Failed creating Resource Directory Publish resource.");
334     }
335
336     return result;
337 }
338
339 /**
340  * Stops resource directory server
341  */
342 OCStackResult OCRDStop()
343 {
344     if (!rdHandle)
345     {
346         OIC_LOG(ERROR, TAG, "Resource Directory resource handle is not initialized.");
347         return OC_STACK_NO_RESOURCE;
348     }
349
350     OCStackResult result = OCDeleteResource(rdHandle);
351
352     if (OC_STACK_OK == result)
353     {
354       OIC_LOG(DEBUG, TAG, "Resource Directory resource deleted.");
355     }
356     else
357     {
358       OIC_LOG(ERROR, TAG, "Resource Directory resource not deleted.");
359     }
360
361     return result;
362 }
363
364 #endif