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