Continue improving libcoap build script
[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_STACK_OK != sendResponse(ehRequest, resPayload, ehResult))
191     {
192         OIC_LOG(ERROR, TAG, "Sending response failed.");
193     }
194
195     if (OC_EH_OK == ehResult)
196     {
197         OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
198         assert(handle);
199         result = OCNotifyAllObservers(handle, OC_NA_QOS);
200         if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
201         {
202             OIC_LOG(ERROR, TAG, "Notifying observers failed.");
203         }
204     }
205
206     return ehResult;
207 }
208
209 static OCEntityHandlerResult handleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
210 {
211     OCEntityHandlerResult ehResult = OC_EH_ERROR;
212     char *key = NULL;
213     char *value = NULL;
214     char *queryDup = NULL;
215     char *restOfQuery = NULL;
216     char *keyValuePair = NULL;
217     char *di = NULL;
218     uint16_t nIns = 0;
219     int64_t *ins = NULL;
220
221     if (!ehRequest)
222     {
223         OIC_LOG(DEBUG, TAG, "Invalid request pointer");
224         return OC_EH_ERROR;
225     }
226
227     OIC_LOG_V(DEBUG, TAG, "Received OC_REST_DELETE from client with query: %s.", ehRequest->query);
228
229     if (OC_STACK_OK != OCRDDatabaseInit())
230     {
231         goto exit;
232     }
233
234 #define OC_RSRVD_INS_KEY OC_RSRVD_INS OC_KEY_VALUE_DELIMITER /* "ins=" */
235     keyValuePair = strstr(ehRequest->query, OC_RSRVD_INS_KEY);
236     while (keyValuePair)
237     {
238         ++nIns;
239         keyValuePair = strstr(keyValuePair + sizeof(OC_RSRVD_INS_KEY), OC_RSRVD_INS_KEY);
240     }
241     if (nIns)
242     {
243         ins = OICMalloc(nIns * sizeof(*ins));
244         if (!ins)
245         {
246             OIC_LOG_V(ERROR, TAG, "ins is NULL");
247             goto exit;
248         }
249     }
250
251     nIns = 0;
252     queryDup = OICStrdup(ehRequest->query);
253     if (NULL == queryDup)
254     {
255         OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
256         goto exit;
257     }
258     keyValuePair = strtok_r(queryDup, OC_QUERY_SEPARATOR, &restOfQuery);
259     while (keyValuePair)
260     {
261         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
262         if (!key || !value)
263         {
264             OIC_LOG_V(ERROR, TAG, "Invalid query parameter!");
265             goto exit;
266         }
267         else if (0 == strncasecmp(key, OC_RSRVD_DEVICE_ID, sizeof(OC_RSRVD_DEVICE_ID) - 1))
268         {
269             di = value;
270         }
271         else if (0 == strncasecmp(key, OC_RSRVD_INS, sizeof(OC_RSRVD_INS) - 1))
272         {
273             // Arduino's AVR-GCC doesn't support strtoll().
274             int64_t i;
275             int matchedItems = sscanf(value, "%lld", &i);
276             if (0 == matchedItems)
277             {
278                 OIC_LOG_V(ERROR, TAG, "Invalid ins query parameter: %s", value);
279                 goto exit;
280             }
281
282             ins[nIns++] = i;
283         }
284
285         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
286     }
287     if (!di && !nIns)
288     {
289         OIC_LOG_V(ERROR, TAG, "Missing required query parameters!");
290         goto exit;
291     }
292
293     if (OC_STACK_OK == OCRDDatabaseDeleteResources(di, ins, nIns))
294     {
295         OIC_LOG_V(DEBUG, TAG, "Deleted resource(s).");
296         ehResult = OC_EH_OK;
297     }
298
299     if (OC_EH_OK == ehResult)
300     {
301         OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_WELL_KNOWN_URI);
302         assert(handle);
303         OCStackResult result = OCNotifyAllObservers(handle, OC_NA_QOS);
304         if (OC_STACK_NO_OBSERVERS != result && OC_STACK_OK != result)
305         {
306             OIC_LOG(ERROR, TAG, "Notifying observers failed.");
307         }
308     }
309
310 exit:
311     OICFree(ins);
312     OICFree(queryDup);
313     if (OC_STACK_OK != sendResponse(ehRequest, NULL, ehResult))
314     {
315         OIC_LOG(ERROR, TAG, "Sending response failed.");
316     }
317     return ehResult;
318 }
319
320 /*
321  * This internal method is the entity handler for RD resources and
322  * will handle REST request (GET/PUT/POST/DEL) for them.
323  */
324 static OCEntityHandlerResult rdEntityHandler(OCEntityHandlerFlag flag,
325         OCEntityHandlerRequest *ehRequest, void *callbackParameter)
326 {
327     OC_UNUSED(callbackParameter);
328
329     OCEntityHandlerResult ehRet = OC_EH_ERROR;
330
331     if (!ehRequest)
332     {
333         return ehRet;
334     }
335
336     if (flag & OC_REQUEST_FLAG)
337     {
338         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG.");
339         switch (ehRequest->method)
340         {
341             case OC_REST_GET:
342             case OC_REST_DISCOVER:
343                 ehRet = handleGetRequest(ehRequest);
344                 break;
345             case OC_REST_POST:
346                 ehRet = handlePublishRequest(ehRequest);
347                 break;
348             case OC_REST_DELETE:
349                 ehRet = handleDeleteRequest(ehRequest);
350                 break;
351             case OC_REST_PUT:
352             case OC_REST_OBSERVE:
353             case OC_REST_OBSERVE_ALL:
354             case OC_REST_PRESENCE:
355             case OC_REST_NOMETHOD:
356                 break;
357         }
358     }
359
360     return ehRet;
361 }
362
363 /**
364  * Registers RD resource
365  */
366 OCStackResult OC_CALL OCRDStart()
367 {
368     OCStackResult result = OCCreateResource(&rdHandle,
369                                 OC_RSRVD_RESOURCE_TYPE_RD,
370                                 OC_RSRVD_INTERFACE_DEFAULT,
371                                 OC_RSRVD_RD_URI,
372                                 rdEntityHandler,
373                                 NULL,
374                                 (OC_ACTIVE | OC_DISCOVERABLE | OC_SECURE));
375
376     if (OC_STACK_OK == result)
377     {
378         OIC_LOG(DEBUG, TAG, "Resource Directory resource created.");
379     }
380     else
381     {
382         OIC_LOG(ERROR, TAG, "Failed creating Resource Directory resource.");
383         return result;
384     }
385
386     return result;
387 }
388
389 /**
390  * Stops resource directory server
391  */
392 OCStackResult OC_CALL OCRDStop()
393 {
394     if (!rdHandle)
395     {
396         OIC_LOG(ERROR, TAG, "Resource Directory resource handle is not initialized.");
397         return OC_STACK_NO_RESOURCE;
398     }
399
400     OCStackResult result = OCDeleteResource(rdHandle);
401
402     if (OC_STACK_OK == result)
403     {
404       OIC_LOG(DEBUG, TAG, "Resource Directory resource deleted.");
405     }
406     else
407     {
408       OIC_LOG(ERROR, TAG, "Resource Directory resource not deleted.");
409     }
410
411     return result;
412 }
413
414 #endif