Fix invalid error handling
[platform/core/iot/iotcon.git] / lib / icl-remote-resource-crud.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 <stdio.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <glib.h>
21 #include <gio/gio.h>
22
23 #include "iotcon.h"
24 #include "ic-utils.h"
25 #include "ic-dbus.h"
26 #include "icl.h"
27 #include "icl-options.h"
28 #include "icl-dbus.h"
29 #include "icl-dbus-type.h"
30 #include "icl-representation.h"
31 #include "icl-response.h"
32 #include "icl-remote-resource.h"
33 #include "icl-payload.h"
34
35 typedef struct {
36         iotcon_remote_resource_response_cb cb;
37         void *user_data;
38         iotcon_remote_resource_h resource;
39 } icl_on_response_s;
40
41 typedef struct {
42         iotcon_remote_resource_observe_cb cb;
43         void *user_data;
44         iotcon_remote_resource_h resource;
45 } icl_on_observe_s;
46
47 static GList *icl_crud_cb_list = NULL;
48
49 void icl_remote_resource_crud_stop(iotcon_remote_resource_h resource)
50 {
51         GList *c;
52         for (c = icl_crud_cb_list; c; c = c->next) {
53                 icl_on_response_s *cb_container = c->data;
54                 if (NULL == cb_container) {
55                         ERR("cb_container is NULL");
56                         continue;
57                 }
58                 if (cb_container->resource == resource)
59                         cb_container->cb = NULL;
60         }
61 }
62
63 static iotcon_options_h _icl_parse_options_iter(GVariantIter *iter)
64 {
65         int ret;
66         iotcon_options_h options = NULL;
67
68         if (NULL == iter)
69                 return NULL;
70
71         if (g_variant_iter_n_children(iter)) {
72                 unsigned short option_id;
73                 char *option_data;
74
75                 ret = iotcon_options_create(&options);
76                 if (IOTCON_ERROR_NONE != ret) {
77                         ERR("iotcon_options_create() Fail(%d)", ret);
78                         return NULL;
79                 }
80                 while (g_variant_iter_loop(iter, "(q&s)", &option_id, &option_data))
81                         iotcon_options_add(options, option_id, option_data);
82         }
83         return options;
84 }
85
86 static int _icl_parse_crud_gvariant(iotcon_request_type_e request_type,
87                 GVariant *gvar, iotcon_response_h *response)
88 {
89         int res;
90         GVariantIter *options_iter = NULL;
91         GVariant *repr_gvar = NULL;
92         iotcon_response_h resp = NULL;
93         iotcon_options_h options = NULL;
94         iotcon_representation_h repr = NULL;
95
96         if (IOTCON_REQUEST_DELETE == request_type)
97                 g_variant_get(gvar, "(a(qs)i)", &options_iter, &res);
98         else
99                 g_variant_get(gvar, "(a(qs)vi)", &options_iter, &repr_gvar, &res);
100
101         if (options_iter) {
102                 options = _icl_parse_options_iter(options_iter);
103                 g_variant_iter_free(options_iter);
104         }
105
106         if (repr_gvar) {
107                 repr = icl_representation_from_gvariant(repr_gvar);
108                 if (NULL == repr) {
109                         ERR("icl_representation_from_gvariant() Fail");
110                         if (options)
111                                 iotcon_options_destroy(options);
112                         return IOTCON_ERROR_SYSTEM;
113                 }
114         }
115
116         res = icl_dbus_convert_daemon_error(res);
117
118         resp = calloc(1, sizeof(struct icl_resource_response));
119         if (NULL == resp) {
120                 ERR("calloc() Fail(%d)", errno);
121                 if (repr)
122                         iotcon_representation_destroy(repr);
123                 if (options)
124                         iotcon_options_destroy(options);
125                 return IOTCON_ERROR_OUT_OF_MEMORY;
126         }
127         resp->result = res;
128         resp->repr = repr;
129         resp->header_options = options;
130
131         *response = resp;
132
133         return IOTCON_ERROR_NONE;
134 }
135
136 static void _icl_on_crud_cb(iotcon_request_type_e request_type,
137                 GObject *object, GAsyncResult *g_async_res, icl_on_response_s *cb_container)
138 {
139         int ret;
140         iotcon_response_h response = NULL;
141         GVariant *result;
142         GError *error = NULL;
143
144         RET_IF(NULL == cb_container);
145
146         icl_crud_cb_list = g_list_remove(icl_crud_cb_list, cb_container);
147
148         switch (request_type) {
149         case IOTCON_REQUEST_GET:
150                 ic_dbus_call_get_finish(IC_DBUS(object), &result, g_async_res, &error);
151                 break;
152         case IOTCON_REQUEST_PUT:
153                 ic_dbus_call_put_finish(IC_DBUS(object), &result, g_async_res, &error);
154                 break;
155         case IOTCON_REQUEST_POST:
156                 ic_dbus_call_post_finish(IC_DBUS(object), &result, g_async_res, &error);
157                 break;
158         case IOTCON_REQUEST_DELETE:
159                 ic_dbus_call_delete_finish(IC_DBUS(object), &result, g_async_res, &error);
160                 break;
161         default:
162                 ERR("Invalid type(%d)", request_type);
163                 return;
164         }
165
166         if (error) {
167                 ERR("ic_dbus_call_finish() Fail(%d, %s)", request_type, error->message);
168                 if (cb_container->cb) {
169                         int ret = icl_dbus_convert_dbus_error(error->code);
170                         cb_container->cb(cb_container->resource, ret, request_type, NULL,
171                                         cb_container->user_data);
172                 }
173                 g_error_free(error);
174                 free(cb_container);
175                 return;
176         }
177
178         ret = _icl_parse_crud_gvariant(request_type, result, &response);
179         if (IOTCON_ERROR_NONE != ret) {
180                 ERR("_icl_parse_crud_gvariant() Fail(%s)", ret);
181                 if (cb_container->cb) {
182                         cb_container->cb(cb_container->resource, ret, request_type, NULL,
183                                         cb_container->user_data);
184                 }
185                 free(cb_container);
186                 return;
187         }
188         if (cb_container->cb)
189                 cb_container->cb(cb_container->resource, IOTCON_ERROR_NONE, request_type,
190                                 response, cb_container->user_data);
191
192         if (response)
193                 iotcon_response_destroy(response);
194
195         free(cb_container);
196 }
197
198
199 static void _icl_on_get_cb(GObject *object, GAsyncResult *g_async_res,
200                 gpointer user_data)
201 {
202         _icl_on_crud_cb(IOTCON_REQUEST_GET, object, g_async_res, user_data);
203 }
204
205
206 static void _icl_on_put_cb(GObject *object, GAsyncResult *g_async_res,
207                 gpointer user_data)
208 {
209         _icl_on_crud_cb(IOTCON_REQUEST_PUT, object, g_async_res, user_data);
210 }
211
212
213 static void _icl_on_post_cb(GObject *object, GAsyncResult *g_async_res,
214                 gpointer user_data)
215 {
216         _icl_on_crud_cb(IOTCON_REQUEST_POST, object, g_async_res, user_data);
217 }
218
219
220 API int iotcon_remote_resource_get(iotcon_remote_resource_h resource,
221                 iotcon_query_h query, iotcon_remote_resource_response_cb cb, void *user_data)
222 {
223         GVariant *arg_query;
224         GVariant *arg_remote_resource;
225         icl_on_response_s *cb_container;
226
227         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
228         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
229         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
230         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
231
232         cb_container = calloc(1, sizeof(icl_on_response_s));
233         if (NULL == cb_container) {
234                 ERR("calloc() Fail(%d)", errno);
235                 return IOTCON_ERROR_OUT_OF_MEMORY;
236         }
237
238         cb_container->resource = resource;
239         cb_container->cb = cb;
240         cb_container->user_data = user_data;
241
242         arg_remote_resource = icl_dbus_remote_resource_to_gvariant(resource);
243         arg_query = icl_dbus_query_to_gvariant(query);
244
245         ic_dbus_call_get(icl_dbus_get_object(), arg_remote_resource, arg_query, NULL,
246                         _icl_on_get_cb, cb_container);
247
248         icl_crud_cb_list = g_list_append(icl_crud_cb_list, cb_container);
249
250         return IOTCON_ERROR_NONE;
251 }
252
253
254 API int iotcon_remote_resource_put(iotcon_remote_resource_h resource,
255                 iotcon_representation_h repr,
256                 iotcon_query_h query,
257                 iotcon_remote_resource_response_cb cb,
258                 void *user_data)
259 {
260         GVariant *arg_repr;
261         GVariant *arg_remote_resource;
262         GVariant *arg_query;
263         icl_on_response_s *cb_container;
264
265         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
266         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
267         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
268         RETV_IF(NULL == repr, IOTCON_ERROR_INVALID_PARAMETER);
269         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
270
271         cb_container = calloc(1, sizeof(icl_on_response_s));
272         if (NULL == cb_container) {
273                 ERR("calloc() Fail(%d)", errno);
274                 return IOTCON_ERROR_OUT_OF_MEMORY;
275         }
276
277         cb_container->resource = resource;
278         cb_container->cb = cb;
279         cb_container->user_data = user_data;
280
281         arg_repr = icl_representation_to_gvariant(repr);
282         if (NULL == arg_repr) {
283                 ERR("icl_representation_to_gvariant() Fail");
284                 free(cb_container);
285                 return IOTCON_ERROR_REPRESENTATION;
286         }
287
288         arg_remote_resource = icl_dbus_remote_resource_to_gvariant(resource);
289         arg_query = icl_dbus_query_to_gvariant(query);
290
291         ic_dbus_call_put(icl_dbus_get_object(), arg_remote_resource, arg_repr, arg_query,
292                         NULL, _icl_on_put_cb, cb_container);
293
294         icl_crud_cb_list = g_list_append(icl_crud_cb_list, cb_container);
295
296         return IOTCON_ERROR_NONE;
297 }
298
299
300 API int iotcon_remote_resource_post(iotcon_remote_resource_h resource,
301                 iotcon_representation_h repr,
302                 iotcon_query_h query,
303                 iotcon_remote_resource_response_cb cb,
304                 void *user_data)
305 {
306         GVariant *arg_repr;
307         GVariant *arg_query;
308         GVariant *arg_remote_resource;
309         icl_on_response_s *cb_container;
310
311         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
312         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
313         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
314         RETV_IF(NULL == repr, IOTCON_ERROR_INVALID_PARAMETER);
315         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
316
317         cb_container = calloc(1, sizeof(icl_on_response_s));
318         if (NULL == cb_container) {
319                 ERR("calloc() Fail(%d)", errno);
320                 return IOTCON_ERROR_OUT_OF_MEMORY;
321         }
322
323         cb_container->resource = resource;
324         cb_container->cb = cb;
325         cb_container->user_data = user_data;
326
327         arg_repr = icl_representation_to_gvariant(repr);
328         if (NULL == arg_repr) {
329                 ERR("icl_representation_to_gvariant() Fail");
330                 free(cb_container);
331                 return IOTCON_ERROR_REPRESENTATION;
332         }
333
334         arg_remote_resource = icl_dbus_remote_resource_to_gvariant(resource);
335         arg_query = icl_dbus_query_to_gvariant(query);
336
337         ic_dbus_call_post(icl_dbus_get_object(), arg_remote_resource, arg_repr, arg_query,
338                         NULL, _icl_on_post_cb, cb_container);
339
340         icl_crud_cb_list = g_list_append(icl_crud_cb_list, cb_container);
341
342         return IOTCON_ERROR_NONE;
343 }
344
345
346 static void _icl_on_delete_cb(GObject *object, GAsyncResult *g_async_res,
347                 gpointer user_data)
348 {
349         _icl_on_crud_cb(IOTCON_REQUEST_DELETE, object, g_async_res, user_data);
350 }
351
352
353 API int iotcon_remote_resource_delete(iotcon_remote_resource_h resource,
354                 iotcon_remote_resource_response_cb cb, void *user_data)
355 {
356         GVariant *arg_remote_resource;
357         icl_on_response_s *cb_container;
358
359         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
360         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
361         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
362         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
363
364         cb_container = calloc(1, sizeof(icl_on_response_s));
365         if (NULL == cb_container) {
366                 ERR("calloc() Fail(%d)", errno);
367                 return IOTCON_ERROR_OUT_OF_MEMORY;
368         }
369
370         cb_container->resource = resource;
371         cb_container->cb = cb;
372         cb_container->user_data = user_data;
373
374         arg_remote_resource = icl_dbus_remote_resource_to_gvariant(resource);
375
376         ic_dbus_call_delete(icl_dbus_get_object(), arg_remote_resource, NULL,
377                         _icl_on_delete_cb, cb_container);
378
379         icl_crud_cb_list = g_list_append(icl_crud_cb_list, cb_container);
380
381         return IOTCON_ERROR_NONE;
382 }
383
384 static void _icl_on_observe_cb(GDBusConnection *connection,
385                 const gchar *sender_name,
386                 const gchar *object_path,
387                 const gchar *interface_name,
388                 const gchar *signal_name,
389                 GVariant *parameters,
390                 gpointer user_data)
391 {
392         int res;
393         int seq_number = -1;
394         GVariantIter *options_iter = NULL;
395         GVariant *repr_gvar = NULL;
396         iotcon_response_h response = NULL;
397         icl_on_observe_s *cb_container = user_data;
398         iotcon_options_h options = NULL;
399         iotcon_representation_h repr = NULL;
400
401         RET_IF(NULL == cb_container);
402
403         g_variant_get(parameters, "(a(qs)vii)", &options_iter, &repr_gvar, &res, &seq_number);
404
405         if (options_iter) {
406                 options = _icl_parse_options_iter(options_iter);
407                 g_variant_iter_free(options_iter);
408         }
409
410         if (repr_gvar) {
411                 repr = icl_representation_from_gvariant(repr_gvar);
412                 if (NULL == repr) {
413                         ERR("icl_representation_from_gvariant() Fail");
414                         if (options)
415                                 iotcon_options_destroy(options);
416
417                         if (cb_container->cb)
418                                 cb_container->cb(cb_container->resource, IOTCON_ERROR_SYSTEM, -1,
419                                                 NULL, cb_container->user_data);
420                         return;
421                 }
422         }
423
424         res = icl_dbus_convert_daemon_error(res);
425
426         response = calloc(1, sizeof(struct icl_resource_response));
427         if (NULL == response) {
428                 ERR("calloc() Fail(%d)", errno);
429                 if (repr)
430                         iotcon_representation_destroy(repr);
431                 if (options)
432                         iotcon_options_destroy(options);
433
434                 if (cb_container->cb)
435                         cb_container->cb(cb_container->resource, IOTCON_ERROR_OUT_OF_MEMORY, -1,
436                                         NULL, cb_container->user_data);
437                 return;
438         }
439         response->result = res;
440         response->repr = repr;
441         response->header_options = options;
442
443         if (cb_container->cb)
444                 cb_container->cb(cb_container->resource, IOTCON_ERROR_NONE, seq_number,
445                                 response, cb_container->user_data);
446
447         if (response)
448                 iotcon_response_destroy(response);
449 }
450
451
452 static void _icl_observe_conn_cleanup(icl_on_observe_s *cb_container)
453 {
454         cb_container->resource->observe_handle = 0;
455         cb_container->resource->observe_sub_id = 0;
456         icl_remote_resource_unref(cb_container->resource);
457         free(cb_container);
458 }
459
460
461 API int iotcon_remote_resource_observe_register(iotcon_remote_resource_h resource,
462                 iotcon_observe_policy_e observe_policy,
463                 iotcon_query_h query,
464                 iotcon_remote_resource_observe_cb cb,
465                 void *user_data)
466 {
467         int ret;
468         unsigned int sub_id;
469         GError *error = NULL;
470         int64_t signal_number;
471         int64_t observe_handle;
472         icl_on_observe_s *cb_container;
473         GVariant *arg_query, *arg_remote_resource;
474         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
475
476         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
477         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
478         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
479         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
480         RETV_IF(resource->observe_handle || resource->observe_sub_id, IOTCON_ERROR_ALREADY);
481
482         arg_remote_resource = icl_dbus_remote_resource_to_gvariant(resource);
483         arg_query = icl_dbus_query_to_gvariant(query);
484
485         cb_container = calloc(1, sizeof(icl_on_observe_s));
486         if (NULL == cb_container) {
487                 ERR("calloc() Fail(%d)", errno);
488                 g_variant_unref(arg_query);
489                 g_variant_unref(arg_remote_resource);
490                 return IOTCON_ERROR_OUT_OF_MEMORY;
491         }
492
493         cb_container->resource = resource;
494         cb_container->cb = cb;
495         cb_container->user_data = user_data;
496
497         ic_dbus_call_observer_start_sync(icl_dbus_get_object(), arg_remote_resource,
498                         observe_policy, arg_query, &signal_number, &observe_handle, NULL, &error);
499         if (error) {
500                 ERR("ic_dbus_call_observer_start_sync() Fail(%s)", error->message);
501                 ret = icl_dbus_convert_dbus_error(error->code);
502                 g_error_free(error);
503                 g_variant_unref(arg_query);
504                 g_variant_unref(arg_remote_resource);
505                 free(cb_container);
506                 return ret;
507         }
508         if (0 == observe_handle) {
509                 ERR("iotcon-daemon Fail");
510                 free(cb_container);
511                 return IOTCON_ERROR_IOTIVITY;
512         }
513
514         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_OBSERVE,
515                         signal_number);
516
517         sub_id = icl_dbus_subscribe_signal(signal_name, cb_container,
518                         _icl_observe_conn_cleanup, _icl_on_observe_cb);
519         if (0 == sub_id) {
520                 ERR("icl_dbus_subscribe_signal() Fail");
521                 free(cb_container);
522                 return IOTCON_ERROR_DBUS;
523         }
524
525         resource->observe_sub_id = sub_id;
526         resource->observe_handle = observe_handle;
527         icl_remote_resource_ref(resource);
528
529         return IOTCON_ERROR_NONE;
530 }
531
532
533 API int iotcon_remote_resource_observe_deregister(iotcon_remote_resource_h resource)
534 {
535         int ret;
536         GError *error = NULL;
537         GVariant *arg_options;
538
539         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
540         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
541         RETV_IF(NULL == resource, IOTCON_ERROR_INVALID_PARAMETER);
542         if (0 == resource->observe_handle) {
543                 ERR("It doesn't have a observe_handle");
544                 return IOTCON_ERROR_INVALID_PARAMETER;
545         }
546
547         arg_options = icl_dbus_options_to_gvariant(resource->header_options);
548
549         ic_dbus_call_observer_stop_sync(icl_dbus_get_object(), resource->observe_handle,
550                         arg_options, &ret, NULL, &error);
551         if (error) {
552                 ERR("ic_dbus_call_observer_stop_sync() Fail(%s)", error->message);
553                 ret = icl_dbus_convert_dbus_error(error->code);
554                 g_error_free(error);
555                 return ret;
556         }
557         if (IOTCON_ERROR_NONE != ret) {
558                 ERR("iotcon-daemon Fail(%d)", ret);
559                 return icl_dbus_convert_daemon_error(ret);
560         }
561         resource->observe_handle = 0;
562
563         icl_dbus_unsubscribe_signal(resource->observe_sub_id);
564         resource->observe_sub_id = 0;
565
566
567         return IOTCON_ERROR_NONE;
568 }
569