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