Unsubscribe signal on timeout callback
[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         GError *error = NULL;
142         unsigned int sub_id;
143         int ret, signal_number;
144         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
145         icl_device_info_s *cb_container;
146
147         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
148         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
149         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
150
151         signal_number = icl_dbus_generate_signal_number();
152
153         ic_dbus_call_get_device_info_sync(icl_dbus_get_object(), host_address,
154                         connectivity_type, signal_number, &ret, NULL, &error);
155         if (error) {
156                 ERR("ic_dbus_call_get_device_info_sync() Fail(%s)", error->message);
157                 ret = icl_dbus_convert_dbus_error(error->code);
158                 g_error_free(error);
159                 return ret;
160         }
161
162         if (IOTCON_ERROR_NONE != ret) {
163                 ERR("iotcon-daemon Fail(%d)", ret);
164                 return icl_dbus_convert_daemon_error(ret);
165         }
166
167         snprintf(signal_name, sizeof(signal_name), "%s_%u", IC_DBUS_SIGNAL_DEVICE,
168                         signal_number);
169
170         cb_container = calloc(1, sizeof(icl_device_info_s));
171         if (NULL == cb_container) {
172                 ERR("calloc() Fail(%d)", errno);
173                 return IOTCON_ERROR_OUT_OF_MEMORY;
174         }
175
176         cb_container->cb = cb;
177         cb_container->user_data = user_data;
178
179         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
180                         _icl_device_info_cb);
181         if (0 == sub_id) {
182                 ERR("icl_dbus_subscribe_signal() Fail");
183                 free(cb_container);
184                 return IOTCON_ERROR_DBUS;
185         }
186
187         cb_container->id = sub_id;
188
189         cb_container->timeout_id = g_timeout_add_seconds(icl_dbus_get_timeout(),
190                         _icl_timeout_get_device_info, cb_container);
191
192         return ret;
193 }
194
195 API int iotcon_platform_info_get_property(iotcon_platform_info_h platform_info,
196                 iotcon_platform_info_e property, char **value)
197 {
198         RETV_IF(NULL == platform_info, IOTCON_ERROR_INVALID_PARAMETER);
199         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
200
201         switch (property) {
202         case IOTCON_PLATFORM_INFO_ID:
203                 *value = platform_info->platform_id;
204                 break;
205         case IOTCON_PLATFORM_INFO_MANUF_NAME:
206                 *value = platform_info->manuf_name;
207                 break;
208         case IOTCON_PLATFORM_INFO_MANUF_URL:
209                 *value = platform_info->manuf_url;
210                 break;
211         case IOTCON_PLATFORM_INFO_MODEL_NUMBER:
212                 *value = platform_info->model_number;
213                 break;
214         case IOTCON_PLATFORM_INFO_DATE_OF_MANUF:
215                 *value = platform_info->date_of_manuf;
216                 break;
217         case IOTCON_PLATFORM_INFO_PLATFORM_VER:
218                 *value = platform_info->platform_ver;
219                 break;
220         case IOTCON_PLATFORM_INFO_OS_VER:
221                 *value = platform_info->os_ver;
222                 break;
223         case IOTCON_PLATFORM_INFO_HARDWARE_VER:
224                 *value = platform_info->hardware_ver;
225                 break;
226         case IOTCON_PLATFORM_INFO_FIRMWARE_VER:
227                 *value = platform_info->firmware_ver;
228                 break;
229         case IOTCON_PLATFORM_INFO_SUPPORT_URL:
230                 *value = platform_info->support_url;
231                 break;
232         case IOTCON_PLATFORM_INFO_SYSTEM_TIME:
233                 *value = platform_info->system_time;
234                 break;
235         default:
236                 ERR("Invalid property(%d)", property);
237                 return IOTCON_ERROR_INVALID_PARAMETER;
238         }
239
240         return IOTCON_ERROR_NONE;
241 }
242
243
244 static void _icl_platform_info_cb(GDBusConnection *connection,
245                 const gchar *sender_name,
246                 const gchar *object_path,
247                 const gchar *interface_name,
248                 const gchar *signal_name,
249                 GVariant *parameters,
250                 gpointer user_data)
251 {
252         char *uri_path;
253         struct icl_platform_info info = {0};
254         icl_platform_info_s *cb_container = user_data;
255         iotcon_platform_info_cb cb = cb_container->cb;
256
257         if (cb_container->timeout_id)
258                 cb_container->timeout_id = 0;
259
260         g_variant_get(parameters, "(&s&s&s&s&s&s&s&s&s&s&s&s)",
261                         &uri_path,
262                         &info.platform_id,
263                         &info.manuf_name,
264                         &info.manuf_url,
265                         &info.model_number,
266                         &info.date_of_manuf,
267                         &info.platform_ver,
268                         &info.os_ver,
269                         &info.hardware_ver,
270                         &info.firmware_ver,
271                         &info.support_url,
272                         &info.system_time);
273
274         /* From iotivity, we can get uri_path. But, the value is always "/oic/p". */
275
276         if (cb)
277                 cb(&info, IOTCON_ERROR_NONE, cb_container->user_data);
278 }
279
280 static gboolean _icl_timeout_get_platform_info(gpointer p)
281 {
282         FN_CALL;
283         icl_platform_info_s *cb_container = p;
284         struct icl_platform_info info = {0};
285
286         if (NULL == cb_container) {
287                 ERR("cb_container is NULL");
288                 return G_SOURCE_REMOVE;
289         }
290
291         if (cb_container->timeout_id && cb_container->cb)
292                 cb_container->cb(&info, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
293
294         icl_dbus_unsubscribe_signal(cb_container->id);
295
296         return G_SOURCE_REMOVE;
297 }
298
299 API int iotcon_get_platform_info(const char *host_address,
300                 iotcon_connectivity_type_e connectivity_type,
301                 iotcon_platform_info_cb cb,
302                 void *user_data)
303 {
304         GError *error = NULL;
305         unsigned int sub_id;
306         int ret, signal_number;
307         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
308         icl_platform_info_s *cb_container;
309
310         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
311         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
312         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
313
314         signal_number = icl_dbus_generate_signal_number();
315
316         ic_dbus_call_get_platform_info_sync(icl_dbus_get_object(), host_address,
317                         connectivity_type, signal_number, &ret, NULL, &error);
318         if (error) {
319                 ERR("ic_dbus_call_get_platform_info_sync() Fail(%s)", error->message);
320                 ret = icl_dbus_convert_dbus_error(error->code);
321                 g_error_free(error);
322                 return ret;
323         }
324
325         if (IOTCON_ERROR_NONE != ret) {
326                 ERR("iotcon-daemon Fail(%d)", ret);
327                 return icl_dbus_convert_daemon_error(ret);
328         }
329
330         snprintf(signal_name, sizeof(signal_name), "%s_%u", IC_DBUS_SIGNAL_PLATFORM,
331                         signal_number);
332
333         cb_container = calloc(1, sizeof(icl_platform_info_s));
334         if (NULL == cb_container) {
335                 ERR("calloc() Fail(%d)", errno);
336                 return IOTCON_ERROR_OUT_OF_MEMORY;
337         }
338
339         cb_container->cb = cb;
340         cb_container->user_data = user_data;
341
342         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
343                         _icl_platform_info_cb);
344         if (0 == sub_id) {
345                 ERR("icl_dbus_subscribe_signal() Fail");
346                 free(cb_container);
347                 return IOTCON_ERROR_DBUS;
348         }
349
350         cb_container->id = sub_id;
351         cb_container->timeout_id = g_timeout_add_seconds(icl_dbus_get_timeout(),
352                         _icl_timeout_get_platform_info, cb_container);
353
354         return ret;
355 }
356
357
358 static void _icl_tizen_info_cb(GObject *object, GAsyncResult *g_async_res,
359                 gpointer user_data)
360 {
361         int res;
362         GVariant *result;
363         char *device_name;
364         char *tizen_device_id;
365         GError *error = NULL;
366         struct icl_tizen_info info = {0};
367         icl_tizen_info_s *cb_container = user_data;
368         iotcon_tizen_info_cb cb = cb_container->cb;
369
370         ic_dbus_call_get_tizen_info_finish(IC_DBUS(object), &result, g_async_res, &error);
371         if (error) {
372                 ERR("ic_dbus_call_get_tizen_info_finish() Fail(%s)", error->message);
373                 if (cb) {
374                         int ret = icl_dbus_convert_dbus_error(error->code);
375                         cb(&info, ret, cb_container->user_data);
376                 }
377                 g_error_free(error);
378                 /* TODO contain time out error */
379                 free(cb_container);
380                 return;
381         }
382
383         g_variant_get(result, "(&s&si)", &device_name, &tizen_device_id, &res);
384
385         if (IOTCON_ERROR_NONE == res && NULL != ic_utils_dbus_decode_str(tizen_device_id)) {
386                 info.device_name = ic_utils_dbus_decode_str(device_name);
387                 info.tizen_device_id = tizen_device_id;
388         }
389
390         if (cb)
391                 cb(&info, res, cb_container->user_data);
392
393         free(cb_container);
394 }
395
396
397 API int iotcon_get_tizen_info(const char *host_address,
398                 iotcon_connectivity_type_e connectivity_type,
399                 iotcon_tizen_info_cb cb,
400                 void *user_data)
401 {
402         icl_tizen_info_s *cb_container;
403
404         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
405         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
406         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
407
408         cb_container = calloc(1, sizeof(icl_tizen_info_s));
409         if (NULL == cb_container) {
410                 ERR("calloc() Fail(%d)", errno);
411                 return IOTCON_ERROR_OUT_OF_MEMORY;
412         }
413
414         cb_container->cb = cb;
415         cb_container->user_data = user_data;
416
417         ic_dbus_call_get_tizen_info(icl_dbus_get_object(), host_address, connectivity_type,
418                         NULL, _icl_tizen_info_cb, cb_container);
419
420         return IOTCON_ERROR_NONE;
421 }
422
423
424 API int iotcon_tizen_info_get_property(iotcon_tizen_info_h tizen_info,
425                 iotcon_tizen_info_e property, char **value)
426 {
427         RETV_IF(NULL == tizen_info, IOTCON_ERROR_INVALID_PARAMETER);
428         RETV_IF(NULL == value, IOTCON_ERROR_INVALID_PARAMETER);
429
430         switch (property) {
431         case IOTCON_TIZEN_INFO_DEVICE_NAME:
432                 *value = tizen_info->device_name;
433                 break;
434         case IOTCON_TIZEN_INFO_TIZEN_DEVICE_ID:
435                 *value = tizen_info->tizen_device_id;
436                 break;
437         default:
438                 ERR("Invalid property(%d)", property);
439                 return IOTCON_ERROR_INVALID_PARAMETER;
440         }
441
442         return IOTCON_ERROR_NONE;
443 }