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