Add Tizen Info Handling API
[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, gboolean is_parent)
249 {
250         OCStringLL *node;
251         int ret, ifaces = 0;
252         GVariant *child, *value;
253         OCRepPayload *child_node;
254         iotcon_interface_e iface;
255         GVariantBuilder *repr_gvar;
256         GVariantBuilder children, types_builder;
257
258         RETV_IF(NULL == repr, NULL);
259
260         /* Resource Types */
261         g_variant_builder_init(&types_builder, G_VARIANT_TYPE("as"));
262
263         node = repr->types;
264         while (node) {
265                 g_variant_builder_add(&types_builder, "s", node->value);
266                 node = node->next;
267         }
268
269         /* Resource Interfaces */
270         node = repr->interfaces;
271         while (node) {
272                 ret = ic_utils_convert_interface_string(node->value, &iface);
273                 if (IOTCON_ERROR_NONE != ret) {
274                         ERR("ic_utils_convert_interface_string() Fail(%d)", ret);
275                         return NULL;
276                 }
277                 ifaces |= iface;
278
279                 node = node->next;
280         }
281
282         /* Representation */
283         repr_gvar = _icd_state_value_to_gvariant(repr);
284
285         /* Children */
286         g_variant_builder_init(&children, G_VARIANT_TYPE("av"));
287
288         child_node = repr->next;
289         while (is_parent && child_node) {
290                 /* generate recursively */
291                 child = _icd_payload_representation_to_gvariant(child_node, FALSE);
292                 g_variant_builder_add(&children, "v", child);
293                 child_node = child_node->next;
294         }
295
296         value = g_variant_new("(siasa{sv}av)", ic_utils_dbus_encode_str(repr->uri), ifaces,
297                         &types_builder, repr_gvar, &children);
298
299         return value;
300 }
301
302
303 static GVariant* _icd_payload_platform_to_gvariant(OCPlatformPayload *repr)
304 {
305         GVariant *value;
306
307         value = g_variant_new("(ssssssssssss)",
308                         repr->uri,
309                         repr->info.platformID,
310                         repr->info.manufacturerName,
311                         repr->info.manufacturerUrl,
312                         repr->info.modelNumber,
313                         repr->info.dateOfManufacture,
314                         repr->info.platformVersion,
315                         repr->info.operatingSystemVersion,
316                         repr->info.hardwareVersion,
317                         repr->info.firmwareVersion,
318                         repr->info.supportUrl,
319                         repr->info.systemTime);
320
321         return value;
322 }
323
324
325 static GVariant* _icd_payload_device_to_gvariant(OCDevicePayload *repr)
326 {
327         GVariant *value;
328         OCRandomUuidResult random_res;
329         char device_id[UUID_STRING_SIZE] = {0};
330
331         random_res = OCConvertUuidToString(repr->sid, device_id);
332         if (RAND_UUID_OK != random_res) {
333                 ERR("OCConvertUuidToString() Fail(%d)", random_res);
334                 return NULL;
335         }
336
337         value = g_variant_new("(sssss)", repr->uri, repr->deviceName, repr->specVersion,
338                         device_id, repr->dataModelVersion);
339
340         return value;
341 }
342
343
344 GVariant* icd_payload_to_gvariant(OCPayload *repr)
345 {
346         GVariant *value = NULL;
347
348         if (NULL == repr)
349                 return value;
350
351         switch (repr->type) {
352         case PAYLOAD_TYPE_REPRESENTATION:
353                 value = _icd_payload_representation_to_gvariant((OCRepPayload*)repr, TRUE);
354                 break;
355         case PAYLOAD_TYPE_PLATFORM:
356                 value = _icd_payload_platform_to_gvariant((OCPlatformPayload*)repr);
357                 break;
358         case PAYLOAD_TYPE_DEVICE:
359                 value = _icd_payload_device_to_gvariant((OCDevicePayload*)repr);
360                 break;
361         case PAYLOAD_TYPE_PRESENCE:
362         case PAYLOAD_TYPE_SECURITY:
363         default:
364                 break;
365         }
366
367         return value;
368 }
369
370
371 static void _icd_state_list_from_gvariant(GVariant *var,
372                 struct icd_state_list_s *value_list, int depth)
373 {
374         GVariantIter iter;
375         const GVariantType *type;
376         union icd_state_value_u *value;
377
378         type = g_variant_get_type(var);
379
380         g_variant_iter_init(&iter, var);
381
382         value_list->dimensions[depth] = g_variant_iter_n_children(&iter);
383         DBG("[%d]list dim : %d", depth, value_list->dimensions[depth]);
384
385         if (g_variant_type_equal(G_VARIANT_TYPE("ab"), type)) {
386                 bool b;
387                 value_list->type = OCREP_PROP_BOOL;
388                 while (g_variant_iter_loop(&iter, "b", &b)) {
389                         value = calloc(1, sizeof(union icd_state_value_u));
390                         if (NULL == value) {
391                                 ERR("calloc() Fail(%d)", errno);
392                                 return;
393                         }
394                         value->b = b;
395                         value_list->list = g_list_append(value_list->list, value);
396                 }
397         } else if (g_variant_type_equal(G_VARIANT_TYPE("ai"), type)) {
398                 int i;
399                 value_list->type = OCREP_PROP_INT;
400                 while (g_variant_iter_loop(&iter, "i", &i)) {
401                         value = calloc(1, sizeof(union icd_state_value_u));
402                         if (NULL == value) {
403                                 ERR("calloc() Fail(%d)", errno);
404                                 return;
405                         }
406                         value->i = i;
407                         value_list->list = g_list_append(value_list->list, value);
408                 }
409         } else if (g_variant_type_equal(G_VARIANT_TYPE("ad"), type)) {
410                 double d;
411                 value_list->type = OCREP_PROP_DOUBLE;
412                 while (g_variant_iter_loop(&iter, "d", &d)) {
413                         value = calloc(1, sizeof(union icd_state_value_u));
414                         if (NULL == value) {
415                                 ERR("calloc() Fail(%d)", errno);
416                                 return;
417                         }
418                         value->d = d;
419                         value_list->list = g_list_append(value_list->list, value);
420                 }
421         } else if (g_variant_type_equal(G_VARIANT_TYPE("as"), type)) {
422                 char *s;
423                 value_list->type = OCREP_PROP_STRING;
424                 while (g_variant_iter_next(&iter, "s", &s))
425                         value_list->list = g_list_append(value_list->list, s);
426         } else if (g_variant_type_equal(G_VARIANT_TYPE("av"), type)) {
427                 GVariant *value;
428
429                 if (g_variant_iter_loop(&iter, "v", &value)) {
430                         if (g_variant_is_of_type(value, G_VARIANT_TYPE("(siasa{sv}av)"))) {
431                                 OCRepPayload *repr_value;
432                                 value_list->type = OCREP_PROP_OBJECT;
433                                 do {
434                                         repr_value = icd_payload_representation_from_gvariant(value);
435                                         value_list->list = g_list_append(value_list->list, repr_value);
436
437                                 } while (g_variant_iter_loop(&iter, "v", &value));
438
439                         } else if (g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) {
440                                 do {
441                                         _icd_state_list_from_gvariant(value, value_list, depth + 1);
442                                 } while (g_variant_iter_loop(&iter, "v", &value));
443                         }
444                 }
445         }
446
447         return;
448 }
449
450
451 static void _icd_state_list_free(gpointer node)
452 {
453         OCRepPayloadDestroy(node);
454 }
455
456
457 static void _icd_state_array_from_list(OCRepPayload *repr,
458                 struct icd_state_list_s *value_list, const char *key)
459 {
460         int i, len;
461         GList *node;
462         bool *b_arr;
463         double *d_arr;
464         char **str_arr;
465         int64_t *i_arr;
466         union icd_state_value_u *value;
467         struct OCRepPayload **state_arr;
468
469         len = calcDimTotal(value_list->dimensions);
470
471         switch (value_list->type) {
472         case OCREP_PROP_INT:
473                 i_arr = calloc(len, sizeof(int64_t));
474                 if (NULL == i_arr) {
475                         ERR("calloc() Fail(%d)", errno);
476                         return;
477                 }
478                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
479                         value = node->data;
480                         i_arr[i] = value->i;
481                 }
482                 g_list_free_full(value_list->list, free);
483                 OCRepPayloadSetIntArrayAsOwner(repr, key, i_arr, value_list->dimensions);
484                 break;
485         case OCREP_PROP_BOOL:
486                 b_arr = calloc(len, sizeof(bool));
487                 if (NULL == b_arr) {
488                         ERR("calloc() Fail(%d)", errno);
489                         return;
490                 }
491                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
492                         value = node->data;
493                         b_arr[i] = value->b;
494                 }
495                 g_list_free_full(value_list->list, free);
496                 OCRepPayloadSetBoolArrayAsOwner(repr, key, b_arr, value_list->dimensions);
497                 break;
498         case OCREP_PROP_DOUBLE:
499                 d_arr = calloc(len, sizeof(double));
500                 if (NULL == d_arr) {
501                         ERR("calloc() Fail(%d)", errno);
502                         return;
503                 }
504                 for (node = value_list->list, i = 0; node; node = node->next, i++) {
505                         value = node->data;
506                         d_arr[i] = value->d;
507                 }
508                 g_list_free_full(value_list->list, free);
509                 OCRepPayloadSetDoubleArrayAsOwner(repr, key, d_arr, value_list->dimensions);
510                 break;
511         case OCREP_PROP_STRING:
512                 str_arr = calloc(len, sizeof(char *));
513                 if (NULL == str_arr) {
514                         ERR("calloc() Fail(%d)", errno);
515                         return;
516                 }
517                 for (node = value_list->list, i = 0; node; node = node->next, i++)
518                         str_arr[i] = strdup(node->data);
519                 g_list_free_full(value_list->list, free);
520                 OCRepPayloadSetStringArrayAsOwner(repr, key, str_arr, value_list->dimensions);
521                 break;
522         case OCREP_PROP_OBJECT:
523                 state_arr = calloc(len, sizeof(struct OCRepPayload *));
524                 if (NULL == state_arr) {
525                         ERR("calloc() Fail(%d)", errno);
526                         return;
527                 }
528                 for (node = value_list->list, i = 0; node; node = node->next, i++)
529                         state_arr[i] = OCRepPayloadClone(node->data);
530                 g_list_free_full(value_list->list, _icd_state_list_free);
531                 OCRepPayloadSetPropObjectArrayAsOwner(repr, key, state_arr,
532                                 value_list->dimensions);
533                 break;
534         case OCREP_PROP_ARRAY:
535         case OCREP_PROP_NULL:
536         default:
537                 ERR("Invalid Type");
538         }
539 }
540
541
542 static void _icd_state_value_from_gvariant(OCRepPayload *repr, GVariantIter *iter)
543 {
544         char *key;
545         GVariant *var;
546         const char *str_value;
547         OCRepPayload *repr_value;
548         struct icd_state_list_s value_list = {0};
549
550         while (g_variant_iter_loop(iter, "{sv}", &key, &var)) {
551
552                 if (g_variant_is_of_type(var, G_VARIANT_TYPE_BOOLEAN)) {
553                         OCRepPayloadSetPropBool(repr, key, g_variant_get_boolean(var));
554
555                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_INT32)) {
556                         OCRepPayloadSetPropInt(repr, key, g_variant_get_int32(var));
557
558                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_DOUBLE)) {
559                         OCRepPayloadSetPropDouble(repr, key, g_variant_get_double(var));
560
561                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_STRING)) {
562                         str_value = g_variant_get_string(var, NULL);
563                         if (IC_STR_EQUAL == strcmp(IC_STR_NULL, str_value))
564                                 OCRepPayloadSetNull(repr, key);
565                         else
566                                 OCRepPayloadSetPropString(repr, key, str_value);
567
568                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE_ARRAY)) {
569                         memset(&value_list, 0, sizeof(struct icd_state_list_s));
570                         _icd_state_list_from_gvariant(var, &value_list, 0);
571                         _icd_state_array_from_list(repr, &value_list, key);
572
573                 } else if (g_variant_is_of_type(var, G_VARIANT_TYPE("(siasa{sv}av)"))) {
574                         repr_value = icd_payload_representation_from_gvariant(var);
575                         OCRepPayloadSetPropObjectAsOwner(repr, key, repr_value);
576                 }
577         }
578
579         return;
580 }
581
582
583 OCRepPayload* icd_payload_representation_from_gvariant(GVariant *var)
584 {
585         GVariant *child;
586         int ret, i, ifaces = 0;
587         OCRepPayload *repr, *cur;
588         char *uri_path, *iface_str, *resource_type;
589         GVariantIter *resource_types, *repr_gvar, *children;
590
591         repr = OCRepPayloadCreate();
592
593         g_variant_get(var, "(&siasa{sv}av)", &uri_path, &ifaces, &resource_types, &repr_gvar,
594                         &children);
595
596         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, uri_path))
597                 OCRepPayloadSetUri(repr, uri_path);
598
599         for (i = 1; i <= IC_INTERFACE_MAX; i = i << 1) {
600                 if (IOTCON_INTERFACE_NONE == (ifaces & i)) /* this interface not exist */
601                         continue;
602                 ret = ic_utils_convert_interface_flag((ifaces & i), &iface_str);
603                 if (IOTCON_ERROR_NONE != ret) {
604                         ERR("ic_utils_convert_interface_flag(%d) Fail(%d)", i, ret);
605                         OCRepPayloadDestroy(repr);
606                         return NULL;
607                 }
608                 OCRepPayloadAddInterface(repr, iface_str);
609         }
610         while (g_variant_iter_loop(resource_types, "s", &resource_type))
611                 OCRepPayloadAddResourceType(repr, resource_type);
612
613         _icd_state_value_from_gvariant(repr, repr_gvar);
614
615         cur = repr;
616         while (g_variant_iter_loop(children, "v", &child)) {
617                 cur->next = icd_payload_representation_from_gvariant(child);
618                 cur = cur->next;
619         }
620
621         return repr;
622 }
623