Fix invalid error handling
[platform/core/iot/iotcon.git] / lib / icl-presence.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 <string.h>
20 #include <errno.h>
21 #include <glib.h>
22
23 #include "iotcon-types.h"
24 #include "iotcon-internal.h"
25 #include "ic-utils.h"
26 #include "icl.h"
27 #include "icl-resource-types.h"
28 #include "icl-dbus.h"
29
30 #define ICL_PRESENCE_TTL_SECONDS_MAX (60 * 60 * 24) /* 60 sec/min * 60 min/hr * 24 hr/day */
31
32 typedef struct icl_presence {
33         char *host_address;
34         iotcon_connectivity_type_e connectivity_type;
35         char *resource_type;
36         iotcon_presence_cb cb;
37         void *user_data;
38         unsigned int sub_id;
39         int64_t handle;
40 } icl_presence_s;
41
42
43 typedef struct icl_presence_response {
44         char *host_address;
45         iotcon_connectivity_type_e connectivity_type;
46         char *resource_type;
47         iotcon_presence_result_e result;
48         iotcon_presence_trigger_e trigger;
49 } icl_presence_response_s;
50
51
52 API int iotcon_start_presence(unsigned int time_to_live)
53 {
54         FN_CALL;
55         int ret;
56         GError *error = NULL;
57
58         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
59         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
60         RETV_IF(ICL_PRESENCE_TTL_SECONDS_MAX < time_to_live, IOTCON_ERROR_INVALID_PARAMETER);
61
62         ic_dbus_call_start_presence_sync(icl_dbus_get_object(), time_to_live, &ret, NULL,
63                         &error);
64         if (error) {
65                 ERR("ic_dbus_call_start_presence_sync() Fail(%s)", error->message);
66                 ret = icl_dbus_convert_dbus_error(error->code);
67                 g_error_free(error);
68                 return ret;
69         }
70
71         if (IOTCON_ERROR_NONE != ret) {
72                 ERR("iotcon-daemon Fail(%d)", ret);
73                 return icl_dbus_convert_daemon_error(ret);
74         }
75
76         return IOTCON_ERROR_NONE;
77 }
78
79
80 API int iotcon_stop_presence(void)
81 {
82         FN_CALL;
83         int ret;
84         GError *error = NULL;
85
86         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
87         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_DBUS);
88
89         ic_dbus_call_stop_presence_sync(icl_dbus_get_object(), &ret, NULL, &error);
90         if (error) {
91                 ERR("ic_dbus_call_stop_presence_sync() Fail(%s)", error->message);
92                 ret = icl_dbus_convert_dbus_error(error->code);
93                 g_error_free(error);
94                 return ret;
95         }
96
97         if (IOTCON_ERROR_NONE != ret) {
98                 ERR("iotcon-daemon Fail(%d)", ret);
99                 return icl_dbus_convert_daemon_error(ret);
100         }
101
102         return IOTCON_ERROR_NONE;
103 }
104
105
106 static void _icl_presence_cb(GDBusConnection *connection,
107                 const gchar *sender_name,
108                 const gchar *object_path,
109                 const gchar *interface_name,
110                 const gchar *signal_name,
111                 GVariant *parameters,
112                 gpointer user_data)
113 {
114         FN_CALL;
115         unsigned int nonce;
116         char *host_address, *resource_type;
117         int res, connectivity_type, trigger;
118         icl_presence_s *presence = user_data;
119         iotcon_presence_cb cb = presence->cb;
120         icl_presence_response_s response = {0};
121
122         g_variant_get(parameters, "(iu&sii&s)", &res, &nonce, &host_address,
123                         &connectivity_type, &trigger, &resource_type);
124
125         response.resource_type = ic_utils_dbus_decode_str(resource_type);
126
127         if (response.resource_type && presence->resource_type) {
128                 if (IC_STR_EQUAL != strcmp(response.resource_type, presence->resource_type))
129                         return;
130         }
131
132         if (res < IOTCON_ERROR_NONE && cb)
133                 cb(presence, icl_dbus_convert_daemon_error(res), NULL, presence->user_data);
134
135         DBG("presence nonce : %u", nonce);
136
137         response.host_address = host_address;
138         response.connectivity_type = connectivity_type;
139         response.result = res;
140         response.trigger = trigger;
141
142         if (cb)
143                 cb(presence, IOTCON_ERROR_NONE, &response, presence->user_data);
144 }
145
146
147 static void _icl_presence_conn_cleanup(icl_presence_s *presence)
148 {
149         presence->sub_id = 0;
150
151         if (presence->handle) {
152                 presence->handle = 0;
153                 return;
154         }
155
156         free(presence->resource_type);
157         free(presence->host_address);
158         free(presence);
159 }
160
161
162 /* The length of resource_type should be less than or equal to 61. */
163 API int iotcon_add_presence_cb(const char *host_address,
164                 iotcon_connectivity_type_e connectivity_type,
165                 const char *resource_type,
166                 iotcon_presence_cb cb,
167                 void *user_data,
168                 iotcon_presence_h *presence_handle)
169 {
170         FN_CALL;
171         int ret;
172         unsigned int sub_id;
173         GError *error = NULL;
174         icl_presence_s *presence;
175         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
176
177         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
178         RETV_IF(NULL == icl_dbus_get_object(), IOTCON_ERROR_INVALID_PARAMETER);
179         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
180         RETV_IF(NULL == presence_handle, IOTCON_ERROR_INVALID_PARAMETER);
181
182         if (resource_type && (ICL_RESOURCE_TYPE_LENGTH_MAX < strlen(resource_type))) {
183                 ERR("The length of resource_type(%s) is invalid", resource_type);
184                 return IOTCON_ERROR_INVALID_PARAMETER;
185         }
186
187         if ((IOTCON_MULTICAST_ADDRESS == host_address || '\0' == host_address[0])
188                         && (IOTCON_CONNECTIVITY_IPV4 != connectivity_type
189                                 && IOTCON_CONNECTIVITY_ALL != connectivity_type)) {
190                 ERR("Multicast is available only if IPV4");
191                 return IOTCON_ERROR_INVALID_PARAMETER;
192         }
193
194         presence = calloc(1, sizeof(icl_presence_s));
195         if (NULL == presence) {
196                 ERR("calloc() Fail(%d)", errno);
197                 return IOTCON_ERROR_OUT_OF_MEMORY;
198         }
199
200         ic_dbus_call_subscribe_presence_sync(icl_dbus_get_object(),
201                         ic_utils_dbus_encode_str(host_address),
202                         connectivity_type,
203                         ic_utils_dbus_encode_str(resource_type),
204                         &(presence->handle),
205                         NULL,
206                         &error);
207         if (error) {
208                 ERR("ic_dbus_call_subscribe_presence_sync() Fail(%s)", error->message);
209                 ret = icl_dbus_convert_dbus_error(error->code);
210                 g_error_free(error);
211                 free(presence);
212                 return ret;
213         }
214
215         if (0 == presence->handle) {
216                 ERR("iotcon-daemon Fail");
217                 free(presence);
218                 return IOTCON_ERROR_IOTIVITY;
219         }
220
221         snprintf(signal_name, sizeof(signal_name), "%s_%llx", IC_DBUS_SIGNAL_PRESENCE,
222                         presence->handle);
223
224         presence->cb = cb;
225         presence->user_data = user_data;
226
227         if (host_address)
228                 presence->host_address = strdup(host_address);
229         presence->connectivity_type = connectivity_type;
230         if (resource_type)
231                 presence->resource_type = strdup(resource_type);
232
233         sub_id = icl_dbus_subscribe_signal(signal_name, presence,
234                         _icl_presence_conn_cleanup, _icl_presence_cb);
235         if (0 == sub_id) {
236                 ERR("icl_dbus_subscribe_signal() Fail");
237                 free(presence->resource_type);
238                 free(presence->host_address);
239                 free(presence);
240                 return IOTCON_ERROR_DBUS;
241         }
242
243         presence->sub_id = sub_id;
244
245         *presence_handle = presence;
246
247         return IOTCON_ERROR_NONE;
248 }
249
250
251 API int iotcon_remove_presence_cb(iotcon_presence_h presence)
252 {
253         FN_CALL;
254         int ret;
255         GError *error = NULL;
256
257         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
258         RETV_IF(NULL == presence, IOTCON_ERROR_INVALID_PARAMETER);
259
260         if (0 == presence->sub_id) { /* disconnected iotcon dbus */
261                 WARN("Invalid Presence handle");
262                 free(presence->resource_type);
263                 free(presence->host_address);
264                 free(presence);
265                 return IOTCON_ERROR_NONE;
266         }
267
268         if (NULL == icl_dbus_get_object()) {
269                 ERR("icl_dbus_get_object() return NULL");
270                 return IOTCON_ERROR_DBUS;
271         }
272
273         ic_dbus_call_unsubscribe_presence_sync(icl_dbus_get_object(), presence->handle,
274                         presence->host_address, &ret, NULL, &error);
275         if (error) {
276                 ERR("ic_dbus_call_unsubscribe_presence_sync() Fail(%s)", error->message);
277                 ret = icl_dbus_convert_dbus_error(error->code);
278                 g_error_free(error);
279                 return ret;
280         }
281
282         if (IOTCON_ERROR_NONE != ret) {
283                 ERR("iotcon-daemon Fail(%d)", ret);
284                 return icl_dbus_convert_daemon_error(ret);
285         }
286         presence->handle = 0;
287
288         icl_dbus_unsubscribe_signal(presence->sub_id);
289         presence->sub_id = 0;
290
291         return IOTCON_ERROR_NONE;
292 }
293
294
295 API int iotcon_presence_get_host_address(iotcon_presence_h presence, char **host_address)
296 {
297         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
298         RETV_IF(NULL == presence, IOTCON_ERROR_INVALID_PARAMETER);
299         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
300
301         *host_address = presence->host_address;
302
303         return IOTCON_ERROR_NONE;
304 }
305
306
307 API int iotcon_presence_get_connectivity_type(iotcon_presence_h presence,
308                 iotcon_connectivity_type_e *connectivity_type)
309 {
310         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
311         RETV_IF(NULL == presence, IOTCON_ERROR_INVALID_PARAMETER);
312         RETV_IF(NULL == connectivity_type, IOTCON_ERROR_INVALID_PARAMETER);
313
314         *connectivity_type = presence->connectivity_type;
315
316         return IOTCON_ERROR_NONE;
317 }
318
319
320 API int iotcon_presence_get_resource_type(iotcon_presence_h presence,
321                 char **resource_type)
322 {
323         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
324         RETV_IF(NULL == presence, IOTCON_ERROR_INVALID_PARAMETER);
325         RETV_IF(NULL == resource_type, IOTCON_ERROR_INVALID_PARAMETER);
326
327         *resource_type = presence->resource_type;
328
329         return IOTCON_ERROR_NONE;
330 }
331
332
333 API int iotcon_presence_response_get_host_address(iotcon_presence_response_h response,
334                 char **host_address)
335 {
336         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
337         RETV_IF(NULL == response, IOTCON_ERROR_INVALID_PARAMETER);
338         RETV_IF(NULL == host_address, IOTCON_ERROR_INVALID_PARAMETER);
339
340         *host_address = response->host_address;
341
342         return IOTCON_ERROR_NONE;
343 }
344
345
346 API int iotcon_presence_response_get_connectivity_type(
347                 iotcon_presence_response_h response, iotcon_connectivity_type_e *connectivity_type)
348 {
349         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
350         RETV_IF(NULL == response, IOTCON_ERROR_INVALID_PARAMETER);
351         RETV_IF(NULL == connectivity_type, IOTCON_ERROR_INVALID_PARAMETER);
352
353         *connectivity_type = response->connectivity_type;
354
355         return IOTCON_ERROR_NONE;
356 }
357
358
359 API int iotcon_presence_response_get_resource_type(iotcon_presence_response_h response,
360                 char **resource_type)
361 {
362         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
363         RETV_IF(NULL == response, IOTCON_ERROR_INVALID_PARAMETER);
364         RETV_IF(NULL == resource_type, IOTCON_ERROR_INVALID_PARAMETER);
365
366         *resource_type = response->resource_type;
367
368         return IOTCON_ERROR_NONE;
369 }
370
371
372 API int iotcon_presence_response_get_result(iotcon_presence_response_h response,
373                 iotcon_presence_result_e *result)
374 {
375         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
376         RETV_IF(NULL == response, IOTCON_ERROR_INVALID_PARAMETER);
377         RETV_IF(NULL == result, IOTCON_ERROR_INVALID_PARAMETER);
378
379         *result = response->result;
380
381         return IOTCON_ERROR_NONE;
382 }
383
384
385 API int iotcon_presence_response_get_trigger(iotcon_presence_response_h response,
386                 iotcon_presence_trigger_e *trigger)
387 {
388         RETV_IF(false == ic_utils_check_oic_feature_supported(), IOTCON_ERROR_NOT_SUPPORTED);
389         RETV_IF(NULL == response, IOTCON_ERROR_INVALID_PARAMETER);
390         RETV_IF(NULL == trigger, IOTCON_ERROR_INVALID_PARAMETER);
391
392         if (IOTCON_PRESENCE_OK != response->result) {
393                 ERR("trigger is valid if IOTCON_PRESENCE_OK");
394                 return IOTCON_ERROR_INVALID_PARAMETER;
395         }
396
397         *trigger = response->trigger;
398
399         return IOTCON_ERROR_NONE;
400 }
401