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