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