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