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