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