Add timeout for discovery handle
[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
61 API int iotcon_device_info_get_property(iotcon_device_info_h device_info,
62                 iotcon_device_info_e property, char **value)
63 {
64         RETV_IF(NULL == device_info, IOTCON_ERROR_INVALID_PARAMETER);
65         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
66
67         switch (property) {
68         case IOTCON_DEVICE_INFO_NAME:
69                 *value = device_info->device_name;
70                 break;
71         case IOTCON_DEVICE_INFO_SPEC_VER:
72                 *value = device_info->spec_ver;
73                 break;
74         case IOTCON_DEVICE_INFO_ID:
75                 *value = device_info->device_id;
76                 break;
77         case IOTCON_DEVICE_INFO_DATA_MODEL_VER:
78                 *value = device_info->data_model_ver;
79                 break;
80         default:
81                 ERR("Invalid property(%d)", property);
82                 return IOTCON_ERROR_INVALID_PARAMETER;
83         }
84
85         return IOTCON_ERROR_NONE;
86 }
87
88 static void _icl_device_info_cb(GDBusConnection *connection,
89                 const gchar *sender_name,
90                 const gchar *object_path,
91                 const gchar *interface_name,
92                 const gchar *signal_name,
93                 GVariant *parameters,
94                 gpointer user_data)
95 {
96         char *uri_path;
97         struct icl_device_info info = {0};
98         icl_device_info_s *cb_container = user_data;
99         iotcon_device_info_cb cb = cb_container->cb;
100
101         if (cb_container->timeout_id)
102                 cb_container->timeout_id = 0;
103
104         g_variant_get(parameters, "(&s&s&s&s&s)", &uri_path, &info.device_name,
105                         &info.spec_ver, &info.device_id, &info.data_model_ver);
106
107         /* From iotivity, we can get uri_path. But, the value is always "/oic/d". */
108
109         if (cb)
110                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
111 }
112
113 static gboolean _icl_timeout_get_device_info(gpointer p)
114 {
115         FN_CALL;
116         icl_device_info_s *cb_container = p;
117         struct icl_device_info info = {0};
118
119         if (NULL == cb_container) {
120                 ERR("cb_container is NULL");
121                 return G_SOURCE_REMOVE;
122         }
123
124         if (cb_container->timeout_id && cb_container->cb)
125                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
126
127         icl_dbus_unsubscribe_signal(cb_container->id);
128
129         return G_SOURCE_REMOVE;
130 }
131
132 API int iotcon_get_device_info(const char *host_address,
133                 iotcon_connectivity_type_e connectivity_type,
134                 iotcon_device_info_cb cb,
135                 void *user_data)
136 {
137         int ret, timeout;
138         unsigned int sub_id;
139         GError *error = NULL;
140         icl_device_info_s *cb_container;
141         int64_t signal_number;
142         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
143
144         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
145         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
146
147         timeout = icl_dbus_get_timeout();
148
149         ic_dbus_call_get_device_info_sync(icl_dbus_get_object(),
150                         ic_utils_dbus_encode_str(host_address),
151                         connectivity_type,
152                         timeout,
153                         &signal_number,
154                         &ret,
155                         NULL,
156                         &error);
157         if (error) {
158                 ERR("ic_dbus_call_get_device_info_sync() Fail(%s)", error->message);
159                 ret = icl_dbus_convert_dbus_error(error->code);
160                 g_error_free(error);
161                 return ret;
162         }
163
164         if (IOTCON_ERROR_NONE != ret) {
165                 ERR("iotcon-daemon Fail(%d)", ret);
166                 return icl_dbus_convert_daemon_error(ret);
167         }
168
169         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_DEVICE,
170                         signal_number);
171
172         cb_container = calloc(1, sizeof(icl_device_info_s));
173         if (NULL == cb_container) {
174                 ERR("calloc() Fail(%d)", errno);
175                 return IOTCON_ERROR_OUT_OF_MEMORY;
176         }
177
178         cb_container->cb = cb;
179         cb_container->user_data = user_data;
180
181         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
182                         _icl_device_info_cb);
183         if (0 == sub_id) {
184                 ERR("icl_dbus_subscribe_signal() Fail");
185                 free(cb_container);
186                 return IOTCON_ERROR_DBUS;
187         }
188
189         cb_container->id = sub_id;
190
191         cb_container->timeout_id = g_timeout_add_seconds(timeout,
192                         _icl_timeout_get_device_info, cb_container);
193
194         return ret;
195 }
196
197 API int iotcon_platform_info_get_property(iotcon_platform_info_h platform_info,
198                 iotcon_platform_info_e property, char **value)
199 {
200         RETV_IF(NULL == platform_info, IOTCON_ERROR_INVALID_PARAMETER);
201         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
202
203         switch (property) {
204         case IOTCON_PLATFORM_INFO_ID:
205                 *value = platform_info->platform_id;
206                 break;
207         case IOTCON_PLATFORM_INFO_MANUF_NAME:
208                 *value = platform_info->manuf_name;
209                 break;
210         case IOTCON_PLATFORM_INFO_MANUF_URL:
211                 *value = platform_info->manuf_url;
212                 break;
213         case IOTCON_PLATFORM_INFO_MODEL_NUMBER:
214                 *value = platform_info->model_number;
215                 break;
216         case IOTCON_PLATFORM_INFO_DATE_OF_MANUF:
217                 *value = platform_info->date_of_manuf;
218                 break;
219         case IOTCON_PLATFORM_INFO_PLATFORM_VER:
220                 *value = platform_info->platform_ver;
221                 break;
222         case IOTCON_PLATFORM_INFO_OS_VER:
223                 *value = platform_info->os_ver;
224                 break;
225         case IOTCON_PLATFORM_INFO_HARDWARE_VER:
226                 *value = platform_info->hardware_ver;
227                 break;
228         case IOTCON_PLATFORM_INFO_FIRMWARE_VER:
229                 *value = platform_info->firmware_ver;
230                 break;
231         case IOTCON_PLATFORM_INFO_SUPPORT_URL:
232                 *value = platform_info->support_url;
233                 break;
234         case IOTCON_PLATFORM_INFO_SYSTEM_TIME:
235                 *value = platform_info->system_time;
236                 break;
237         default:
238                 ERR("Invalid property(%d)", property);
239                 return IOTCON_ERROR_INVALID_PARAMETER;
240         }
241
242         return IOTCON_ERROR_NONE;
243 }
244
245
246 static void _icl_platform_info_cb(GDBusConnection *connection,
247                 const gchar *sender_name,
248                 const gchar *object_path,
249                 const gchar *interface_name,
250                 const gchar *signal_name,
251                 GVariant *parameters,
252                 gpointer user_data)
253 {
254         char *uri_path;
255         struct icl_platform_info info = {0};
256         icl_platform_info_s *cb_container = user_data;
257         iotcon_platform_info_cb cb = cb_container->cb;
258
259         if (cb_container->timeout_id)
260                 cb_container->timeout_id = 0;
261
262         g_variant_get(parameters, "(&s&s&s&s&s&s&s&s&s&s&s&s)",
263                         &uri_path,
264                         &info.platform_id,
265                         &info.manuf_name,
266                         &info.manuf_url,
267                         &info.model_number,
268                         &info.date_of_manuf,
269                         &info.platform_ver,
270                         &info.os_ver,
271                         &info.hardware_ver,
272                         &info.firmware_ver,
273                         &info.support_url,
274                         &info.system_time);
275
276         info.manuf_url = ic_utils_dbus_decode_str(info.manuf_url);
277         info.model_number = ic_utils_dbus_decode_str(info.model_number);
278         info.date_of_manuf = ic_utils_dbus_decode_str(info.date_of_manuf);
279         info.platform_ver = ic_utils_dbus_decode_str(info.platform_ver);
280         info.os_ver = ic_utils_dbus_decode_str(info.os_ver);
281         info.hardware_ver = ic_utils_dbus_decode_str(info.hardware_ver);
282         info.firmware_ver = ic_utils_dbus_decode_str(info.firmware_ver);
283         info.support_url = ic_utils_dbus_decode_str(info.support_url);
284         info.system_time = ic_utils_dbus_decode_str(info.system_time);
285
286         /* From iotivity, we can get uri_path. But, the value is always "/oic/p". */
287
288         if (cb)
289                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
290 }
291
292 static gboolean _icl_timeout_get_platform_info(gpointer p)
293 {
294         FN_CALL;
295         icl_platform_info_s *cb_container = p;
296         struct icl_platform_info info = {0};
297
298         if (NULL == cb_container) {
299                 ERR("cb_container is NULL");
300                 return G_SOURCE_REMOVE;
301         }
302
303         if (cb_container->timeout_id && cb_container->cb)
304                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
305
306         icl_dbus_unsubscribe_signal(cb_container->id);
307
308         return G_SOURCE_REMOVE;
309 }
310
311 API int iotcon_get_platform_info(const char *host_address,
312                 iotcon_connectivity_type_e connectivity_type,
313                 iotcon_platform_info_cb cb,
314                 void *user_data)
315 {
316         int ret, timeout;
317         unsigned int sub_id;
318         GError *error = NULL;
319         icl_platform_info_s *cb_container;
320         int64_t signal_number;
321         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
322
323         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
324         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
325
326         timeout = icl_dbus_get_timeout();
327
328         ic_dbus_call_get_platform_info_sync(icl_dbus_get_object(),
329                         ic_utils_dbus_encode_str(host_address),
330                         connectivity_type,
331                         timeout,
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_%llx", 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(timeout,
370                         _icl_timeout_get_platform_info, cb_container);
371
372         return ret;
373 }