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