[IOT-2537] Filter eps returned from RD queries.
[iotivity.git] / resource / csdk / stack / src / oicresourcedirectory.c
1 //******************************************************************
2 //
3 // Copyright 2016 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 a
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 <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #ifdef RD_SERVER
26 #include "sqlite3.h"
27 #endif
28
29 #include "octypes.h"
30 #include "ocstack.h"
31 #include "ocrandom.h"
32 #include "logger.h"
33 #include "ocpayload.h"
34 #include "ocendpoint.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "cainterface.h"
38
39 #define TAG "OIC_RI_RESOURCEDIRECTORY"
40
41 #define VERIFY_NON_NULL(arg) \
42 if (!(arg)) \
43 { \
44     OIC_LOG(ERROR, TAG, #arg " is NULL"); \
45     result = OC_STACK_NO_MEMORY; \
46     goto exit; \
47 }
48
49 #ifdef RD_SERVER
50
51 static const char *gRDPath = "RD.db";
52
53 static sqlite3 *gRDDB = NULL;
54
55 /* Column indices of RD_DEVICE_LINK_LIST table */
56 static const uint8_t ins_index = 0;
57 static const uint8_t href_index = 1;
58 static const uint8_t rel_index = 2;
59 static const uint8_t anchor_index = 3;
60 static const uint8_t bm_index = 4;
61 static const uint8_t d_index = 5;
62
63 /* Column indices of RD_LINK_RT table */
64 static const uint8_t rt_value_index = 0;
65
66 /* Column indices of RD_LINK_IF table */
67 static const uint8_t if_value_index = 0;
68
69 /* Column indices of RD_LINK_EP table */
70 static const uint8_t ep_value_index = 0;
71 static const uint8_t pri_value_index = 1;
72
73 #define VERIFY_SQLITE(arg) \
74 if (SQLITE_OK != (arg)) \
75 { \
76     OIC_LOG_V(ERROR, TAG, "Error in " #arg ", Error Message: %s",  sqlite3_errmsg(gRDDB)); \
77     result = OC_STACK_ERROR; \
78     goto exit; \
79 }
80
81 OCStackResult OC_CALL OCRDDatabaseSetStorageFilename(const char *filename)
82 {
83     if (!filename)
84     {
85         OIC_LOG(ERROR, TAG, "The persistent storage filename is invalid");
86         return OC_STACK_INVALID_PARAM;
87     }
88     gRDPath = filename;
89     return OC_STACK_OK;
90 }
91
92 const char *OC_CALL OCRDDatabaseGetStorageFilename()
93 {
94     return gRDPath;
95 }
96
97 static void errorCallback(void *arg, int errCode, const char *errMsg)
98 {
99     OC_UNUSED(arg);
100     OC_UNUSED(errCode);
101     OC_UNUSED(errMsg);
102     OIC_LOG_V(ERROR, TAG, "SQLLite Error: %s : %d", errMsg, errCode);
103 }
104
105 static OCStackResult appendStringLL(OCStringLL **type, const unsigned char *value)
106 {
107     OCStackResult result;
108     OCStringLL *temp= (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
109     VERIFY_NON_NULL(temp);
110     temp->value = OICStrdup((char *)value);
111     VERIFY_NON_NULL(temp->value);
112     temp->next = NULL;
113
114     if (!*type)
115     {
116         *type = temp;
117     }
118     else
119     {
120         OCStringLL *tmp = *type;
121         for (; tmp->next; tmp = tmp->next);
122         tmp->next = temp;
123     }
124     temp = NULL;
125     result = OC_STACK_OK;
126
127 exit:
128     if (temp)
129     {
130         OICFree(temp->value);
131         OICFree(temp);
132     }
133     return result;
134 }
135
136 /* stmt is of form "SELECT * FROM RD_DEVICE_LINK_LIST ..." */
137 static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDevAddr *devAddr,
138         OCDiscoveryPayload *discPayload)
139 {
140     int res = sqlite3_step(stmt);
141     if (SQLITE_ROW != res)
142     {
143         return OC_STACK_NO_RESOURCE;
144     }
145
146     OCStackResult result;
147     OCResourcePayload *resourcePayload = NULL;
148     OCEndpointPayload *epPayload = NULL;
149     sqlite3_stmt *stmtRT = NULL;
150     sqlite3_stmt *stmtIF = NULL;
151     sqlite3_stmt *stmtEP = NULL;
152     sqlite3_stmt *stmtDI = NULL;
153     while (SQLITE_ROW == res)
154     {
155         resourcePayload = (OCResourcePayload *)OICCalloc(1, sizeof(OCResourcePayload));
156         VERIFY_NON_NULL(resourcePayload);
157
158         sqlite3_int64 id = sqlite3_column_int64(stmt, ins_index);
159         const unsigned char *uri = sqlite3_column_text(stmt, href_index);
160         const unsigned char *rel = sqlite3_column_text(stmt, rel_index);
161         const unsigned char *anchor = sqlite3_column_text(stmt, anchor_index);
162         sqlite3_int64 bitmap = sqlite3_column_int64(stmt, bm_index);
163         sqlite3_int64 deviceId = sqlite3_column_int64(stmt, d_index);
164         OIC_LOG_V(DEBUG, TAG, " %s %" PRId64, uri, (int64_t) deviceId);
165
166         resourcePayload->uri = OICStrdup((char *)uri);
167         VERIFY_NON_NULL(resourcePayload->uri)
168         if (rel)
169         {
170             resourcePayload->rel = OICStrdup((char *)rel);
171             VERIFY_NON_NULL(resourcePayload->rel);
172         }
173         if (anchor)
174         {
175             resourcePayload->anchor = OICStrdup((char *)anchor);
176             VERIFY_NON_NULL(resourcePayload->anchor);
177         }
178
179         const char rt[] = "SELECT rt FROM RD_LINK_RT WHERE LINK_ID=@id";
180         int rtSize = (int)sizeof(rt);
181         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, rt, rtSize, &stmtRT, NULL));
182         VERIFY_SQLITE(sqlite3_bind_int64(stmtRT, sqlite3_bind_parameter_index(stmtRT, "@id"), id));
183         while (SQLITE_ROW == sqlite3_step(stmtRT))
184         {
185             const unsigned char *tempRt = sqlite3_column_text(stmtRT, rt_value_index);
186             result = appendStringLL(&resourcePayload->types, tempRt);
187             if (OC_STACK_OK != result)
188             {
189                 goto exit;
190             }
191         }
192         VERIFY_SQLITE(sqlite3_finalize(stmtRT));
193         stmtRT = NULL;
194
195         const char itf[] = "SELECT if FROM RD_LINK_IF WHERE LINK_ID=@id";
196         int itfSize = (int)sizeof(itf);
197         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, itf, itfSize, &stmtIF, NULL));
198         VERIFY_SQLITE(sqlite3_bind_int64(stmtIF, sqlite3_bind_parameter_index(stmtIF, "@id"), id));
199         while (SQLITE_ROW == sqlite3_step(stmtIF))
200         {
201             const unsigned char *tempItf = sqlite3_column_text(stmtIF, if_value_index);
202             result = appendStringLL(&resourcePayload->interfaces, tempItf);
203             if (OC_STACK_OK != result)
204             {
205                 goto exit;
206             }
207         }
208         VERIFY_SQLITE(sqlite3_finalize(stmtIF));
209         stmtIF = NULL;
210
211         resourcePayload->bitmap = (uint8_t)(bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE));
212
213         CAEndpoint_t *networkInfo = NULL;
214         size_t infoSize = 0;
215         if (devAddr)
216         {
217             CAResult_t caResult = CAGetNetworkInformation(&networkInfo, &infoSize);
218             if (CA_STATUS_FAILED == caResult)
219             {
220                 OIC_LOG(WARNING, TAG, "CAGetNetworkInformation has error on parsing network infomation");
221             }
222         }
223         const char ep[] = "SELECT ep,pri FROM RD_LINK_EP WHERE LINK_ID=@id";
224         int epSize = (int)sizeof(ep);
225         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, ep, epSize, &stmtEP, NULL));
226         VERIFY_SQLITE(sqlite3_bind_int64(stmtEP, sqlite3_bind_parameter_index(stmtEP, "@id"), id));
227         while (SQLITE_ROW == sqlite3_step(stmtEP))
228         {
229             epPayload = (OCEndpointPayload *)OICCalloc(1, sizeof(OCEndpointPayload));
230             VERIFY_NON_NULL(epPayload);
231             const unsigned char *tempEp = sqlite3_column_text(stmtEP, ep_value_index);
232             result = OCParseEndpointString((const char *)tempEp, epPayload);
233             if (OC_STACK_OK != result)
234             {
235                 goto exit;
236             }
237             sqlite3_int64 pri = sqlite3_column_int64(stmtEP, pri_value_index);
238             epPayload->pri = (uint16_t)pri;
239             bool includeEp = true;
240             if (devAddr)
241             {
242                 CAEndpoint_t *info = NULL;
243                 for (size_t i = 0; i < infoSize; ++i)
244                 {
245                     if (!strcmp(epPayload->addr, networkInfo[i].addr))
246                     {
247                         info = &networkInfo[i];
248                         break;
249                     }
250                 }
251                 includeEp = info &&
252                         (((OC_ADAPTER_IP | OC_ADAPTER_TCP) & (devAddr->adapter)) &&
253                         ((((CA_ADAPTER_IP | CA_ADAPTER_TCP) & info->adapter) &&
254                                 (info->ifindex == devAddr->ifindex)) ||
255                                 info->adapter == CA_ADAPTER_RFCOMM_BTEDR));
256             }
257             if (includeEp)
258             {
259                 OCEndpointPayload **tmp = &resourcePayload->eps;
260                 while (*tmp)
261                 {
262                     tmp = &(*tmp)->next;
263                 }
264                 *tmp = epPayload;
265             }
266             else
267             {
268                 OICFree(epPayload);
269             }
270             epPayload = NULL;
271         }
272         VERIFY_SQLITE(sqlite3_finalize(stmtEP));
273         stmtEP = NULL;
274         if (networkInfo)
275         {
276             OICFree(networkInfo);
277         }
278
279         const char di[] = "SELECT di FROM RD_DEVICE_LIST "
280             "INNER JOIN RD_DEVICE_LINK_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID "
281             "WHERE RD_DEVICE_LINK_LIST.DEVICE_ID=@deviceId";
282         int diSize = (int)sizeof(di);
283         const uint8_t di_index = 0;
284         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, di, diSize, &stmtDI, NULL));
285         VERIFY_SQLITE(sqlite3_bind_int64(stmtDI, sqlite3_bind_parameter_index(stmtDI, "@deviceId"), deviceId));
286         res = sqlite3_step(stmtDI);
287         if (SQLITE_ROW == res || SQLITE_DONE == res)
288         {
289             const unsigned char *tempDi = sqlite3_column_text(stmtDI, di_index);
290             OIC_LOG_V(DEBUG, TAG, " %s", tempDi);
291             discPayload->sid = OICStrdup((char *)tempDi);
292             VERIFY_NON_NULL(discPayload->sid);
293         }
294         VERIFY_SQLITE(sqlite3_finalize(stmtDI));
295         stmtDI = NULL;
296
297         OCDiscoveryPayloadAddNewResource(discPayload, resourcePayload);
298         resourcePayload = NULL;
299         res = sqlite3_step(stmt);
300     }
301     result = OC_STACK_OK;
302
303 exit:
304     sqlite3_finalize(stmtDI);
305     sqlite3_finalize(stmtEP);
306     sqlite3_finalize(stmtIF);
307     sqlite3_finalize(stmtRT);
308     OICFree(epPayload);
309     OCDiscoveryResourceDestroy(resourcePayload);
310     return result;
311 }
312
313 static OCStackResult CheckResources(const char *interfaceType, const char *resourceType,
314         OCDevAddr *devAddr, OCDiscoveryPayload *discPayload)
315 {
316     if (!interfaceType && !resourceType)
317     {
318         return OC_STACK_INVALID_QUERY;
319     }
320     if (!discPayload || !discPayload->sid)
321     {
322         return OC_STACK_INTERNAL_SERVER_ERROR;
323     }
324
325     size_t sidLength = strlen(discPayload->sid);
326     size_t resourceTypeLength = resourceType ? strlen(resourceType) : 0;
327     size_t interfaceTypeLength = interfaceType ? strlen(interfaceType) : 0;
328
329     if ((sidLength > INT_MAX) ||
330         (resourceTypeLength > INT_MAX) ||
331         (interfaceTypeLength > INT_MAX))
332     {
333         return OC_STACK_INVALID_QUERY;
334     }
335
336     OCStackResult result = OC_STACK_OK;
337     sqlite3_stmt *stmt = NULL;
338     if (resourceType)
339     {
340         if (!interfaceType || 0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL) ||
341                 0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_DEFAULT))
342         {
343             const char input[] = "SELECT * FROM RD_DEVICE_LINK_LIST "
344                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
345                                 "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID "
346                                 "WHERE RD_DEVICE_LIST.di LIKE @di AND RD_LINK_RT.rt LIKE @resourceType";
347             int inputSize = (int)sizeof(input);
348             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
349             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@di"),
350                             discPayload->sid, (int)sidLength, SQLITE_STATIC));
351             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@resourceType"),
352                             resourceType, (int)resourceTypeLength, SQLITE_STATIC));
353         }
354         else
355         {
356             const char input[] = "SELECT * FROM RD_DEVICE_LINK_LIST "
357                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
358                                 "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID "
359                                 "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID "
360                                 "WHERE RD_DEVICE_LIST.di LIKE @di "
361                                 "AND RD_LINK_RT.rt LIKE @resourceType "
362                                 "AND RD_LINK_IF.if LIKE @interfaceType";
363             int inputSize = (int)sizeof(input);
364             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
365             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@di"),
366                             discPayload->sid, (int)sidLength, SQLITE_STATIC));
367             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@resourceType"),
368                             resourceType, (int)resourceTypeLength, SQLITE_STATIC));
369             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@interfaceType"),
370                             interfaceType, (int)interfaceTypeLength, SQLITE_STATIC));
371         }
372         result = ResourcePayloadCreate(stmt, devAddr, discPayload);
373     }
374     else if (interfaceType)
375     {
376         if (0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL) ||
377                 0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_DEFAULT))
378         {
379             const char input[] = "SELECT * FROM RD_DEVICE_LINK_LIST "
380                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
381                                 "WHERE RD_DEVICE_LIST.di LIKE @di";
382             int inputSize = (int)sizeof(input);
383             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
384             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@di"),
385                             discPayload->sid, (int)sidLength, SQLITE_STATIC));
386         }
387         else
388         {
389             const char input[] = "SELECT * FROM RD_DEVICE_LINK_LIST "
390                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
391                                 "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID "
392                                 "WHERE RD_DEVICE_LIST.di LIKE @di AND RD_LINK_IF.if LIKE @interfaceType";
393             int inputSize = (int)sizeof(input);
394             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
395             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@di"),
396                             discPayload->sid, (int)sidLength, SQLITE_STATIC));
397             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@interfaceType"),
398                             interfaceType, (int)interfaceTypeLength, SQLITE_STATIC));
399         }
400         result = ResourcePayloadCreate(stmt, devAddr, discPayload);
401     }
402
403 exit:
404     sqlite3_finalize(stmt);
405     return result;
406 }
407
408 OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType,
409         const char *resourceType, OCDiscoveryPayload **payload)
410 {
411     return OCRDDatabaseDiscoveryPayloadCreateWithEp(interfaceType, resourceType, NULL, payload);
412 }
413
414 OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreateWithEp(const char *interfaceType,
415         const char *resourceType, OCDevAddr *endpoint, OCDiscoveryPayload **payload)
416 {
417     OCStackResult result;
418     OCDiscoveryPayload *head = NULL;
419     OCDiscoveryPayload **tail = &head;
420     sqlite3_stmt *stmt = NULL;
421
422     if (*payload)
423     {
424         /*
425          * This is an error of the caller, return here instead of touching the
426          * caller provided payload.
427          */
428         OIC_LOG_V(ERROR, TAG, "Payload is already allocated");
429         result = OC_STACK_INTERNAL_SERVER_ERROR;
430         goto exit;
431     }
432
433     if (SQLITE_OK == sqlite3_config(SQLITE_CONFIG_LOG, errorCallback))
434     {
435         OIC_LOG_V(INFO, TAG, "SQLite debugging log initialized.");
436     }
437     sqlite3_open_v2(OCRDDatabaseGetStorageFilename(), &gRDDB, SQLITE_OPEN_READONLY, NULL);
438     if (!gRDDB)
439     {
440         result = OC_STACK_ERROR;
441         goto exit;
442     }
443
444     const char *serverID = OCGetServerInstanceIDString();
445     const char input[] = "SELECT di, external_host FROM RD_DEVICE_LIST";
446     int inputSize = (int)sizeof(input);
447     const uint8_t di_index = 0;
448     const uint8_t external_host_index = 1;
449     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
450     while (SQLITE_ROW == sqlite3_step(stmt))
451     {
452         const unsigned char *di = sqlite3_column_text(stmt, di_index);
453         if (0 == strcmp((const char *)di, serverID))
454         {
455             continue;
456         }
457         sqlite3_int64 externalHost = sqlite3_column_int64(stmt, external_host_index);
458         *tail = OCDiscoveryPayloadCreate();
459         result = OC_STACK_INTERNAL_SERVER_ERROR;
460         VERIFY_NON_NULL(*tail);
461         (*tail)->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
462         VERIFY_NON_NULL((*tail)->sid);
463         memcpy((*tail)->sid, di, UUID_STRING_SIZE);
464         result = CheckResources(interfaceType, resourceType, externalHost ? NULL : endpoint, *tail);
465         if (OC_STACK_OK == result)
466         {
467             tail = &(*tail)->next;
468         }
469         else
470         {
471             OCPayloadDestroy((OCPayload *) *tail);
472             *tail = NULL;
473         }
474     }
475     result = head ? OC_STACK_OK : OC_STACK_NO_RESOURCE;
476
477 exit:
478     if (OC_STACK_OK != result)
479     {
480         OCPayloadDestroy((OCPayload *) head);
481         head = NULL;
482     }
483     *payload = head;
484     sqlite3_finalize(stmt);
485     sqlite3_close(gRDDB);
486     return result;
487 }
488 #endif