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