Merge branch '1.3-rel' (5fdb8a1)
[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 "iotivity_config.h"
21 #include "rd_server.h"
22
23 #include "rd_database.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "experimental/payload_logging.h"
29 #ifdef HAVE_ARPA_INET_H
30 #include <arpa/inet.h>
31 #endif
32 #ifdef HAVE_WS2TCPIP_H
33 #include <ws2tcpip.h>
34 #endif
35 #ifdef HAVE_IN6ADDR_H
36 #include <in6addr.h>
37 #endif
38 #include "ocpayload.h"
39 #include "octypes.h"
40 #include "oic_string.h"
41 #include "cainterface.h"
42
43 #define TAG PCF("OIC_RD_SERVER")
44
45 #ifdef RD_SERVER
46
47 // This is temporary hardcoded value for bias factor.
48 static const int OC_RD_DISC_SEL = 100;
49
50 static OCResourceHandle rdHandle;
51
52 static OCStackResult sendResponse(const OCEntityHandlerRequest *ehRequest, OCRepPayload *rdPayload,
53     OCEntityHandlerResult ehResult)
54 {
55     OCEntityHandlerResponse response = { 0 };
56     response.requestHandle = ehRequest->requestHandle;
57     response.ehResult = ehResult;
58     response.payload = (OCPayload*)(rdPayload);
59     return OCDoResponse(&response);
60 }
61
62 /**
63  * This internal method handles RD discovery request.
64  * Responds with the RD discovery payload message.
65  */
66 static OCEntityHandlerResult handleGetRequest(const OCEntityHandlerRequest *ehRequest)
67 {
68     if (!ehRequest)
69     {
70         OIC_LOG(DEBUG, TAG, "Invalid request pointer.");
71         return OC_EH_ERROR;
72     }
73
74     OCEntityHandlerResult ehResult = OC_EH_OK;
75     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_GET from client with query: %s.", ehRequest->query);
76
77     OCRepPayload *rdPayload =  (OCRepPayload *)OCRepPayloadCreate();
78     if (!rdPayload)
79     {
80         return OC_STACK_NO_MEMORY;
81     }
82
83     OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_RD_DISCOVERY_SEL, OC_RD_DISC_SEL);
84     OCRepPayloadAddResourceType(rdPayload, OC_RSRVD_RESOURCE_TYPE_RD);
85     OCRepPayloadAddInterface(rdPayload, OC_RSRVD_INTERFACE_DEFAULT);
86     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
87
88     if (OC_STACK_OK != sendResponse(ehRequest, rdPayload, OC_EH_OK))
89     {
90         OIC_LOG(ERROR, TAG, "Sending response failed.");
91         ehResult = OC_EH_ERROR;
92     }
93
94     return ehResult;
95 }
96
97 static bool isRequestFromThisHost(const OCEntityHandlerRequest *ehRequest)
98 {
99     /* ehRequest->devAddr.addr includes zone ID which inet_pton doesn't like */
100     struct in6_addr addr6;
101     if (ehRequest->devAddr.flags & OC_IP_USE_V6)
102     {
103         char addr[MAX_ADDR_STR_SIZE];
104         const char *src = ehRequest->devAddr.addr;
105         char *dst = addr;
106         while (*src && *src != '%')
107         {
108             *dst++ = *src++;
109         }
110         *dst = '\0';
111         inet_pton(AF_INET6, addr, &addr6);
112     }
113
114     bool fromThisHost = false;
115     CAEndpoint_t *caEps = NULL;
116     size_t nCaEps = 0;
117     if (CA_STATUS_OK == CAGetNetworkInformation(&caEps, &nCaEps))
118     {
119         for (size_t i = 0; i < nCaEps; ++i)
120         {
121             if (caEps[i].flags & ehRequest->devAddr.flags & OC_IP_USE_V6)
122             {
123                 struct in6_addr ca6;
124                 if ((1 == inet_pton(AF_INET6, caEps[i].addr, &ca6)) &&
125                         !memcmp(&ca6, &addr6, sizeof(struct in6_addr)))
126                 {
127                     fromThisHost = true;
128                     break;
129                 }
130             }
131             else if (!strcmp(caEps[i].addr, ehRequest->devAddr.addr))
132             {
133                 fromThisHost = true;
134                 break;
135             }
136         }
137         if (caEps)
138         {
139             OICFree(caEps);
140         }
141     }
142     return fromThisHost;
143 }
144
145 /**
146  * This internal method handles RD publish request.
147  * Responds with the RD success message.
148  */
149 static OCEntityHandlerResult handlePublishRequest(const OCEntityHandlerRequest *ehRequest)
150 {
151     OCEntityHandlerResult ehResult;
152
153     if (!ehRequest)
154     {
155         OIC_LOG(DEBUG, TAG, "Invalid request pointer");
156         return OC_EH_ERROR;
157     }
158
159     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_POST from client with query: %s.", ehRequest->query);
160
161     OCRepPayload *payload = (OCRepPayload *)ehRequest->payload;
162     OCRepPayload *resPayload = NULL;
163     OCStackResult result;
164     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) payload);
165     result = OCRDDatabaseInit();
166     if (OC_STACK_OK == result)
167     {
168         if (isRequestFromThisHost(ehRequest))
169         {
170             result = OCRDDatabaseStoreResourcesFromThisHost(payload);
171         }
172         else
173         {
174             result = OCRDDatabaseStoreResources(payload);
175         }
176     }
177     if (OC_STACK_OK == result)
178     {
179         OIC_LOG_V(DEBUG, TAG, "Stored resources.");
180         resPayload = payload;
181         ehResult = OC_EH_OK;
182     }
183     else
184     {
185         resPayload = (OCRepPayload *)OCRepPayloadCreate();
186         ehResult = OC_EH_ERROR;
187     }
188
189     // Send Response
190     if (OC_EH_OK == ehResult)
191     {
192         if (OC_STACK_OK != sendResponse(ehRequest, resPayload, ehResult))
193         {
194             OIC_LOG(ERROR, TAG, "Sending response failed.");
195             ehResult = OC_EH_ERROR;
196         }
197     }
198
199     if (OC_EH_OK == ehResult)
200     {
201         OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
202         assert(handle);
203         result = OCNotifyAllObservers(handle, OC_NA_QOS);
204         if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
205         {
206             OIC_LOG(ERROR, TAG, "Notifying observers failed.");
207         }
208     }
209
210     return ehResult;
211 }
212
213 static OCEntityHandlerResult handleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
214 {
215     OCEntityHandlerResult ehResult = OC_EH_ERROR;
216     char *key = NULL;
217     char *value = NULL;
218     char *queryDup = NULL;
219     char *restOfQuery = NULL;
220     char *keyValuePair = NULL;
221     char *di = NULL;
222     uint16_t nIns = 0;
223     int64_t *ins = NULL;
224
225     if (!ehRequest)
226     {
227         OIC_LOG(DEBUG, TAG, "Invalid request pointer");
228         return OC_EH_ERROR;
229     }
230
231     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_DELETE from client with query: %s.", ehRequest->query);
232
233     if (OC_STACK_OK != OCRDDatabaseInit())
234     {
235         goto exit;
236     }
237
238 #define OC_RSRVD_INS_KEY OC_RSRVD_INS OC_KEY_VALUE_DELIMITER /* "ins=" */
239     keyValuePair = strstr(ehRequest->query, OC_RSRVD_INS_KEY);
240     while (keyValuePair)
241     {
242         ++nIns;
243         keyValuePair = strstr(keyValuePair + sizeof(OC_RSRVD_INS_KEY), OC_RSRVD_INS_KEY);
244     }
245     if (nIns)
246     {
247         ins = OICMalloc(nIns * sizeof(*ins));
248         if (!ins)
249         {
250             OIC_LOG_V(ERROR, TAG, "ins is NULL");
251             goto exit;
252         }
253     }
254
255     nIns = 0;
256     queryDup = OICStrdup(ehRequest->query);
257     if (NULL == queryDup)
258     {
259         OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
260         goto exit;
261     }
262     keyValuePair = strtok_r(queryDup, OC_QUERY_SEPARATOR, &restOfQuery);
263     while (keyValuePair)
264     {
265         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
266         if (!key || !value)
267         {
268             OIC_LOG_V(ERROR, TAG, "Invalid query parameter!");
269             ehResult = OC_EH_BAD_REQ;
270             goto exit;
271         }
272         else if (0 == strncasecmp(key, OC_RSRVD_DEVICE_ID, sizeof(OC_RSRVD_DEVICE_ID) - 1))
273         {
274             di = value;
275         }
276         else if (0 == strncasecmp(key, OC_RSRVD_INS, sizeof(OC_RSRVD_INS) - 1))
277         {
278             // Arduino's AVR-GCC doesn't support strtoll().
279             int64_t i;
280             int matchedItems = sscanf(value, "%lld", &i);
281             if (0 == matchedItems)
282             {
283                 OIC_LOG_V(ERROR, TAG, "Invalid ins query parameter: %s", value);
284                 ehResult = OC_EH_BAD_REQ;
285                 goto exit;
286             }
287
288             ins[nIns++] = i;
289         }
290
291         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
292     }
293     if (!di && !nIns)
294     {
295         OIC_LOG_V(ERROR, TAG, "Missing required query parameters!");
296         ehResult = OC_EH_BAD_REQ;
297         goto exit;
298     }
299
300     if (OC_STACK_OK == OCRDDatabaseDeleteResources(di, ins, nIns))
301     {
302         OIC_LOG_V(DEBUG, TAG, "Deleted resource(s).");
303         ehResult = OC_EH_OK;
304     }
305
306     if (OC_EH_OK == ehResult)
307     {
308         if (OC_STACK_OK != sendResponse(ehRequest, NULL, ehResult))
309         {
310             OIC_LOG(ERROR, TAG, "Sending response failed.");
311             ehResult = OC_EH_ERROR;
312         }
313     }
314
315     if (OC_EH_OK == ehResult)
316     {
317         OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
318         assert(handle);
319         OCStackResult result = OCNotifyAllObservers(handle, OC_NA_QOS);
320         if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
321         {
322             OIC_LOG(ERROR, TAG, "Notifying observers failed.");
323         }
324     }
325
326 exit:
327     OICFree(ins);
328     OICFree(queryDup);
329     return ehResult;
330 }
331
332 /*
333  * This internal method is the entity handler for RD resources and
334  * will handle REST request (GET/PUT/POST/DEL) for them.
335  */
336 static OCEntityHandlerResult rdEntityHandler(OCEntityHandlerFlag flag,
337         OCEntityHandlerRequest *ehRequest, void *callbackParameter)
338 {
339     OC_UNUSED(callbackParameter);
340
341     OCEntityHandlerResult ehRet = OC_EH_ERROR;
342
343     if (!ehRequest)
344     {
345         return ehRet;
346     }
347
348     if (flag & OC_REQUEST_FLAG)
349     {
350         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG.");
351         switch (ehRequest->method)
352         {
353             case OC_REST_GET:
354             case OC_REST_DISCOVER:
355                 ehRet = handleGetRequest(ehRequest);
356                 break;
357             case OC_REST_POST:
358                 ehRet = handlePublishRequest(ehRequest);
359                 break;
360             case OC_REST_DELETE:
361                 ehRet = handleDeleteRequest(ehRequest);
362                 break;
363             case OC_REST_PUT:
364             case OC_REST_OBSERVE:
365             case OC_REST_OBSERVE_ALL:
366             case OC_REST_PRESENCE:
367             case OC_REST_NOMETHOD:
368                 break;
369         }
370     }
371
372     return ehRet;
373 }
374
375 /**
376  * Registers RD resource
377  */
378 OCStackResult OC_CALL OCRDStart()
379 {
380     OCStackResult result = OCCreateResource(&rdHandle,
381                                 OC_RSRVD_RESOURCE_TYPE_RD,
382                                 OC_RSRVD_INTERFACE_DEFAULT,
383                                 OC_RSRVD_RD_URI,
384                                 rdEntityHandler,
385                                 NULL,
386                                 (OC_ACTIVE | OC_DISCOVERABLE | OC_SECURE));
387
388     if (OC_STACK_OK == result)
389     {
390         OIC_LOG(DEBUG, TAG, "Resource Directory resource created.");
391     }
392     else
393     {
394         OIC_LOG(ERROR, TAG, "Failed creating Resource Directory resource.");
395         return result;
396     }
397
398     return result;
399 }
400
401 /**
402  * Stops resource directory server
403  */
404 OCStackResult OC_CALL OCRDStop()
405 {
406     if (!rdHandle)
407     {
408         OIC_LOG(ERROR, TAG, "Resource Directory resource handle is not initialized.");
409         return OC_STACK_NO_RESOURCE;
410     }
411
412     OCStackResult result = OCDeleteResource(rdHandle);
413
414     if (OC_STACK_OK == result)
415     {
416       OIC_LOG(DEBUG, TAG, "Resource Directory resource deleted.");
417     }
418     else
419     {
420       OIC_LOG(ERROR, TAG, "Resource Directory resource not deleted.");
421     }
422
423     return result;
424 }
425
426 #endif