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