Resource Encapsulation
[platform/core/iot/iotcon.git] / daemon / icd-payload.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <glib.h>
19
20 #include <ocstack.h>
21 #include <octypes.h>
22 #include <ocpayload.h>
23 #include <ocrandom.h>
24
25 #include "iotcon.h"
26 #include "ic-utils.h"
27 #include "icd.h"
28 #include "icd-ioty.h"
29 #include "icd-payload.h"
30
31 union icd_state_value_u {
32         int i;
33         double d;
34         bool b;
35 };
36
37 struct icd_state_list_s {
38         OCRepPayloadPropType type;
39         size_t dimensions[MAX_REP_ARRAY_DEPTH];
40         GList *list;
41 };
42
43 static GVariant* _icd_payload_representation_to_gvariant(OCRepPayload *repr, gboolean is_parent);
44
45 GVariant** icd_payload_res_to_gvariant(OCPayload *payload, OCDevAddr *dev_addr)
46 {
47         int port = 0;
48         int ifaces = 0;
49         GVariant **value;
50         OCStringLL *node;
51         iotcon_interface_e iface;
52         GVariantBuilder types;
53         OCRandomUuidResult random_res;
54         OCDiscoveryPayload *discovered;
55         struct OCResourcePayload *resource;
56         int i, is_observable, ret, res_count;
57         char device_id[UUID_STRING_SIZE] = {0};
58
59         discovered = (OCDiscoveryPayload*)payload;
60         resource = discovered->resources;
61
62         res_count = OCDiscoveryPayloadGetResourceCount(discovered);
63
64         value = calloc(res_count, sizeof(GVariant*));
65         if (NULL == value) {
66                 ERR("calloc() Fail(%d)", errno);
67                 return NULL;
68         }
69         for (i = 0; resource; i++) {
70                 /* uri path */
71                 if (NULL == resource->uri) {
72                         ERR("resource uri is NULL");
73                         resource = resource->next;
74                 }
75
76                 /* device id */
77                 random_res = OCConvertUuidToString(resource->sid, device_id);
78                 if (RAND_UUID_OK != random_res) {
79                         ERR("OCConvertUuidToString() Fail(%d)", random_res);
80                         resource = resource->next;
81                 }
82
83                 /* Resource Types */
84                 g_variant_builder_init(&types, G_VARIANT_TYPE("as"));
85                 node = resource->types;
86                 if (NULL == node) {
87                         ERR("resource types is NULL");
88                         resource = resource->next;
89                 }
90                 while (node) {
91                         g_variant_builder_add(&types, "s", node->value);
92                         node = node->next;
93                 }
94
95                 /* Resource Interfaces */
96                 node = resource->interfaces;
97                 if (NULL == node) {
98                         ERR("resource interfaces is NULL");
99                         resource = resource->next;
100                 }
101                 while (node) {
102                         ret = ic_utils_convert_interface_string(node->value, &iface);
103                         if (IOTCON_ERROR_NONE != ret) {
104                                 ERR("ic_utils_convert_interface_string() Fail(%d)", ret);
105                                 resource = resource->next;
106                         }
107                         ifaces |= iface;
108
109                         node = node->next;
110                 }
111
112                 /* is_observable */
113                 is_observable = resource->bitmap & OC_OBSERVABLE;
114
115                 /* port */
116                 port = (resource->port)? resource->port:dev_addr->port;
117
118                 value[i] = g_variant_new("(ssiasibsi)", resource->uri, device_id, ifaces, &types,
119                                 is_observable, resource->secure, dev_addr->addr, port);
120                 DBG("found resource[%d] : %s", i, g_variant_print(value[i], FALSE));
121
122                 resource = resource->next;
123         }
124
125         return value;
126 }
127
128
129 static GVariant* _icd_state_array_attr_to_gvariant(OCRepPayloadValueArray *arr, int len,
130                 int index)
131 {
132         int i;
133         GVariant *var;
134         GVariantBuilder builder;
135
136         g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
137
138         switch (arr->type) {
139         case OCREP_PROP_INT:
140                 for (i = 0; i < len; i++)
141                         g_variant_builder_add(&builder, "i", arr->iArray[index + i]);
142                 break;
143         case OCREP_PROP_BOOL:
144                 for (i = 0; i < len; i++)
145                         g_variant_builder_add(&builder, "b", arr->bArray[index + i]);
146                 break;
147         case OCREP_PROP_DOUBLE:
148                 for (i = 0; i < len; i++)
149                         g_variant_builder_add(&builder, "d", arr->dArray[index + i]);
150                 break;
151         case OCREP_PROP_STRING:
152                 for (i = 0; i < len; i++)
153                         g_variant_builder_add(&builder, "s", arr->strArray[index + i]);
154                 break;
155         case OCREP_PROP_NULL:
156                 for (i = 0; i < len; i++)
157                         g_variant_builder_add(&builder, "s", IC_STR_NULL);
158                 break;
159         case OCREP_PROP_OBJECT:
160                 for (i = 0; i < len; i++) {
161                         var = _icd_payload_representation_to_gvariant(arr->objArray[index + i], TRUE);
162                         g_variant_builder_add(&builder, "v", var);
163                 }
164                 break;
165         case OCREP_PROP_ARRAY:
166         default:
167                 break;
168         }
169
170         return g_variant_builder_end(&builder);
171 }
172
173
174 static GVariant* _icd_state_array_to_gvariant(OCRepPayloadValueArray *arr,
175                 int current_depth, int current_len, int index)
176 {
177         int i, next_len;
178         GVariantBuilder builder;
179         GVariant *arr_var = NULL;
180
181         if ((MAX_REP_ARRAY_DEPTH - 1) == current_depth
182                         || 0 == arr->dimensions[current_depth + 1])
183                 return _icd_state_array_attr_to_gvariant(arr, current_len, index);
184
185         i = current_len + index;
186
187         next_len = current_len / arr->dimensions[current_depth];
188         index -= next_len;
189
190         g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
191
192         while ((index += next_len) < i) {
193                 arr_var = _icd_state_array_to_gvariant(arr, current_depth + 1, next_len, index);
194                 g_variant_builder_add(&builder, "v", arr_var);
195         }
196
197         return g_variant_builder_end(&builder);
198 }
199
200
201 static GVariantBuilder* _icd_state_value_to_gvariant(OCRepPayload *repr)
202 {
203         int total_len;
204         GVariant *var = NULL;
205         GVariantBuilder *builder;
206         OCRepPayloadValue *val = repr->values;
207
208         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
209
210         while (val) {
211                 switch (val->type) {
212                 case OCREP_PROP_INT:
213                         var = g_variant_new_int32(val->i);
214                         break;
215                 case OCREP_PROP_BOOL:
216                         var = g_variant_new_boolean(val->b);
217                         break;
218                 case OCREP_PROP_DOUBLE:
219                         var = g_variant_new_double(val->d);
220                         break;
221                 case OCREP_PROP_STRING:
222                         var = g_variant_new_string(val->str);
223                         break;
224                 case OCREP_PROP_NULL:
225                         var = g_variant_new_string(IC_STR_NULL);
226                         break;
227                 case OCREP_PROP_ARRAY:
228                         total_len = calcDimTotal(val->arr.dimensions);
229                         var = _icd_state_array_to_gvariant(&(val->arr), 0, total_len, 0);
230                         break;
231                 case OCREP_PROP_OBJECT:
232                         var = _icd_payload_representation_to_gvariant(val->obj, TRUE);
233                         break;
234                 default:
235                         ERR("Invalid Type");
236                 }
237                 if (var) {
238                         g_variant_builder_add(builder, "{sv}", val->name, var);
239                         var = NULL;
240                 }
241                 val = val->next;
242         }
243
244         return builder;
245 }
246
247
248 static GVariant* _icd_payload_representation_to_gvariant(OCRepPayload *repr,
249                 gboolean is_parent)
250 {
251         OCStringLL *node;
252         int ret, ifaces = 0;
253         GVariant *child, *value;
254         OCRepPayload *child_node;
255         iotcon_interface_e iface;
256         GVariantBuilder *repr_gvar;
257         GVariantBuilder children, types_builder;
258
259         RETV_IF(NULL == repr, NULL);
260
261         /* Resource Types */
262         g_variant_builder_init(&types_builder, G_VARIANT_TYPE("as"));
263
264         node = repr->types;
265         while (node) {
266                 g_variant_builder_add(&types_builder, "s", node->value);
267                 node = node->next;
268         }
269
270         /* Resource Interfaces */
271         node = repr->interfaces;
272         while (node) {
273                 ret = ic_utils_convert_interface_string(node->value, &iface);
274                 if (IOTCON_ERROR_NONE != ret) {
275                         ERR("ic_utils_convert_interface_string() Fail(%d)", ret);
276                         return NULL;
277                 }
278                 ifaces |= iface;
279
280                 node = node->next;
281         }
282
283         /* Representation */
284         repr_gvar = _icd_state_value_to_gvariant(repr);
285
286         /* Children */
287         g_variant_builder_init(&children, G_VARIANT_TYPE("av"));
288
289         child_node = repr->next;
290         while (is_parent && child_node) {
291                 /* generate recursively */
292                 child = _icd_payload_representation_to_gvariant(child_node, FALSE);
293                 g_variant_builder_add(&children, "v", child);
294                 child_node = child_node->next;
295         }
296
297         value = g_variant_new("(siasa{sv}av)", ic_utils_dbus_encode_str(repr->uri), ifaces,
298                         &types_builder, repr_gvar, &children);
299
300         return value;
301 }
302
303
304 GVariant* icd_payload_representation_empty_gvariant(void)
305 {
306         GVariant *value;
307         GVariantBuilder types, repr, children;
308
309         g_variant_builder_init(&types, G_VARIANT_TYPE("as"));
310         g_variant_builder_init(&repr, G_VARIANT_TYPE("a{sv}"));
311         g_variant_builder_init(&children, G_VARIANT_TYPE("av"));
312
313         value = g_variant_new("(siasa{sv}av)", IC_STR_NULL, 0, &types, &repr, &children);
314
315         return value;
316 }
317
318
319 static GVariant* _icd_payload_platform_to_gvariant(OCPlatformPayload *repr)
320 {
321         GVariant *value;
322
323         value = g_variant_new("(ssssssssssss)",
324                         repr->uri,
325                         repr->info.platformID,
326                         repr->info.manufacturerName,
327                         repr->info.manufacturerUrl,
328                         repr->info.modelNumber,
329                         repr->info.dateOfManufacture,
330                         repr->info.platformVersion,
331                         repr->info.operatingSystemVersion,
332                         repr->info.hardwareVersion,
333                         repr->info.firmwareVersion,
334                         repr->info.supportUrl,
335                         repr->info.systemTime);
336
337         return value;
338 }
339
340
341 static GVariant* _icd_payload_device_to_gvariant(OCDevicePayload *repr)
342 {
343         GVariant *value;
344         OCRandomUuidResult random_res;
345         char device_id[UUID_STRING_SIZE] = {0};
346
347         random_res = OCConvertUuidToString(repr->sid, device_id);
348         if (RAND_UUID_OK != random_res) {
349                 ERR("OCConvertUuidToString() Fail(%d)", random_res);
350                 return NULL;
351         }
352
353         value = g_variant_new("(sssss)", repr->uri, repr->deviceName, repr->specVersion,
354                         device_id, repr->dataModelVersion);
355
356         return value;
357 }
358
359
360 GVariant* icd_payload_to_gvariant(OCPayload *repr)
361 {
362         GVariant *value = NULL;
363
364         if (NULL == repr)
365                 return value;
366
367         switch (repr->type) {
368         case PAYLOAD_TYPE_REPRESENTATION:
369                 value = _icd_payload_representation_to_gvariant((OCRepPayload*)repr, TRUE);
370                 break;
371         case PAYLOAD_TYPE_PLATFORM:
372                 value = _icd_payload_platform_to_gvariant((OCPlatformPayload*)repr);
373                 break;
374         case PAYLOAD_TYPE_DEVICE:
375                 value = _icd_payload_device_to_gvariant((OCDevicePayload*)repr);
376                 break;
377         case PAYLOAD_TYPE_PRESENCE:
378         case PAYLOAD_TYPE_SECURITY:
379         default:
380                 break;
381         }
382
383         return value;
384 }
385
386
387 static void _icd_state_list_from_gvariant(GVariant *var,
388                 struct icd_state_list_s *value_list, int depth)
389 {
390         GVariantIter iter;
391         const GVariantType *type;
392         union icd_state_value_u *value;
393
394         type = g_variant_get_type(var);
395
396         g_variant_iter_init(&iter, var);
397
398         value_list->dimensions[depth] = g_variant_iter_n_children(&iter);
399         DBG("[%d]list dim : %d", depth, value_list->dimensions[depth]);
400
401         if (g_variant_type_equal(G_VARIANT_TYPE("ab"), type)) {
402                 bool b;
403                 value_list->type = OCREP_PROP_BOOL;
404                 while (g_variant_iter_loop(&iter, "b", &b)) {
405                         value = calloc(1, sizeof(union icd_state_value_u));
406                         if (NULL == value) {
407                                 ERR("calloc() Fail(%d)", errno);
408                                 return;
409                         }
410                         value->b = b;
411                         value_list->list = g_list_append(value_list->list, value);
412                 }
413         } else if (g_variant_type_equal(G_VARIANT_TYPE("ai"), type)) {
414                 int i;
415                 value_list->type = OCREP_PROP_INT;
416                 while (g_variant_iter_loop(&iter, "i", &i)) {
417                         value = calloc(1, sizeof(union icd_state_value_u));
418                         if (NULL == value) {
419                                 ERR("calloc() Fail(%d)", errno);
420                                 return;
421                         }
422                         value->i = i;
423                         value_list->list = g_list_append(value_list->list, value);
424                 }
425         } else if (g_variant_type_equal(G_VARIANT_TYPE("ad"), type)) {
426                 double d;
427                 value_list->type = OCREP_PROP_DOUBLE;
428                 while (g_variant_iter_loop(&iter, "d", &d)) {
429                         value = calloc(1, sizeof(union icd_state_value_u));
430                         if (NULL == value) {
431                                 ERR("calloc() Fail(%d)", errno);
432                                 return;
433                         }
434                         value->d = d;
435                         value_list->list = g_list_append(value_list->list, value);
436                 }
437         } else if (g_variant_type_equal(G_VARIANT_TYPE("as"), type)) {
438                 char *s;
439                 value_list->type = OCREP_PROP_STRING;
440                 while (g_variant_iter_next(&iter, "s", &s))
441                         value_list->list = g_list_append(value_list->list, s);
442         } else if (g_variant_type_equal(G_VARIANT_TYPE("av"), type)) {
443                 GVariant *value;
444
445                 if (g_variant_iter_loop(&iter, "v", &value)) {
446                         if (g_variant_is_of_type(value, G_VARIANT_TYPE("(siasa{sv}av)"))) {
447                                 OCRepPayload *repr_value;
448                                 value_list->type = OCREP_PROP_OBJECT;
449                                 do {
450                                         repr_value = icd_payload_representation_from_gvariant(value);
451                                         value_list->list = g_list_append(value_list->list, repr_value);
452
453                                 } while (g_variant_iter_loop(&iter, "v", &value));
454
455                         } else if (g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) {
456                                 do {
457                                         _icd_state_list_from_gvariant(value, value_list, depth + 1);
458                                 } while (g_variant_iter_loop(&iter, "v", &value));
459                         }
460                 }
461         }
462
463         return;
464 }
465
466
467 static void _icd_state_list_free(gpointer node)
468 {
469         OCRepPayloadDestroy(node);
470 }
471
472
473 static void _icd_state_array_from_list(OCRepPayload *repr,
474                 struct icd_state_list_s *value_list, const char *key)
475 {
476         int i, len;
477         GList *node;
478         bool *b_arr;
479         double *d_arr;
480         char **str_arr;
481         int64_t *i_arr;
482         union icd_state_value_u *value;
483         struct OCRepPayload **state_arr;
484
485         len = calcDimTotal(value_list->dimensions);
486
487         switch (value_list->type) {
488         case OCREP_PROP_INT:
489                 i_arr = calloc(len, sizeof(int64_t));
490                 if (NULL == i_arr) {
491                         ERR("calloc() Fail(%d)", errno);
492                         return;
493                 }
494                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
495                         value = node->data;
496                         i_arr[i] = value->i;
497                 }
498                 g_list_free_full(value_list->list, free);
499                 OCRepPayloadSetIntArrayAsOwner(repr, key, i_arr, value_list->dimensions);
500                 break;
501         case OCREP_PROP_BOOL:
502                 b_arr = calloc(len, sizeof(bool));
503                 if (NULL == b_arr) {
504                         ERR("calloc() Fail(%d)", errno);
505                         return;
506                 }
507                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
508                         value = node->data;
509                         b_arr[i] = value->b;
510                 }
511                 g_list_free_full(value_list->list, free);
512                 OCRepPayloadSetBoolArrayAsOwner(repr, key, b_arr, value_list->dimensions);
513                 break;
514         case OCREP_PROP_DOUBLE:
515                 d_arr = calloc(len, sizeof(double));
516                 if (NULL == d_arr) {
517                         ERR("calloc() Fail(%d)", errno);
518                         return;
519                 }
520                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
521                         value = node->data;
522                         d_arr[i] = value->d;
523                 }
524                 g_list_free_full(value_list->list, free);
525                 OCRepPayloadSetDoubleArrayAsOwner(repr, key, d_arr, value_list->dimensions);
526                 break;
527         case OCREP_PROP_STRING:
528                 str_arr = calloc(len, sizeof(char *));
529                 if (NULL == str_arr) {
530                         ERR("calloc() Fail(%d)", errno);
531                         return;
532                 }
533                 for (node = value_list->list, i = 0; node; node = node->next, i++)
534                         str_arr[i] = strdup(node->data);
535                 g_list_free_full(value_list->list, free);
536                 OCRepPayloadSetStringArrayAsOwner(repr, key, str_arr, value_list->dimensions);
537                 break;
538         case OCREP_PROP_OBJECT:
539                 state_arr = calloc(len, sizeof(struct OCRepPayload *));
540                 if (NULL == state_arr) {
541                         ERR("calloc() Fail(%d)", errno);
542                         return;
543                 }
544                 for (node = value_list->list, i = 0; node; node = node->next, i++)
545                         state_arr[i] = OCRepPayloadClone(node->data);
546                 g_list_free_full(value_list->list, _icd_state_list_free);
547                 OCRepPayloadSetPropObjectArrayAsOwner(repr, key, state_arr,
548                                 value_list->dimensions);
549                 break;
550         case OCREP_PROP_ARRAY:
551         case OCREP_PROP_NULL:
552         default:
553                 ERR("Invalid Type");
554         }
555 }
556
557
558 static void _icd_state_value_from_gvariant(OCRepPayload *repr, GVariantIter *iter)
559 {
560         char *key;
561         GVariant *var;
562         const char *str_value;
563         OCRepPayload *repr_value;
564         struct icd_state_list_s value_list = {0};
565
566         while (g_variant_iter_loop(iter, "{sv}", &key, &var)) {
567
568                 if (g_variant_is_of_type(var, G_VARIANT_TYPE_BOOLEAN)) {
569                         OCRepPayloadSetPropBool(repr, key, g_variant_get_boolean(var));
570
571                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_INT32)) {
572                         OCRepPayloadSetPropInt(repr, key, g_variant_get_int32(var));
573
574                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_DOUBLE)) {
575                         OCRepPayloadSetPropDouble(repr, key, g_variant_get_double(var));
576
577                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_STRING)) {
578                         str_value = g_variant_get_string(var, NULL);
579                         if (IC_STR_EQUAL == strcmp(IC_STR_NULL, str_value))
580                                 OCRepPayloadSetNull(repr, key);
581                         else
582                                 OCRepPayloadSetPropString(repr, key, str_value);
583
584                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_ARRAY)) {
585                         memset(&value_list, 0, sizeof(struct icd_state_list_s));
586                         _icd_state_list_from_gvariant(var, &value_list, 0);
587                         _icd_state_array_from_list(repr, &value_list, key);
588
589                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE("(siasa{sv}av)"))) {
590                         repr_value = icd_payload_representation_from_gvariant(var);
591                         OCRepPayloadSetPropObjectAsOwner(repr, key, repr_value);
592                 }
593         }
594
595         return;
596 }
597
598
599 OCRepPayload* icd_payload_representation_from_gvariant(GVariant *var)
600 {
601         GVariant *child;
602         int ret, i, ifaces = 0;
603         OCRepPayload *repr, *cur;
604         char *uri_path, *iface_str, *resource_type;
605         GVariantIter *resource_types, *repr_gvar, *children;
606
607         repr = OCRepPayloadCreate();
608
609         g_variant_get(var, "(&siasa{sv}av)", &uri_path, &ifaces, &resource_types, &repr_gvar,
610                         &children);
611
612         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, uri_path))
613                 OCRepPayloadSetUri(repr, uri_path);
614
615         for (i = 1; i <= IC_INTERFACE_MAX; i = i << 1) {
616                 if (IOTCON_INTERFACE_NONE == (ifaces & i)) /* this interface not exist */
617                         continue;
618                 ret = ic_utils_convert_interface_flag((ifaces & i), &iface_str);
619                 if (IOTCON_ERROR_NONE != ret) {
620                         ERR("ic_utils_convert_interface_flag(%d) Fail(%d)", i, ret);
621                         OCRepPayloadDestroy(repr);
622                         return NULL;
623                 }
624                 OCRepPayloadAddInterface(repr, iface_str);
625         }
626         while (g_variant_iter_loop(resource_types, "s", &resource_type))
627                 OCRepPayloadAddResourceType(repr, resource_type);
628
629         _icd_state_value_from_gvariant(repr, repr_gvar);
630
631         cur = repr;
632         while (g_variant_iter_loop(children, "v", &child)) {
633                 cur->next = icd_payload_representation_from_gvariant(child);
634                 cur = cur->next;
635         }
636
637         return repr;
638 }
639