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