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