Allow multiple presence
[platform/core/iot/iotcon.git] / lib / icl-device.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 <stdio.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <glib.h>
22
23 #include "iotcon.h"
24 #include "ic-utils.h"
25 #include "icl.h"
26 #include "icl-representation.h"
27 #include "icl-dbus.h"
28 #include "icl-dbus-type.h"
29 #include "icl-device.h"
30
31 /**
32  * @brief The maximum length which can be held in a manufacturer name.
33  *
34  * @since_tizen 3.0
35  */
36 #define ICL_MANUFACTURER_NAME_LENGTH_MAX 15
37
38 /**
39  * @brief The maximum length which can be held in a manufacturer url.
40  *
41  * @since_tizen 3.0
42  */
43 #define ICL_MANUFACTURER_URL_LENGTH_MAX 32
44
45
46 typedef struct {
47         iotcon_device_info_cb cb;
48         void *user_data;
49         unsigned int id;
50         int timeout_id;
51 } icl_device_info_s;
52
53 typedef struct {
54         iotcon_platform_info_cb cb;
55         void *user_data;
56         unsigned int id;
57         int timeout_id;
58 } icl_platform_info_s;
59
60 typedef struct {
61         iotcon_tizen_info_cb cb;
62         void *user_data;
63 } icl_tizen_info_s;
64
65
66 API int iotcon_device_info_get_property(iotcon_device_info_h device_info,
67                 iotcon_device_info_e property, char **value)
68 {
69         RETV_IF(NULL == device_info, IOTCON_ERROR_INVALID_PARAMETER);
70         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
71
72         switch (property) {
73         case IOTCON_DEVICE_INFO_NAME:
74                 *value = device_info->device_name;
75                 break;
76         case IOTCON_DEVICE_INFO_SPEC_VER:
77                 *value = device_info->spec_ver;
78                 break;
79         case IOTCON_DEVICE_INFO_ID:
80                 *value = device_info->device_id;
81                 break;
82         case IOTCON_DEVICE_INFO_DATA_MODEL_VER:
83                 *value = device_info->data_model_ver;
84                 break;
85         default:
86                 ERR("Invalid property(%d)", property);
87                 return IOTCON_ERROR_INVALID_PARAMETER;
88         }
89
90         return IOTCON_ERROR_NONE;
91 }
92
93 static void _icl_device_info_cb(GDBusConnection *connection,
94                 const gchar *sender_name,
95                 const gchar *object_path,
96                 const gchar *interface_name,
97                 const gchar *signal_name,
98                 GVariant *parameters,
99                 gpointer user_data)
100 {
101         char *uri_path;
102         struct icl_device_info info = {0};
103         icl_device_info_s *cb_container = user_data;
104         iotcon_device_info_cb cb = cb_container->cb;
105
106         if (cb_container->timeout_id)
107                 cb_container->timeout_id = 0;
108
109         g_variant_get(parameters, "(&s&s&s&s&s)", &uri_path, &info.device_name,
110                         &info.spec_ver, &info.device_id, &info.data_model_ver);
111
112         /* From iotivity, we can get uri_path. But, the value is always "/oic/d". */
113
114         if (cb)
115                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
116 }
117
118 static gboolean _icl_timeout_get_device_info(gpointer p)
119 {
120         FN_CALL;
121         icl_device_info_s *cb_container = p;
122         struct icl_device_info info = {0};
123
124         if (NULL == cb_container) {
125                 ERR("cb_container is NULL");
126                 return G_SOURCE_REMOVE;
127         }
128
129         if (cb_container->timeout_id && cb_container->cb)
130                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
131
132         icl_dbus_unsubscribe_signal(cb_container->id);
133
134         return G_SOURCE_REMOVE;
135 }
136
137 API int iotcon_get_device_info(const char *host_address,
138                 iotcon_connectivity_type_e connectivity_type,
139                 iotcon_device_info_cb cb,
140                 void *user_data)
141 {
142         int ret;
143         unsigned int sub_id;
144         GError *error = NULL;
145         icl_device_info_s *cb_container;
146         int64_t signal_number;
147         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
148
149         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
150         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
151
152         signal_number = icl_dbus_generate_signal_number();
153
154         ic_dbus_call_get_device_info_sync(icl_dbus_get_object(),
155                         ic_utils_dbus_encode_str(host_address),
156                         connectivity_type,
157                         signal_number,
158                         &ret,
159                         NULL,
160                         &error);
161         if (error) {
162                 ERR("ic_dbus_call_get_device_info_sync() Fail(%s)", error->message);
163                 ret = icl_dbus_convert_dbus_error(error->code);
164                 g_error_free(error);
165                 return ret;
166         }
167
168         if (IOTCON_ERROR_NONE != ret) {
169                 ERR("iotcon-daemon Fail(%d)", ret);
170                 return icl_dbus_convert_daemon_error(ret);
171         }
172
173         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_DEVICE,
174                         signal_number);
175
176         cb_container = calloc(1, sizeof(icl_device_info_s));
177         if (NULL == cb_container) {
178                 ERR("calloc() Fail(%d)", errno);
179                 return IOTCON_ERROR_OUT_OF_MEMORY;
180         }
181
182         cb_container->cb = cb;
183         cb_container->user_data = user_data;
184
185         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
186                         _icl_device_info_cb);
187         if (0 == sub_id) {
188                 ERR("icl_dbus_subscribe_signal() Fail");
189                 free(cb_container);
190                 return IOTCON_ERROR_DBUS;
191         }
192
193         cb_container->id = sub_id;
194
195         cb_container->timeout_id = g_timeout_add_seconds(icl_dbus_get_timeout(),
196                         _icl_timeout_get_device_info, cb_container);
197
198         return ret;
199 }
200
201 API int iotcon_platform_info_get_property(iotcon_platform_info_h platform_info,
202                 iotcon_platform_info_e property, char **value)
203 {
204         RETV_IF(NULL == platform_info, IOTCON_ERROR_INVALID_PARAMETER);
205         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
206
207         switch (property) {
208         case IOTCON_PLATFORM_INFO_ID:
209                 *value = platform_info->platform_id;
210                 break;
211         case IOTCON_PLATFORM_INFO_MANUF_NAME:
212                 *value = platform_info->manuf_name;
213                 break;
214         case IOTCON_PLATFORM_INFO_MANUF_URL:
215                 *value = platform_info->manuf_url;
216                 break;
217         case IOTCON_PLATFORM_INFO_MODEL_NUMBER:
218                 *value = platform_info->model_number;
219                 break;
220         case IOTCON_PLATFORM_INFO_DATE_OF_MANUF:
221                 *value = platform_info->date_of_manuf;
222                 break;
223         case IOTCON_PLATFORM_INFO_PLATFORM_VER:
224                 *value = platform_info->platform_ver;
225                 break;
226         case IOTCON_PLATFORM_INFO_OS_VER:
227                 *value = platform_info->os_ver;
228                 break;
229         case IOTCON_PLATFORM_INFO_HARDWARE_VER:
230                 *value = platform_info->hardware_ver;
231                 break;
232         case IOTCON_PLATFORM_INFO_FIRMWARE_VER:
233                 *value = platform_info->firmware_ver;
234                 break;
235         case IOTCON_PLATFORM_INFO_SUPPORT_URL:
236                 *value = platform_info->support_url;
237                 break;
238         case IOTCON_PLATFORM_INFO_SYSTEM_TIME:
239                 *value = platform_info->system_time;
240                 break;
241         default:
242                 ERR("Invalid property(%d)", property);
243                 return IOTCON_ERROR_INVALID_PARAMETER;
244         }
245
246         return IOTCON_ERROR_NONE;
247 }
248
249
250 static void _icl_platform_info_cb(GDBusConnection *connection,
251                 const gchar *sender_name,
252                 const gchar *object_path,
253                 const gchar *interface_name,
254                 const gchar *signal_name,
255                 GVariant *parameters,
256                 gpointer user_data)
257 {
258         char *uri_path;
259         struct icl_platform_info info = {0};
260         icl_platform_info_s *cb_container = user_data;
261         iotcon_platform_info_cb cb = cb_container->cb;
262
263         if (cb_container->timeout_id)
264                 cb_container->timeout_id = 0;
265
266         g_variant_get(parameters, "(&s&s&s&s&s&s&s&s&s&s&s&s)",
267                         &uri_path,
268                         &info.platform_id,
269                         &info.manuf_name,
270                         &info.manuf_url,
271                         &info.model_number,
272                         &info.date_of_manuf,
273                         &info.platform_ver,
274                         &info.os_ver,
275                         &info.hardware_ver,
276                         &info.firmware_ver,
277                         &info.support_url,
278                         &info.system_time);
279
280         info.manuf_url = ic_utils_dbus_decode_str(info.manuf_url);
281         info.model_number = ic_utils_dbus_decode_str(info.model_number);
282         info.date_of_manuf = ic_utils_dbus_decode_str(info.date_of_manuf);
283         info.platform_ver = ic_utils_dbus_decode_str(info.platform_ver);
284         info.os_ver = ic_utils_dbus_decode_str(info.os_ver);
285         info.hardware_ver = ic_utils_dbus_decode_str(info.hardware_ver);
286         info.firmware_ver = ic_utils_dbus_decode_str(info.firmware_ver);
287         info.support_url = ic_utils_dbus_decode_str(info.support_url);
288         info.system_time = ic_utils_dbus_decode_str(info.system_time);
289
290         /* From iotivity, we can get uri_path. But, the value is always "/oic/p". */
291
292         if (cb)
293                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
294 }
295
296 static gboolean _icl_timeout_get_platform_info(gpointer p)
297 {
298         FN_CALL;
299         icl_platform_info_s *cb_container = p;
300         struct icl_platform_info info = {0};
301
302         if (NULL == cb_container) {
303                 ERR("cb_container is NULL");
304                 return G_SOURCE_REMOVE;
305         }
306
307         if (cb_container->timeout_id && cb_container->cb)
308                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
309
310         icl_dbus_unsubscribe_signal(cb_container->id);
311
312         return G_SOURCE_REMOVE;
313 }
314
315 API int iotcon_get_platform_info(const char *host_address,
316                 iotcon_connectivity_type_e connectivity_type,
317                 iotcon_platform_info_cb cb,
318                 void *user_data)
319 {
320         int ret;
321         unsigned int sub_id;
322         GError *error = NULL;
323         icl_platform_info_s *cb_container;
324         int64_t signal_number;
325         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
326
327         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
328         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
329
330         signal_number = icl_dbus_generate_signal_number();
331
332         ic_dbus_call_get_platform_info_sync(icl_dbus_get_object(),
333                         ic_utils_dbus_encode_str(host_address),
334                         connectivity_type,
335                         signal_number,
336                         &ret,
337                         NULL,
338                         &error);
339         if (error) {
340                 ERR("ic_dbus_call_get_platform_info_sync() Fail(%s)", error->message);
341                 ret = icl_dbus_convert_dbus_error(error->code);
342                 g_error_free(error);
343                 return ret;
344         }
345
346         if (IOTCON_ERROR_NONE != ret) {
347                 ERR("iotcon-daemon Fail(%d)", ret);
348                 return icl_dbus_convert_daemon_error(ret);
349         }
350
351         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_PLATFORM,
352                         signal_number);
353
354         cb_container = calloc(1, sizeof(icl_platform_info_s));
355         if (NULL == cb_container) {
356                 ERR("calloc() Fail(%d)", errno);
357                 return IOTCON_ERROR_OUT_OF_MEMORY;
358         }
359
360         cb_container->cb = cb;
361         cb_container->user_data = user_data;
362
363         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
364                         _icl_platform_info_cb);
365         if (0 == sub_id) {
366                 ERR("icl_dbus_subscribe_signal() Fail");
367                 free(cb_container);
368                 return IOTCON_ERROR_DBUS;
369         }
370
371         cb_container->id = sub_id;
372         cb_container->timeout_id = g_timeout_add_seconds(icl_dbus_get_timeout(),
373                         _icl_timeout_get_platform_info, cb_container);
374
375         return ret;
376 }
377
378
379 static void _icl_tizen_info_cb(GObject *object, GAsyncResult *g_async_res,
380                 gpointer user_data)
381 {
382         int res;
383         GVariant *result;
384         char *device_name;
385         char *tizen_device_id;
386         GError *error = NULL;
387         struct icl_tizen_info info = {0};
388         icl_tizen_info_s *cb_container = user_data;
389         iotcon_tizen_info_cb cb = cb_container->cb;
390
391         ic_dbus_call_get_tizen_info_finish(IC_DBUS(object), &result, g_async_res, &error);
392         if (error) {
393                 ERR("ic_dbus_call_get_tizen_info_finish() Fail(%s)", error->message);
394                 if (cb) {
395                         int ret = icl_dbus_convert_dbus_error(error->code);
396                         cb(&info, ret, cb_container->user_data);
397                 }
398                 g_error_free(error);
399                 /* TODO contain time out error */
400                 free(cb_container);
401                 return;
402         }
403
404         g_variant_get(result, "(&s&si)", &device_name, &tizen_device_id, &res);
405
406         if (IOTCON_ERROR_NONE == res && NULL != ic_utils_dbus_decode_str(tizen_device_id)) {
407                 info.device_name = ic_utils_dbus_decode_str(device_name);
408                 info.tizen_device_id = tizen_device_id;
409         }
410
411         if (cb)
412                 cb(&info, res, cb_container->user_data);
413
414         free(cb_container);
415 }
416
417
418 API int iotcon_get_tizen_info(const char *host_address,
419                 iotcon_connectivity_type_e connectivity_type,
420                 iotcon_tizen_info_cb cb,
421                 void *user_data)
422 {
423         icl_tizen_info_s *cb_container;
424
425         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
426         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
427         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
428
429         cb_container = calloc(1, sizeof(icl_tizen_info_s));
430         if (NULL == cb_container) {
431                 ERR("calloc() Fail(%d)", errno);
432                 return IOTCON_ERROR_OUT_OF_MEMORY;
433         }
434
435         cb_container->cb = cb;
436         cb_container->user_data = user_data;
437
438         ic_dbus_call_get_tizen_info(icl_dbus_get_object(), host_address, connectivity_type,
439                         NULL, _icl_tizen_info_cb, cb_container);
440
441         return IOTCON_ERROR_NONE;
442 }
443
444
445 API int iotcon_tizen_info_get_property(iotcon_tizen_info_h tizen_info,
446                 iotcon_tizen_info_e property, char **value)
447 {
448         RETV_IF(NULL == tizen_info, IOTCON_ERROR_INVALID_PARAMETER);
449         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
450
451         switch (property) {
452         case IOTCON_TIZEN_INFO_DEVICE_NAME:
453                 *value = tizen_info->device_name;
454                 break;
455         case IOTCON_TIZEN_INFO_TIZEN_DEVICE_ID:
456                 *value = tizen_info->tizen_device_id;
457                 break;
458         default:
459                 ERR("Invalid property(%d)", property);
460                 return IOTCON_ERROR_INVALID_PARAMETER;
461         }
462
463         return IOTCON_ERROR_NONE;
464 }