fix the problem when structures are destoried, repeatedly
[platform/core/iot/iotcon.git] / lib / icl-remote-resource.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-types.h"
24 #include "ic-utils.h"
25 #include "icl.h"
26 #include "icl-options.h"
27 #include "icl-dbus.h"
28 #include "icl-representation.h"
29 #include "icl-remote-resource.h"
30 #include "icl-resource-types.h"
31 #include "icl-payload.h"
32
33 #define ICL_REMOTE_RESOURCE_MAX_TIME_INTERVAL 3600 /* 60 min */
34
35 typedef struct {
36         iotcon_found_resource_cb cb;
37         void *user_data;
38         unsigned int id;
39         int timeout_id;
40 } icl_found_resource_s;
41
42 static iotcon_remote_resource_h _icl_remote_resource_from_gvariant(GVariant *payload,
43                 iotcon_connectivity_type_e connectivity_type);
44
45 static void _icl_found_resource_cb(GDBusConnection *connection,
46                 const gchar *sender_name,
47                 const gchar *object_path,
48                 const gchar *interface_name,
49                 const gchar *signal_name,
50                 GVariant *parameters,
51                 gpointer user_data)
52 {
53         FN_CALL;
54         int connectivity_type;
55         iotcon_remote_resource_h resource;
56
57         GVariant *payload;
58         icl_found_resource_s *cb_container = user_data;
59         iotcon_found_resource_cb cb = cb_container->cb;
60
61         if (cb_container->timeout_id)
62                 cb_container->timeout_id = 0;
63
64         g_variant_get(parameters, "(vi)", &payload, &connectivity_type);
65
66         resource = _icl_remote_resource_from_gvariant(payload, connectivity_type);
67         if (NULL == resource) {
68                 ERR("icl_remote_resource_from_gvariant() Fail");
69                 return;
70         }
71
72         if (cb)
73                 cb(resource, IOTCON_ERROR_NONE, cb_container->user_data);
74
75         iotcon_remote_resource_destroy(resource);
76 }
77
78 static gboolean _icl_timeout_find_resource(gpointer p)
79 {
80         icl_found_resource_s *cb_container = p;
81
82         if (NULL == cb_container) {
83                 ERR("cb_container is NULL");
84                 return G_SOURCE_REMOVE;
85         }
86
87         if (cb_container->timeout_id && cb_container->cb)
88                 cb_container->cb(NULL, IOTCON_ERROR_TIMEOUT, cb_container->user_data);
89
90         icl_dbus_unsubscribe_signal(cb_container->id);
91         cb_container->id = 0;
92
93         return G_SOURCE_REMOVE;
94 }
95
96
97 /* The length of resource_type should be less than or equal to 61.
98  * If resource_type is NULL, then All resources in host are discovered. */
99 API int iotcon_find_resource(const char *host_address,
100                 iotcon_connectivity_type_e connectivity_type,
101                 const char *resource_type,
102                 bool is_secure,
103                 iotcon_found_resource_cb cb,
104                 void *user_data)
105 {
106         int ret, timeout;
107         unsigned int sub_id;
108         GError *error = NULL;
109         int64_t signal_number;
110         icl_found_resource_s *cb_container;
111         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
112
113         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
114         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
115         if (resource_type && (ICL_RESOURCE_TYPE_LENGTH_MAX < strlen(resource_type))) {
116                 ERR("The length of resource_type(%s) is invalid", resource_type);
117                 return IOTCON_ERROR_INVALID_PARAMETER;
118         }
119
120         timeout = icl_dbus_get_timeout();
121
122         ic_dbus_call_find_resource_sync(icl_dbus_get_object(),
123                         ic_utils_dbus_encode_str(host_address),
124                         connectivity_type,
125                         ic_utils_dbus_encode_str(resource_type),
126                         is_secure,
127                         timeout,
128                         &signal_number,
129                         &ret,
130                         NULL,
131                         &error);
132         if (error) {
133                 ERR("ic_dbus_call_find_resource_sync() Fail(%s)", error->message);
134                 ret = icl_dbus_convert_dbus_error(error->code);
135                 g_error_free(error);
136                 return ret;
137         }
138
139         if (IOTCON_ERROR_NONE != ret) {
140                 ERR("iotcon-daemon Fail(%d)", ret);
141                 return icl_dbus_convert_daemon_error(ret);
142         }
143
144         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_FOUND_RESOURCE,
145                         signal_number);
146
147         cb_container = calloc(1, sizeof(icl_found_resource_s));
148         if (NULL == cb_container) {
149                 ERR("calloc() Fail(%d)", errno);
150                 return IOTCON_ERROR_OUT_OF_MEMORY;
151         }
152
153         cb_container->cb = cb;
154         cb_container->user_data = user_data;
155
156         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container, free,
157                         _icl_found_resource_cb);
158         if (0 == sub_id) {
159                 ERR("icl_dbus_subscribe_signal() Fail");
160                 return IOTCON_ERROR_DBUS;
161         }
162
163         cb_container->id = sub_id;
164
165         cb_container->timeout_id = g_timeout_add_seconds(timeout, _icl_timeout_find_resource,
166                         cb_container);
167
168         return ret;
169 }
170
171
172 /* If you know the information of resource, then you can make a proxy of the resource. */
173 API int iotcon_remote_resource_create(const char *host_address,
174                 iotcon_connectivity_type_e connectivity_type,
175                 const char *uri_path,
176                 int properties,
177                 iotcon_resource_types_h resource_types,
178                 int resource_ifs,
179                 iotcon_remote_resource_h *resource_handle)
180 {
181         FN_CALL;
182         iotcon_remote_resource_h resource = NULL;
183
184         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
185         RETV_IF(NULL == uri_path, IOTCON_ERROR_INVALID_PARAMETER);
186         RETV_IF(NULL == resource_types, IOTCON_ERROR_INVALID_PARAMETER);
187         RETV_IF(NULL == resource_handle, IOTCON_ERROR_INVALID_PARAMETER);
188
189         resource = calloc(1, sizeof(struct icl_remote_resource));
190         if (NULL == resource) {
191                 ERR("calloc() Fail(%d)", errno);
192                 return IOTCON_ERROR_OUT_OF_MEMORY;
193         }
194
195         resource->host_address = ic_utils_strdup(host_address);
196         resource->connectivity_type = connectivity_type;
197         resource->uri_path = ic_utils_strdup(uri_path);
198         resource->properties = properties;
199         resource->types = icl_resource_types_ref(resource_types);
200         resource->ifaces = resource_ifs;
201
202         *resource_handle = resource;
203
204         return IOTCON_ERROR_NONE;
205 }
206
207
208 API void iotcon_remote_resource_destroy(iotcon_remote_resource_h resource)
209 {
210         RET_IF(NULL == resource);
211
212         if (resource->observe_handle)
213                 iotcon_remote_resource_observe_deregister(resource);
214
215         icl_remote_resource_crud_stop(resource);
216
217         if (0 != resource->caching_sub_id)
218                 iotcon_remote_resource_stop_caching(resource);
219         if (0 != resource->monitoring_sub_id)
220                 iotcon_remote_resource_stop_monitoring(resource);
221
222         free(resource->uri_path);
223         free(resource->host_address);
224         free(resource->device_id);
225         iotcon_resource_types_destroy(resource->types);
226
227         /* null COULD be allowed */
228         if (resource->header_options)
229                 iotcon_options_destroy(resource->header_options);
230
231         free(resource);
232 }
233
234 static bool _icl_remote_resource_header_foreach_cb(unsigned short id,
235                 const char *data, void *user_data)
236 {
237         int ret;
238         iotcon_remote_resource_h resource = user_data;
239
240         RETV_IF(NULL == resource, IOTCON_FUNC_STOP);
241
242         if (NULL == resource->header_options) {
243                 ret = iotcon_options_create(&resource->header_options);
244                 if (IOTCON_ERROR_NONE != ret) {
245                         ERR("resource->header_options() Fail(%d)", ret);
246                         return IOTCON_FUNC_STOP;
247                 }
248         }
249
250         ret = iotcon_options_add(resource->header_options, id, data);
251         if (IOTCON_ERROR_NONE != ret) {
252                 ERR("iotcon_options_add() Fail(%d)", ret);
253                 return IOTCON_FUNC_STOP;
254         }
255
256         return IOTCON_FUNC_CONTINUE;
257 }
258
259 API int iotcon_remote_resource_clone(iotcon_remote_resource_h src,
260                 iotcon_remote_resource_h *dest)
261 {
262         int ret;
263         iotcon_remote_resource_h resource = NULL;
264
265         RETV_IF(NULL == src, IOTCON_ERROR_INVALID_PARAMETER);
266
267         resource = calloc(1, sizeof(struct icl_remote_resource));
268         if (NULL == resource) {
269                 ERR("calloc() Fail(%d)", errno);
270                 return IOTCON_ERROR_OUT_OF_MEMORY;
271         }
272
273         resource->uri_path = ic_utils_strdup(src->uri_path);
274         resource->host_address = ic_utils_strdup(src->host_address);
275         resource->connectivity_type = src->connectivity_type;
276         resource->device_id = ic_utils_strdup(src->device_id);
277         resource->properties = src->properties;
278
279         if (src->header_options) {
280                 ret = iotcon_options_foreach(src->header_options,
281                                 _icl_remote_resource_header_foreach_cb, resource);
282                 if (IOTCON_ERROR_NONE != ret) {
283                         ERR("iotcon_options_foreach() Fail(%d)", ret);
284                         iotcon_remote_resource_destroy(resource);
285                         return ret;
286                 }
287         }
288
289         if (src->types) {
290                 ret = iotcon_resource_types_clone(src->types, &resource->types);
291                 if (IOTCON_ERROR_NONE != ret) {
292                         ERR("iotcon_resource_types_clone() Fail(%d)", ret);
293                         iotcon_remote_resource_destroy(resource);
294                         return ret;
295                 }
296         }
297
298         resource->ifaces = src->ifaces;
299         resource->connectivity_type = src->connectivity_type;
300
301         *dest = resource;
302
303         return IOTCON_ERROR_NONE;
304 }
305
306
307 /* The content of the resource should not be freed by user. */
308 API int iotcon_remote_resource_get_uri_path(iotcon_remote_resource_h resource,
309                 char **uri_path)
310 {
311         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
312         RETV_IF(NULL == uri_path, IOTCON_ERROR_INVALID_PARAMETER);
313
314         *uri_path = resource->uri_path;
315
316         return IOTCON_ERROR_NONE;
317 }
318
319
320 /* The content of the resource should not be freed by user. */
321 API int iotcon_remote_resource_get_host_address(iotcon_remote_resource_h resource,
322                 char **host_address)
323 {
324         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
325         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
326
327         *host_address = resource->host_address;
328
329         return IOTCON_ERROR_NONE;
330 }
331
332
333 /* The content of the resource should not be freed by user. */
334 API int iotcon_remote_resource_get_connectivity_type(iotcon_remote_resource_h resource,
335                 iotcon_connectivity_type_e *connectivity_type)
336 {
337         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
338         RETV_IF(NULL == connectivity_type, IOTCON_ERROR_INVALID_PARAMETER);
339
340         *connectivity_type = resource->connectivity_type;
341
342         return IOTCON_ERROR_NONE;
343 }
344
345
346 /* The content of the resource should not be freed by user. */
347 API int iotcon_remote_resource_get_device_id(iotcon_remote_resource_h resource,
348                 char **device_id)
349 {
350         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
351         RETV_IF(NULL == device_id, IOTCON_ERROR_INVALID_PARAMETER);
352
353         *device_id = resource->device_id;
354
355         return IOTCON_ERROR_NONE;
356 }
357
358 /* The content of the resource should not be freed by user. */
359 API int iotcon_remote_resource_get_types(iotcon_remote_resource_h resource,
360                 iotcon_resource_types_h *types)
361 {
362         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
363         RETV_IF(NULL == types, IOTCON_ERROR_INVALID_PARAMETER);
364
365         *types = resource->types;
366
367         return IOTCON_ERROR_NONE;
368 }
369
370
371 API int iotcon_remote_resource_get_interfaces(iotcon_remote_resource_h resource,
372                 int *ifaces)
373 {
374         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
375         RETV_IF(NULL == ifaces, IOTCON_ERROR_INVALID_PARAMETER);
376
377         *ifaces = resource->ifaces;
378
379         return IOTCON_ERROR_NONE;
380 }
381
382
383 API int iotcon_remote_resource_get_properties(iotcon_remote_resource_h resource,
384                 int *properties)
385 {
386         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
387         RETV_IF(NULL == properties, IOTCON_ERROR_INVALID_PARAMETER);
388
389         *properties = resource->properties;
390
391         return IOTCON_ERROR_NONE;
392 }
393
394 API int iotcon_remote_resource_get_options(iotcon_remote_resource_h resource,
395                 iotcon_options_h *options)
396 {
397         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
398         RETV_IF(NULL == options, IOTCON_ERROR_INVALID_PARAMETER);
399
400         *options = resource->header_options;
401
402         return IOTCON_ERROR_NONE;
403 }
404
405 /* if header_options is NULL, then client's header_options is unset */
406 API int iotcon_remote_resource_set_options(iotcon_remote_resource_h resource,
407                 iotcon_options_h options)
408 {
409         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
410
411         if (resource->header_options)
412                 iotcon_options_destroy(resource->header_options);
413
414         if (options)
415                 resource->header_options = icl_options_ref(options);
416         else
417                 resource->header_options = NULL;
418
419         return IOTCON_ERROR_NONE;
420 }
421
422
423 static iotcon_remote_resource_h _icl_remote_resource_from_gvariant(GVariant *payload,
424                 iotcon_connectivity_type_e connectivity_type)
425 {
426         int ret;
427         iotcon_remote_resource_h resource;
428         GVariantIter *types_iter;
429         char host_addr[PATH_MAX] = {0};
430         iotcon_resource_types_h res_types;
431         char *uri_path, *device_id, *res_type, *addr;
432         int ifaces, properties, is_secure, port;
433
434         g_variant_get(payload, "(&s&siasib&si)", &uri_path, &device_id, &ifaces, &types_iter,
435                         &properties, &is_secure, &addr, &port);
436
437         switch (connectivity_type) {
438         case IOTCON_CONNECTIVITY_IPV6:
439                 snprintf(host_addr, sizeof(host_addr), "[%s]:%d", addr, port);
440                 break;
441         case IOTCON_CONNECTIVITY_IPV4:
442                 snprintf(host_addr, sizeof(host_addr), "%s:%d", addr, port);
443                 break;
444         case IOTCON_CONNECTIVITY_BT_EDR:
445         default:
446                 snprintf(host_addr, sizeof(host_addr), "%s", addr);
447         }
448
449         ret = iotcon_resource_types_create(&res_types);
450         if (IOTCON_ERROR_NONE != ret) {
451                 ERR("iotcon_resource_types_create() Fail(%d)", ret);
452                 return NULL;
453         }
454
455         while (g_variant_iter_loop(types_iter, "s", &res_type))
456                 iotcon_resource_types_add(res_types, res_type);
457
458         ret = iotcon_remote_resource_create(host_addr, connectivity_type, uri_path,
459                         properties, res_types, ifaces, &resource);
460         if (res_types)
461                 iotcon_resource_types_destroy(res_types);
462
463         if (IOTCON_ERROR_NONE != ret) {
464                 ERR("iotcon_remote_resource_create() Fail");
465                 return NULL;
466         }
467
468         resource->device_id = strdup(device_id);
469         if (NULL == resource->device_id) {
470                 ERR("strdup(device_id) Fail(%d)", errno);
471                 iotcon_remote_resource_destroy(resource);
472                 return NULL;
473         }
474         resource->connectivity_type = connectivity_type;
475         resource->properties = properties;
476
477         return resource;
478 }
479
480
481 API int iotcon_remote_resource_get_time_interval(int *time_interval)
482 {
483         GError *error = NULL;
484         int ret, arg_time_interval;
485
486         RETV_IF(NULL == time_interval, IOTCON_ERROR_INVALID_PARAMETER);
487
488         ic_dbus_call_encap_get_time_interval_sync(icl_dbus_get_object(), &arg_time_interval,
489                         NULL, &error);
490         if (error) {
491                 ERR("ic_dbus_call_encap_get_time_interval_sync() Fail(%s)", error->message);
492                 ret = icl_dbus_convert_dbus_error(error->code);
493                 g_error_free(error);
494                 return ret;
495         }
496
497         *time_interval = arg_time_interval;
498
499         return IOTCON_ERROR_NONE;
500 }
501
502
503 API int iotcon_remote_resource_set_time_interval(int time_interval)
504 {
505         int ret;
506         GError *error = NULL;
507
508         RETV_IF(ICL_REMOTE_RESOURCE_MAX_TIME_INTERVAL < time_interval || time_interval <= 0,
509                         IOTCON_ERROR_INVALID_PARAMETER);
510
511         ic_dbus_call_encap_set_time_interval_sync(icl_dbus_get_object(), time_interval,
512                         NULL, &error);
513         if (error) {
514                 ERR("ic_dbus_call_encap_set_time_interval_sync() Fail(%s)", error->message);
515                 ret = icl_dbus_convert_dbus_error(error->code);
516                 g_error_free(error);
517                 return ret;
518         }
519
520         return IOTCON_ERROR_NONE;
521 }
522