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