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