f0496c8b42c12cc0c3e87e9c5730d5f813e83054
[platform/upstream/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 <stdlib.h>
22 #include <string.h>
23
24 #ifdef RD_SERVER
25 #include "sqlite3.h"
26 #endif
27
28 #include "octypes.h"
29 #include "ocstack.h"
30 #include "ocrandom.h"
31 #include "logger.h"
32 #include "ocpayload.h"
33 #include "oic_malloc.h"
34 #include "oic_string.h"
35
36 #define TAG "OIC_RI_RESOURCEDIRECTORY"
37
38 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
39              TAG, #arg " is NULL"); return (retVal); } }
40
41 #ifdef RD_SERVER
42
43 #define RD_PATH "RD.db"
44
45 static sqlite3 *gRDDB = NULL;
46
47 /* Column indices of RD_DEVICE_LINK_LIST table */
48 static const uint8_t ins_index = 0;
49 static const uint8_t uri_index = 1;
50 static const uint8_t p_index = 4;
51 static const uint8_t d_index = 7;
52
53 /* Column indices of RD_LINK_RT table */
54 static const uint8_t rt_value_index = 0;
55
56 /* Column indices of RD_LINK_IF table */
57 static const uint8_t if_value_index = 0;
58
59 #define VERIFY_SQLITE(arg) \
60 if (SQLITE_OK != (arg)) \
61 { \
62     OIC_LOG_V(ERROR, TAG, "Error in " #arg ", Error Message: %s",  sqlite3_errmsg(gRDDB)); \
63     sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); \
64     return OC_STACK_ERROR; \
65 }
66
67 static void errorCallback(void *arg, int errCode, const char *errMsg)
68 {
69     OC_UNUSED(arg);
70     OC_UNUSED(errCode);
71     OC_UNUSED(errMsg);
72     OIC_LOG_V(ERROR, TAG, "SQLLite Error: %s : %d", errMsg, errCode);
73 }
74
75 static OCStackResult initializeDatabase(const char *path)
76 {
77     if (SQLITE_OK == sqlite3_config(SQLITE_CONFIG_LOG, errorCallback))
78     {
79         OIC_LOG_V(INFO, TAG, "SQLite debugging log initialized.");
80     }
81
82     sqlite3_open_v2(!path ? RD_PATH : path, &gRDDB, SQLITE_OPEN_READONLY, NULL);
83     if (!gRDDB)
84     {
85         return OC_STACK_ERROR;
86     }
87     return OC_STACK_OK;
88 }
89
90 static OCStackResult appendStringLL(OCStringLL **type, const unsigned char *value)
91 {
92     OCStringLL *temp= (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
93     if (!temp)
94     {
95         return OC_STACK_NO_MEMORY;
96     }
97     temp->value = OICStrdup((char *)value);
98     if (!temp->value)
99     {
100         return OC_STACK_NO_MEMORY;
101     }
102     temp->next = NULL;
103
104     if (!*type)
105     {
106         *type = temp;
107     }
108     else
109     {
110         OCStringLL *tmp = *type;
111         for (; tmp->next; tmp = tmp->next);
112         tmp->next = temp;
113     }
114     return OC_STACK_OK;
115 }
116
117 /* stmt is of form "SELECT * FROM RD_DEVICE_LINK_LIST ..." */
118 static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDiscoveryPayload *discPayload)
119 {
120     int res = sqlite3_step(stmt);
121     if (SQLITE_ROW != res)
122     {
123         return OC_STACK_NO_RESOURCE;
124     }
125     OCStackResult result = OC_STACK_OK;
126     OCResourcePayload *resourcePayload = NULL;
127     while (SQLITE_ROW == res)
128     {
129         resourcePayload = (OCResourcePayload *)OICCalloc(1, sizeof(OCResourcePayload));
130         if (!resourcePayload)
131         {
132             result = OC_STACK_NO_MEMORY;
133             goto exit;
134         }
135
136         int id = sqlite3_column_int(stmt, ins_index);
137         const unsigned char *uri = sqlite3_column_text(stmt, uri_index);
138         int bitmap = sqlite3_column_int(stmt, p_index);
139         int deviceId = sqlite3_column_int(stmt, d_index);
140         OIC_LOG_V(DEBUG, TAG, " %s %d", uri, deviceId);
141         resourcePayload->uri = OICStrdup((char *)uri);
142         if (!resourcePayload->uri)
143         {
144             result = OC_STACK_NO_MEMORY;
145             goto exit;
146         }
147
148         sqlite3_stmt *stmtRT = 0;
149         const char *rt = "SELECT rt FROM RD_LINK_RT WHERE LINK_ID=?";
150         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, rt, strlen(rt) + 1, &stmtRT, NULL));
151         VERIFY_SQLITE(sqlite3_bind_int(stmtRT, 1, id));
152         while (SQLITE_ROW == sqlite3_step(stmtRT))
153         {
154             const unsigned char *rt1 = sqlite3_column_text(stmtRT, rt_value_index);
155             result = appendStringLL(&resourcePayload->types, rt1);
156             if (OC_STACK_OK != result)
157             {
158                 goto exit;
159             }
160         }
161         VERIFY_SQLITE(sqlite3_finalize(stmtRT));
162
163         sqlite3_stmt *stmtIF = 0;
164         const char *itf = "SELECT if FROM RD_LINK_IF WHERE LINK_ID=?";
165         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, itf, strlen(itf) + 1, &stmtIF, NULL));
166         VERIFY_SQLITE(sqlite3_bind_int(stmtIF, 1, id));
167         while (SQLITE_ROW == sqlite3_step(stmtIF))
168         {
169             const unsigned char *itf = sqlite3_column_text(stmtIF, if_value_index);
170             result = appendStringLL(&resourcePayload->interfaces, itf);
171             if (OC_STACK_OK != result)
172             {
173                 goto exit;
174             }
175         }
176         VERIFY_SQLITE(sqlite3_finalize(stmtIF));
177
178         resourcePayload->bitmap = bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE);
179         resourcePayload->secure = (bitmap & OC_SECURE) != 0;
180
181         const char *address = "SELECT di, address FROM RD_DEVICE_LIST "
182             "INNER JOIN RD_DEVICE_LINK_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID "
183             "WHERE RD_DEVICE_LINK_LIST.DEVICE_ID=?";
184         const uint8_t di_index = 0;
185         const uint8_t address_index = 1;
186
187         sqlite3_stmt *stmt1 = 0;
188         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, address, strlen(address) + 1, &stmt1, NULL));
189         VERIFY_SQLITE(sqlite3_bind_int(stmt1, 1, deviceId));
190
191         res = sqlite3_step(stmt1);
192         if (SQLITE_ROW == res || SQLITE_DONE == res)
193         {
194             const unsigned char *di = sqlite3_column_text(stmt1, di_index);
195             const unsigned char *address = sqlite3_column_text(stmt1, address_index);
196             OIC_LOG_V(DEBUG, TAG, " %s %s", di, address);
197             discPayload->baseURI = OICStrdup((char *)address);
198             if (!discPayload->baseURI)
199             {
200                 result = OC_STACK_NO_MEMORY;
201                 goto exit;
202             }
203             discPayload->sid = OICStrdup((char *)di);
204             if (!discPayload->sid)
205             {
206                 result = OC_STACK_NO_MEMORY;
207                 goto exit;
208             }
209         }
210         VERIFY_SQLITE(sqlite3_finalize(stmt1));
211         OCDiscoveryPayloadAddNewResource(discPayload, resourcePayload);
212         res = sqlite3_step(stmt);
213     }
214 exit:
215     if (OC_STACK_OK != result)
216     {
217         OCDiscoveryResourceDestroy(resourcePayload);
218     }
219     return result;
220 }
221
222 static OCStackResult CheckResources(const char *interfaceType, const char *resourceType,
223         OCDiscoveryPayload *discPayload)
224 {
225     if (initializeDatabase(NULL) != OC_STACK_OK)
226     {
227         return OC_STACK_INTERNAL_SERVER_ERROR;
228     }
229     if (!interfaceType && !resourceType)
230     {
231         return OC_STACK_INVALID_QUERY;
232     }
233     if (!discPayload || !discPayload->sid)
234     {
235         return OC_STACK_INTERNAL_SERVER_ERROR;
236     }
237
238     OCStackResult result = OC_STACK_OK;
239     sqlite3_stmt *stmt = 0;
240     if (resourceType)
241     {
242         if (!interfaceType || 0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL))
243         {
244             const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST "
245                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
246                                 "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID "
247                                 "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_RT.rt LIKE ?2";
248             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, strlen(input) + 1, &stmt, NULL));
249             VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid),
250                                             SQLITE_STATIC));
251             VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, resourceType, strlen(resourceType), SQLITE_STATIC));
252         }
253         else
254         {
255             const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST "
256                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
257                                 "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID "
258                                 "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID "
259                                 "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_RT.rt LIKE ?2 AND RD_LINK_IF.if LIKE ?3";
260             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, strlen(input) + 1, &stmt, NULL));
261             VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid),
262                                             SQLITE_STATIC));
263             VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, resourceType, strlen(resourceType), SQLITE_STATIC));
264             VERIFY_SQLITE(sqlite3_bind_text(stmt, 3, interfaceType, strlen(interfaceType), SQLITE_STATIC));
265         }
266         result = ResourcePayloadCreate(stmt, discPayload);
267     }
268     else if (interfaceType)
269     {
270         if (0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL))
271         {
272             const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST "
273                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
274                                 "WHERE RD_DEVICE_LIST.di LIKE ?1";
275             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, strlen(input) + 1, &stmt, NULL));
276             VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid),
277                                             SQLITE_STATIC));
278         }
279         else
280         {
281             const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST "
282                                 "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
283                                 "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID "
284                                 "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_IF.if LIKE ?2";
285             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, strlen(input) + 1, &stmt, NULL));
286             VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid),
287                                             SQLITE_STATIC));
288             VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, interfaceType, strlen(interfaceType), SQLITE_STATIC));
289         }
290         result = ResourcePayloadCreate(stmt, discPayload);
291     }
292     if (stmt)
293     {
294         VERIFY_SQLITE(sqlite3_finalize(stmt));
295     }
296     return result;
297 }
298
299 OCStackResult OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType,
300         const char *resourceType,
301         OCDiscoveryPayload **payload)
302 {
303     OCStackResult result = OC_STACK_NO_RESOURCE;
304     OCDiscoveryPayload *head = NULL;
305     OCDiscoveryPayload **tail = &head;
306
307     if (*payload)
308     {
309         /*
310          * This is an error of the caller, return here instead of touching the
311          * caller provided payload.
312          */
313         OIC_LOG_V(ERROR, TAG, "Payload is already allocated");
314         return OC_STACK_INTERNAL_SERVER_ERROR;
315     }
316     if (initializeDatabase(NULL) != OC_STACK_OK)
317     {
318         goto exit;
319     }
320
321     const char *serverID = OCGetServerInstanceIDString();
322     sqlite3_stmt *stmt = 0;
323     const char *input = "SELECT di FROM RD_DEVICE_LIST";
324     const uint8_t di_index = 0;
325     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, strlen(input) + 1, &stmt, NULL));
326     while (SQLITE_ROW == sqlite3_step(stmt))
327     {
328         const unsigned char *di = sqlite3_column_text(stmt, di_index);
329         if (0 == strcmp((const char *)di, serverID))
330         {
331             continue;
332         }
333         *tail = OCDiscoveryPayloadCreate();
334         VERIFY_PARAM_NON_NULL(TAG, *tail, "Failed creating discovery payload.");
335         (*tail)->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
336         VERIFY_PARAM_NON_NULL(TAG, (*tail)->sid, "Failed adding device id to discovery payload.");
337         memcpy((*tail)->sid, di, UUID_STRING_SIZE);
338         result = CheckResources(interfaceType, resourceType, *tail);
339         if (OC_STACK_OK == result)
340         {
341             tail = &(*tail)->next;
342         }
343         else
344         {
345             OCPayloadDestroy((OCPayload *) *tail);
346             *tail = NULL;
347         }
348     }
349     VERIFY_SQLITE(sqlite3_finalize(stmt));
350     *payload = head;
351     return result;
352 exit:
353     OCPayloadDestroy((OCPayload *) *tail);
354     *payload = NULL;
355     return OC_STACK_INTERNAL_SERVER_ERROR;
356 }
357 #endif