fix the problem when structures are destoried, repeatedly
[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         cb_container->id = 0;
129
130         return G_SOURCE_REMOVE;
131 }
132
133 API int iotcon_get_device_info(const char *host_address,
134                 iotcon_connectivity_type_e connectivity_type,
135                 iotcon_device_info_cb cb,
136                 void *user_data)
137 {
138         int ret, timeout;
139         unsigned int sub_id;
140         GError *error = NULL;
141         icl_device_info_s *cb_container;
142         int64_t signal_number;
143         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
144
145         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
146         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
147
148         timeout = icl_dbus_get_timeout();
149
150         ic_dbus_call_get_device_info_sync(icl_dbus_get_object(),
151                         ic_utils_dbus_encode_str(host_address),
152                         connectivity_type,
153                         timeout,
154                         &signal_number,
155                         &ret,
156                         NULL,
157                         &error);
158         if (error) {
159                 ERR("ic_dbus_call_get_device_info_sync() Fail(%s)", error->message);
160                 ret = icl_dbus_convert_dbus_error(error->code);
161                 g_error_free(error);
162                 return ret;
163         }
164
165         if (IOTCON_ERROR_NONE != ret) {
166                 ERR("iotcon-daemon Fail(%d)", ret);
167                 return icl_dbus_convert_daemon_error(ret);
168         }
169
170         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_DEVICE,
171                         signal_number);
172
173         cb_container = calloc(1, sizeof(icl_device_info_s));
174         if (NULL == cb_container) {
175                 ERR("calloc() Fail(%d)", errno);
176                 return IOTCON_ERROR_OUT_OF_MEMORY;
177         }
178
179         cb_container->cb = cb;
180         cb_container->user_data = user_data;
181
182         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
183                         _icl_device_info_cb);
184         if (0 == sub_id) {
185                 ERR("icl_dbus_subscribe_signal() Fail");
186                 free(cb_container);
187                 return IOTCON_ERROR_DBUS;
188         }
189
190         cb_container->id = sub_id;
191
192         cb_container->timeout_id = g_timeout_add_seconds(timeout,
193                         _icl_timeout_get_device_info, cb_container);
194
195         return ret;
196 }
197
198 API int iotcon_platform_info_get_property(iotcon_platform_info_h platform_info,
199                 iotcon_platform_info_e property, char **value)
200 {
201         RETV_IF(NULL == platform_info, IOTCON_ERROR_INVALID_PARAMETER);
202         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
203
204         switch (property) {
205         case IOTCON_PLATFORM_INFO_ID:
206                 *value = platform_info->platform_id;
207                 break;
208         case IOTCON_PLATFORM_INFO_MANUF_NAME:
209                 *value = platform_info->manuf_name;
210                 break;
211         case IOTCON_PLATFORM_INFO_MANUF_URL:
212                 *value = platform_info->manuf_url;
213                 break;
214         case IOTCON_PLATFORM_INFO_MODEL_NUMBER:
215                 *value = platform_info->model_number;
216                 break;
217         case IOTCON_PLATFORM_INFO_DATE_OF_MANUF:
218                 *value = platform_info->date_of_manuf;
219                 break;
220         case IOTCON_PLATFORM_INFO_PLATFORM_VER:
221                 *value = platform_info->platform_ver;
222                 break;
223         case IOTCON_PLATFORM_INFO_OS_VER:
224                 *value = platform_info->os_ver;
225                 break;
226         case IOTCON_PLATFORM_INFO_HARDWARE_VER:
227                 *value = platform_info->hardware_ver;
228                 break;
229         case IOTCON_PLATFORM_INFO_FIRMWARE_VER:
230                 *value = platform_info->firmware_ver;
231                 break;
232         case IOTCON_PLATFORM_INFO_SUPPORT_URL:
233                 *value = platform_info->support_url;
234                 break;
235         case IOTCON_PLATFORM_INFO_SYSTEM_TIME:
236                 *value = platform_info->system_time;
237                 break;
238         default:
239                 ERR("Invalid property(%d)", property);
240                 return IOTCON_ERROR_INVALID_PARAMETER;
241         }
242
243         return IOTCON_ERROR_NONE;
244 }
245
246
247 static void _icl_platform_info_cb(GDBusConnection *connection,
248                 const gchar *sender_name,
249                 const gchar *object_path,
250                 const gchar *interface_name,
251                 const gchar *signal_name,
252                 GVariant *parameters,
253                 gpointer user_data)
254 {
255         char *uri_path;
256         struct icl_platform_info info = {0};
257         icl_platform_info_s *cb_container = user_data;
258         iotcon_platform_info_cb cb = cb_container->cb;
259
260         if (cb_container->timeout_id)
261                 cb_container->timeout_id = 0;
262
263         g_variant_get(parameters, "(&s&s&s&s&s&s&s&s&s&s&s&s)",
264                         &uri_path,
265                         &info.platform_id,
266                         &info.manuf_name,
267                         &info.manuf_url,
268                         &info.model_number,
269                         &info.date_of_manuf,
270                         &info.platform_ver,
271                         &info.os_ver,
272                         &info.hardware_ver,
273                         &info.firmware_ver,
274                         &info.support_url,
275                         &info.system_time);
276
277         info.manuf_url = ic_utils_dbus_decode_str(info.manuf_url);
278         info.model_number = ic_utils_dbus_decode_str(info.model_number);
279         info.date_of_manuf = ic_utils_dbus_decode_str(info.date_of_manuf);
280         info.platform_ver = ic_utils_dbus_decode_str(info.platform_ver);
281         info.os_ver = ic_utils_dbus_decode_str(info.os_ver);
282         info.hardware_ver = ic_utils_dbus_decode_str(info.hardware_ver);
283         info.firmware_ver = ic_utils_dbus_decode_str(info.firmware_ver);
284         info.support_url = ic_utils_dbus_decode_str(info.support_url);
285         info.system_time = ic_utils_dbus_decode_str(info.system_time);
286
287         /* From iotivity, we can get uri_path. But, the value is always "/oic/p". */
288
289         if (cb)
290                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
291 }
292
293 static gboolean _icl_timeout_get_platform_info(gpointer p)
294 {
295         FN_CALL;
296         icl_platform_info_s *cb_container = p;
297         struct icl_platform_info info = {0};
298
299         if (NULL == cb_container) {
300                 ERR("cb_container is NULL");
301                 return G_SOURCE_REMOVE;
302         }
303
304         if (cb_container->timeout_id && cb_container->cb)
305                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
306
307         icl_dbus_unsubscribe_signal(cb_container->id);
308         cb_container->id = 0;
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, timeout;
319         unsigned int sub_id;
320         GError *error = NULL;
321         icl_platform_info_s *cb_container;
322         int64_t signal_number;
323         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
324
325         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
326         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
327
328         timeout = icl_dbus_get_timeout();
329
330         ic_dbus_call_get_platform_info_sync(icl_dbus_get_object(),
331                         ic_utils_dbus_encode_str(host_address),
332                         connectivity_type,
333                         timeout,
334                         &signal_number,
335                         &ret,
336                         NULL,
337                         &error);
338         if (error) {
339                 ERR("ic_dbus_call_get_platform_info_sync() Fail(%s)", error->message);
340                 ret = icl_dbus_convert_dbus_error(error->code);
341                 g_error_free(error);
342                 return ret;
343         }
344
345         if (IOTCON_ERROR_NONE != ret) {
346                 ERR("iotcon-daemon Fail(%d)", ret);
347                 return icl_dbus_convert_daemon_error(ret);
348         }
349
350         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_PLATFORM,
351                         signal_number);
352
353         cb_container = calloc(1, sizeof(icl_platform_info_s));
354         if (NULL == cb_container) {
355                 ERR("calloc() Fail(%d)", errno);
356                 return IOTCON_ERROR_OUT_OF_MEMORY;
357         }
358
359         cb_container->cb = cb;
360         cb_container->user_data = user_data;
361
362         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
363                         _icl_platform_info_cb);
364         if (0 == sub_id) {
365                 ERR("icl_dbus_subscribe_signal() Fail");
366                 free(cb_container);
367                 return IOTCON_ERROR_DBUS;
368         }
369
370         cb_container->id = sub_id;
371         cb_container->timeout_id = g_timeout_add_seconds(timeout,
372                         _icl_timeout_get_platform_info, cb_container);
373
374         return ret;
375 }