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