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