iotcon_initialize() is called multiple times
[platform/core/iot/iotcon.git] / lib / icl-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 <stdbool.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <glib.h>
23
24 #include "iotcon.h"
25 #include "ic-utils.h"
26 #include "icl-resource-types.h"
27 #include "icl-resource.h"
28 #include "icl-request.h"
29 #include "icl-repr.h"
30 #include "icl-dbus.h"
31 #include "icl-dbus-type.h"
32 #include "icl.h"
33
34 static void _icl_request_handler(GDBusConnection *connection,
35                 const gchar *sender_name,
36                 const gchar *object_path,
37                 const gchar *interface_name,
38                 const gchar *signal_name,
39                 GVariant *parameters,
40                 gpointer user_data)
41 {
42         GVariantIter *options;
43         unsigned short option_id;
44         char *option_data;
45         GVariantIter *query;
46         char *key = NULL;
47         char *value = NULL;
48         char *repr_json;
49         int request_handle;
50         int resource_handle;
51         struct icl_resource_request request = {0};
52         iotcon_resource_h resource = user_data;
53         iotcon_request_handler_cb cb = resource->cb;
54
55         g_variant_get(parameters, "(ia(qs)a(ss)ii&sii)",
56                         &request.types,
57                         &options,
58                         &query,
59                         &request.observation_info.action,
60                         &request.observation_info.observer_id,
61                         &repr_json,
62                         &request_handle,
63                         &resource_handle);
64
65         if (g_variant_iter_n_children(options)) {
66                 request.header_options = iotcon_options_new();
67                 while (g_variant_iter_loop(options, "(q&s)", &option_id, &option_data))
68                         iotcon_options_insert(request.header_options, option_id, option_data);
69         }
70         g_variant_iter_free(options);
71
72         if (g_variant_iter_n_children(query)) {
73                 request.query = iotcon_query_new();
74                 while (g_variant_iter_loop(query, "(&s&s)", &key, &value))
75                         iotcon_query_insert(request.query, key, value);
76         }
77         g_variant_iter_free(query);
78
79         request.request_handle = GINT_TO_POINTER(request_handle);
80         request.resource_handle = GINT_TO_POINTER(resource_handle);
81
82         if (ic_utils_dbus_decode_str(repr_json)) {
83                 request.repr = icl_repr_create_repr(repr_json);
84                 if (NULL == request.repr) {
85                         ERR("icl_repr_create_repr() Fail");
86                         if (request.query)
87                                 iotcon_query_free(request.query);
88                         if (request.header_options)
89                                 iotcon_options_free(request.header_options);
90                         return;
91                 }
92         }
93
94         /* TODO remove request.uri */
95         request.uri_path = "temp_uri_path";
96
97         if (cb)
98                 cb(resource, &request, resource->user_data);
99
100         /* To avoid unnecessary ERR log (repr could be NULL) */
101         if (request.repr)
102                 iotcon_repr_free(request.repr);
103         if (request.query)
104                 iotcon_query_free(request.query);
105         if (request.header_options)
106                 iotcon_options_free(request.header_options);
107 }
108
109
110 static void _icl_resource_conn_cleanup(iotcon_resource_h resource)
111 {
112         resource->sub_id = 0;
113         resource->handle = 0;
114 }
115
116
117 /* The length of uri_path should be less than or equal to 36. */
118 API iotcon_resource_h iotcon_register_resource(const char *uri_path,
119                 iotcon_resource_types_h res_types,
120                 int ifaces,
121                 uint8_t properties,
122                 iotcon_request_handler_cb cb,
123                 void *user_data)
124 {
125         FN_CALL;
126         int signal_number;
127         unsigned int sub_id;
128         GError *error = NULL;
129         const gchar **types;
130         char sig_name[IC_DBUS_SIGNAL_LENGTH];
131         iotcon_resource_h resource;
132
133         RETV_IF(NULL == icl_dbus_get_object(), NULL);
134         RETV_IF(NULL == uri_path, NULL);
135         RETVM_IF(IOTCON_URI_PATH_LENGTH_MAX < strlen(uri_path), NULL, "Invalid uri_path(%s)",
136                         uri_path);
137         RETV_IF(NULL == res_types, NULL);
138         RETV_IF(NULL == cb, NULL);
139
140         resource = calloc(1, sizeof(struct icl_resource));
141         if (NULL == resource) {
142                 ERR("calloc() Fail(%d)", errno);
143                 return NULL;
144         }
145
146         types = icl_dbus_resource_types_to_array(res_types);
147         if (NULL == types) {
148                 ERR("icl_dbus_resource_types_to_array() Fail");
149                 free(resource);
150                 return NULL;
151         }
152
153         signal_number = icl_dbus_generate_signal_number();
154
155         ic_dbus_call_register_resource_sync(icl_dbus_get_object(), uri_path, types, ifaces,
156                         properties, signal_number, &(resource->handle), NULL, &error);
157         if (error) {
158                 ERR("ic_dbus_call_register_resource_sync() Fail(%s)", error->message);
159                 g_error_free(error);
160                 free(types);
161                 free(resource);
162                 return NULL;
163         }
164         free(types);
165
166         if (0 == resource->handle) {
167                 ERR("iotcon-daemon Fail");
168                 free(resource);
169                 return NULL;
170         }
171
172         resource->cb = cb;
173         resource->user_data = user_data;
174
175         resource->types = icl_resource_types_ref(res_types);
176         resource->uri_path = ic_utils_strdup(uri_path);
177         resource->ifaces = ifaces;
178         resource->is_observable = properties & IOTCON_OBSERVABLE;
179
180         snprintf(sig_name, sizeof(sig_name), "%s_%u", IC_DBUS_SIGNAL_REQUEST_HANDLER,
181                         signal_number);
182
183         sub_id = icl_dbus_subscribe_signal(sig_name, resource, _icl_resource_conn_cleanup,
184                         _icl_request_handler);
185         if (0 == sub_id) {
186                 ERR("icl_dbus_subscribe_signal() Fail");
187                 free(resource);
188                 return NULL;
189         }
190
191         resource->sub_id = sub_id;
192
193         return resource;
194 }
195
196
197 API int iotcon_unregister_resource(iotcon_resource_h resource)
198 {
199         FN_CALL;
200         int ret;
201         GError *error = NULL;
202
203         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
204         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
205
206         if (0 == resource->sub_id) {
207                 WARN("Invalid Resource handle");
208                 iotcon_resource_types_free(resource->types);
209                 free(resource->uri_path);
210                 free(resource);
211                 return IOTCON_ERROR_NONE;
212         }
213
214         ic_dbus_call_unregister_resource_sync(icl_dbus_get_object(), resource->handle,
215                         &ret, NULL, &error);
216         if (error) {
217                 ERR("ic_dbus_call_unregister_resource_sync() Fail(%s)", error->message);
218                 g_error_free(error);
219                 return IOTCON_ERROR_DBUS;
220         }
221
222         if (IOTCON_ERROR_NONE != ret) {
223                 ERR("iotcon-daemon Fail(%d)", ret);
224                 return icl_dbus_convert_daemon_error(ret);
225         }
226
227         icl_dbus_unsubscribe_signal(resource->sub_id);
228
229         iotcon_resource_types_free(resource->types);
230         free(resource->uri_path);
231         free(resource);
232
233         return IOTCON_ERROR_NONE;
234 }
235
236
237 API int iotcon_bind_interface(iotcon_resource_h resource, iotcon_interface_e iface)
238 {
239         FN_CALL;
240         int ret;
241         GError *error = NULL;
242
243         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
244         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
245         if (0 == resource->sub_id) {
246                 ERR("Invalid Resource handle");
247                 return IOTCON_ERROR_INVALID_PARAMETER;
248         }
249
250         ic_dbus_call_bind_interface_sync(icl_dbus_get_object(), resource->handle,
251                         iface, &ret, NULL, &error);
252         if (error) {
253                 ERR("ic_dbus_call_bind_interface_sync() Fail(%s)", error->message);
254                 g_error_free(error);
255                 return IOTCON_ERROR_DBUS;
256         }
257
258         if (IOTCON_ERROR_NONE != ret) {
259                 ERR("iotcon-daemon Fail(%d)", ret);
260                 return icl_dbus_convert_daemon_error(ret);
261         }
262
263         return ret;
264 }
265
266
267 API int iotcon_bind_type(iotcon_resource_h resource, const char *resource_type)
268 {
269         FN_CALL;
270         int ret;
271         GError *error = NULL;
272
273         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
274         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
275         RETV_IF(NULL == resource_type, IOTCON_ERROR_INVALID_PARAMETER);
276         if (IOTCON_RESOURCE_TYPE_LENGTH_MAX < strlen(resource_type)) {
277                 ERR("Invalid resource_type(%s)", resource_type);
278                 return IOTCON_ERROR_INVALID_PARAMETER;
279         }
280
281         if (0 == resource->sub_id) {
282                 ERR("Invalid Resource handle");
283                 return IOTCON_ERROR_INVALID_PARAMETER;
284         }
285
286         ic_dbus_call_bind_type_sync(icl_dbus_get_object(), resource->handle, resource_type,
287                         &ret, NULL, &error);
288         if (error) {
289                 ERR("ic_dbus_call_bind_type_sync() Fail(%s)", error->message);
290                 g_error_free(error);
291                 return IOTCON_ERROR_DBUS;
292         }
293
294         if (IOTCON_ERROR_NONE != ret) {
295                 ERR("iotcon-daemon Fail(%d)", ret);
296                 return icl_dbus_convert_daemon_error(ret);
297         }
298
299         return ret;
300 }
301
302
303 API int iotcon_bind_request_handler(iotcon_resource_h resource,
304                 iotcon_request_handler_cb cb)
305 {
306         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
307         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
308
309         WARN("Request handler is changed");
310         resource->cb = cb;
311
312         return IOTCON_ERROR_NONE;
313 }
314
315
316 API int iotcon_bind_resource(iotcon_resource_h parent, iotcon_resource_h child)
317 {
318         FN_CALL;
319         int ret;
320         int i;
321         GError *error = NULL;
322
323         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
324         RETV_IF(NULL == parent, IOTCON_ERROR_INVALID_PARAMETER);
325         RETV_IF(NULL == child, IOTCON_ERROR_INVALID_PARAMETER);
326         RETV_IF(parent == child, IOTCON_ERROR_INVALID_PARAMETER);
327
328         if (0 == parent->sub_id) {
329                 ERR("Invalid Resource handle(parent)");
330                 return IOTCON_ERROR_INVALID_PARAMETER;
331         }
332         if (0 == child->sub_id) {
333                 ERR("Invalid Resource handle(child)");
334                 return IOTCON_ERROR_INVALID_PARAMETER;
335         }
336
337         for (i = 0; i < IOTCON_CONTAINED_RESOURCES_MAX; i++) {
338                 if (child == parent->children[i]) {
339                         ERR("Child resource was already bound to parent resource.");
340                         return IOTCON_ERROR_ALREADY;
341                 }
342         }
343
344         for (i = 0; i < IOTCON_CONTAINED_RESOURCES_MAX; i++) {
345                 if (NULL == parent->children[i]) {
346                         ic_dbus_call_bind_resource_sync(icl_dbus_get_object(), parent->handle,
347                                         child->handle, &ret, NULL, &error);
348                         if (error) {
349                                 ERR("ic_dbus_call_bind_resource_sync() Fail(%s)", error->message);
350                                 g_error_free(error);
351                                 return IOTCON_ERROR_DBUS;
352                         }
353
354                         if (IOTCON_ERROR_NONE != ret) {
355                                 ERR("iotcon-daemon Fail(%d)", ret);
356                                 return icl_dbus_convert_daemon_error(ret);
357                         }
358
359                         parent->children[i] = child;
360
361                         return IOTCON_ERROR_NONE;
362                 }
363         }
364
365         ERR("There is no slot to bind a child resource");
366         return IOTCON_ERROR_OUT_OF_MEMORY;
367 }
368
369
370 API int iotcon_unbind_resource(iotcon_resource_h parent, iotcon_resource_h child)
371 {
372         int ret;
373         int i;
374         GError *error = NULL;
375
376         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
377         RETV_IF(NULL == parent, IOTCON_ERROR_INVALID_PARAMETER);
378         RETV_IF(NULL == child, IOTCON_ERROR_INVALID_PARAMETER);
379
380         if (0 == parent->sub_id) {
381                 ERR("Invalid Resource handle(parent)");
382                 return IOTCON_ERROR_INVALID_PARAMETER;
383         }
384         if (0 == child->sub_id) {
385                 ERR("Invalid Resource handle(child)");
386                 return IOTCON_ERROR_INVALID_PARAMETER;
387         }
388
389         ic_dbus_call_unbind_resource_sync(icl_dbus_get_object(), parent->handle,
390                         child->handle, &ret, NULL, &error);
391         if (error) {
392                 ERR("ic_dbus_call_unbind_resource_sync() Fail(%s)", error->message);
393                 g_error_free(error);
394                 return IOTCON_ERROR_DBUS;
395         }
396
397         if (IOTCON_ERROR_NONE != ret) {
398                 ERR("iotcon-daemon Fail(%d)", ret);
399                 return icl_dbus_convert_daemon_error(ret);
400         }
401
402         for (i = 0; i < IOTCON_CONTAINED_RESOURCES_MAX; i++) {
403                 if (child == parent->children[i])
404                         parent->children[i] = NULL;
405         }
406
407         return IOTCON_ERROR_NONE;
408 }
409
410
411 API int iotcon_resource_get_number_of_children(iotcon_resource_h resource, int *number)
412 {
413         int i;
414
415         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
416         RETV_IF(NULL == number, IOTCON_ERROR_INVALID_PARAMETER);
417
418         *number = 0;
419         for (i = 0; i < IOTCON_CONTAINED_RESOURCES_MAX; i++) {
420                 if (resource->children[i])
421                         *number += 1;
422         }
423
424         return IOTCON_ERROR_NONE;
425 }
426
427
428 API int iotcon_resource_get_nth_child(iotcon_resource_h parent, int index,
429                 iotcon_resource_h *child)
430 {
431         RETV_IF(NULL == parent, IOTCON_ERROR_INVALID_PARAMETER);
432         RETV_IF(NULL == child, IOTCON_ERROR_INVALID_PARAMETER);
433         if ((index < 0) || (IOTCON_CONTAINED_RESOURCES_MAX <= index)) {
434                 ERR("Invalid index(%d)", index);
435                 return IOTCON_ERROR_INVALID_PARAMETER;
436         }
437
438         *child = parent->children[index];
439
440         return IOTCON_ERROR_NONE;
441 }
442
443
444 /* The content of the resource should not be freed by user. */
445 API int iotcon_resource_get_uri_path(iotcon_resource_h resource, char **uri_path)
446 {
447         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
448         RETV_IF(NULL == uri_path, IOTCON_ERROR_INVALID_PARAMETER);
449
450         *uri_path = resource->uri_path;
451
452         return IOTCON_ERROR_NONE;
453 }
454
455
456 /* The content of the resource should not be freed by user. */
457 API int iotcon_resource_get_types(iotcon_resource_h resource,
458                 iotcon_resource_types_h *types)
459 {
460         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
461         RETV_IF(NULL == types, IOTCON_ERROR_INVALID_PARAMETER);
462
463         *types = resource->types;
464
465         return IOTCON_ERROR_NONE;
466 }
467
468
469 API int iotcon_resource_get_interfaces(iotcon_resource_h resource, int *ifaces)
470 {
471         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
472         RETV_IF(NULL == ifaces, IOTCON_ERROR_INVALID_PARAMETER);
473
474         *ifaces = resource->ifaces;
475
476         return IOTCON_ERROR_NONE;
477 }
478
479
480 API int iotcon_resource_is_observable(iotcon_resource_h resource, bool *observable)
481 {
482         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
483         RETV_IF(NULL == observable, IOTCON_ERROR_INVALID_PARAMETER);
484
485         *observable = resource->is_observable;
486
487         return IOTCON_ERROR_NONE;
488 }
489
490
491 API iotcon_notimsg_h iotcon_notimsg_new(iotcon_repr_h repr, iotcon_interface_e iface)
492 {
493         iotcon_notimsg_h msg;
494
495         RETV_IF(NULL == repr, NULL);
496
497         msg = calloc(1, sizeof(struct icl_notify_msg));
498         if (NULL == msg) {
499                 ERR("calloc() Fail(%d)", errno);
500                 return NULL;
501         }
502
503         msg->repr = repr;
504         icl_repr_inc_ref_count(msg->repr);
505         msg->iface = iface;
506         msg->error_code = 200;
507
508         return msg;
509 }
510
511
512 API void iotcon_notimsg_free(iotcon_notimsg_h msg)
513 {
514         RET_IF(NULL == msg);
515
516         iotcon_repr_free(msg->repr);
517         free(msg);
518 }
519
520
521 API int iotcon_notify_list_of_observers(iotcon_resource_h resource, iotcon_notimsg_h msg,
522                 iotcon_observers_h observers)
523 {
524         int ret;
525         GError *error = NULL;
526         GVariant *noti_msg;
527         GVariant *obs;
528
529         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
530         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
531         RETV_IF(NULL == observers, IOTCON_ERROR_INVALID_PARAMETER);
532
533         if (0 == resource->sub_id) {
534                 ERR("Invalid Resource handle");
535                 return IOTCON_ERROR_INVALID_PARAMETER;
536         }
537
538         noti_msg = icl_dbus_notimsg_to_gvariant(msg);
539         if (NULL == noti_msg) {
540                 ERR("icl_dbus_notimsg_to_gvariant() Fail");
541                 return IOTCON_ERROR_REPRESENTATION;
542         }
543         obs = icl_dbus_observers_to_gvariant(observers);
544
545         ic_dbus_call_notify_list_of_observers_sync(icl_dbus_get_object(), resource->handle,
546                         noti_msg, obs, &ret, NULL, &error);
547         if (error) {
548                 ERR("ic_dbus_call_notify_list_of_observers_sync() Fail(%s)", error->message);
549                 g_error_free(error);
550                 g_variant_unref(obs);
551                 g_variant_unref(noti_msg);
552                 return IOTCON_ERROR_DBUS;
553         }
554
555         if (IOTCON_ERROR_NONE != ret) {
556                 ERR("iotcon-daemon Fail(%d)", ret);
557                 return icl_dbus_convert_daemon_error(ret);
558         }
559
560         return IOTCON_ERROR_NONE;
561 }
562
563
564 API int iotcon_notify_all(iotcon_resource_h resource)
565 {
566         int ret;
567         GError *error = NULL;
568
569         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
570         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
571         if (0 == resource->sub_id) {
572                 ERR("Invalid Resource handle");
573                 return IOTCON_ERROR_INVALID_PARAMETER;
574         }
575
576         ic_dbus_call_notify_all_sync(icl_dbus_get_object(), resource->handle, &ret, NULL,
577                         &error);
578         if (error) {
579                 ERR("ic_dbus_call_notify_all_sync() Fail(%s)", error->message);
580                 g_error_free(error);
581                 return IOTCON_ERROR_DBUS;
582         }
583
584         if (IOTCON_ERROR_NONE != ret) {
585                 ERR("iotcon-daemon Fail(%d)", ret);
586                 return icl_dbus_convert_daemon_error(ret);
587         }
588
589         return IOTCON_ERROR_NONE;
590 }