Initialize Tizen 2.3
[framework/system/coord.git] / src / shared / dbus.c
1 /*
2  * coord
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <errno.h>
24
25 #include "core/common.h"
26 #include "core/log.h"
27 #include "dbus.h"
28
29 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
30 #define DBUS_REPLY_TIMEOUT      (-1)
31
32 struct pending_call_data {
33         dbus_pending_cb func;
34         void *data;
35 };
36
37 int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
38 {
39         char *ch;
40         int i;
41         int int_type;
42         uint64_t int64_type;
43         DBusMessageIter arr;
44         struct dbus_byte *byte;
45
46         if (!sig || !param)
47                 return 0;
48
49         for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
50                 switch (*ch) {
51                 case 'i':
52                         int_type = atoi(param[i]);
53                         dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
54                         break;
55                 case 'u':
56                         int_type = strtoul(param[i], NULL, 10);
57                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
58                         break;
59                 case 't':
60                         int64_type = atoll(param[i]);
61                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
62                         break;
63                 case 's':
64                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &param[i]);
65                         break;
66                 case 'a':
67                         ++i, ++ch;
68                         switch (*ch) {
69                         case 'y':
70                                 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
71                                 byte = (struct dbus_byte*)param[i];
72                                 dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
73                                 dbus_message_iter_close_container(iter, &arr);
74                                 break;
75                         default:
76                                 break;
77                         }
78                         break;
79                 default:
80                         return -EINVAL;
81                 }
82         }
83
84         return 0;
85 }
86
87 DBusMessage *dbus_method_sync_with_reply(const char *dest, const char *path,
88                 const char *interface, const char *method,
89                 const char *sig, char *param[])
90 {
91         DBusConnection *conn;
92         DBusMessage *msg;
93         DBusMessageIter iter;
94         DBusMessage *reply;
95         DBusError err;
96         int r;
97
98         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
99         if (!conn) {
100                 _E("dbus_bus_get error");
101                 return NULL;
102         }
103
104         msg = dbus_message_new_method_call(dest, path, interface, method);
105         if (!msg) {
106                 _E("dbus_message_new_method_call(%s:%s-%s)",
107                         path, interface, method);
108                 return NULL;
109         }
110
111         dbus_message_iter_init_append(msg, &iter);
112         r = append_variant(&iter, sig, param);
113         if (r < 0) {
114                 _E("append_variant error(%d) %s %s:%s-%s",
115                         r, dest, path, interface, method);
116                 dbus_message_unref(msg);
117                 return NULL;
118         }
119
120         dbus_error_init(&err);
121
122         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
123         if (!reply) {
124                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
125                         dest, path, interface, method);
126         }
127
128         if (dbus_error_is_set(&err)) {
129                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
130                         err.name, err.message, dest, path, interface, method);
131                 dbus_error_free(&err);
132                 reply = NULL;
133         }
134
135         dbus_message_unref(msg);
136         return reply;
137 }
138
139 int dbus_method_sync(const char *dest, const char *path,
140                 const char *interface, const char *method,
141                 const char *sig, char *param[])
142 {
143         DBusConnection *conn;
144         DBusMessage *msg;
145         DBusMessageIter iter;
146         DBusMessage *reply;
147         DBusError err;
148         int ret, result;
149
150         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
151         if (!conn) {
152                 _E("dbus_bus_get error");
153                 return -EPERM;
154         }
155
156         msg = dbus_message_new_method_call(dest, path, interface, method);
157         if (!msg) {
158                 _E("dbus_message_new_method_call(%s:%s-%s)",
159                         path, interface, method);
160                 return -EBADMSG;
161         }
162
163         dbus_message_iter_init_append(msg, &iter);
164         ret = append_variant(&iter, sig, param);
165         if (ret < 0) {
166                 _E("append_variant error(%d) %s %s:%s-%s",
167                         ret, dest, path, interface, method);
168                 dbus_message_unref(msg);
169                 return ret;
170         }
171
172         dbus_error_init(&err);
173
174         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
175         dbus_message_unref(msg);
176         if (!reply) {
177                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
178                         err.name, err.message, dest, path, interface, method);
179                 dbus_error_free(&err);
180                 return -ECOMM;
181         }
182
183         ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
184         dbus_message_unref(reply);
185         if (!ret) {
186                 _E("no message : [%s:%s] %s %s:%s-%s",
187                         err.name, err.message, dest, path, interface, method);
188                 dbus_error_free(&err);
189                 return -ENOMSG;
190         }
191
192         return result;
193 }
194
195 int dbus_method_async(const char *dest, const char *path,
196                 const char *interface, const char *method,
197                 const char *sig, char *param[])
198 {
199         DBusConnection *conn;
200         DBusMessage *msg;
201         DBusMessageIter iter;
202         int ret;
203
204         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
205         if (!conn) {
206                 _E("dbus_bus_get error");
207                 return -EPERM;
208         }
209
210         msg = dbus_message_new_method_call(dest, path, interface, method);
211         if (!msg) {
212                 _E("dbus_message_new_method_call(%s:%s-%s)",
213                         path, interface, method);
214                 return -EBADMSG;
215         }
216
217         dbus_message_iter_init_append(msg, &iter);
218         ret = append_variant(&iter, sig, param);
219         if (ret < 0) {
220                 _E("append_variant error(%d) %s %s:%s-%s",
221                         ret, dest, path, interface, method);
222                 dbus_message_unref(msg);
223                 return ret;
224         }
225
226         ret = dbus_connection_send(conn, msg, NULL);
227         dbus_message_unref(msg);
228         if (ret != TRUE) {
229                 _E("dbus_connection_send error(%s %s:%s-%s)",
230                         dest, path, interface, method);
231                 return -ECOMM;
232         }
233
234         return 0;
235 }
236
237 static void cb_pending(DBusPendingCall *pending, void *user_data)
238 {
239         DBusMessage *msg;
240         DBusError err;
241         struct pending_call_data *data = user_data;
242         int ret;
243
244         ret = dbus_pending_call_get_completed(pending);
245         if (!ret) {
246                 _I("dbus_pending_call_get_completed() fail");
247                 free(data);
248                 dbus_pending_call_unref(pending);
249                 return;
250         }
251
252         dbus_error_init(&err);
253         msg = dbus_pending_call_steal_reply(pending);
254         if (!msg) {
255                 if (data->func) {
256                         dbus_set_error(&err, "org.tizen.system.deviced.NoReply",
257                                         "There was no reply to this method call");
258                         data->func(data->data, NULL, &err);
259                         dbus_error_free(&err);
260                 }
261                 return;
262         }
263
264         ret = dbus_set_error_from_message(&err, msg);
265         if (ret) {
266                 if (data->func)
267                         data->func(data->data, NULL, &err);
268                 dbus_error_free(&err);
269         } else {
270                 if (data->func)
271                         data->func(data->data, msg, &err);
272         }
273
274         dbus_message_unref(msg);
275         dbus_pending_call_unref(pending);
276 }
277
278 int dbus_method_async_with_reply(const char *dest, const char *path,
279                 const char *interface, const char *method,
280                 const char *sig, char *param[], dbus_pending_cb cb, int timeout, void *data)
281 {
282         DBusConnection *conn;
283         DBusMessage *msg;
284         DBusMessageIter iter;
285         DBusPendingCall *pending = NULL;
286         struct pending_call_data *pdata;
287         int ret;
288
289         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
290         if (!conn) {
291                 _E("dbus_bus_get error");
292                 return -EPERM;
293         }
294
295         msg = dbus_message_new_method_call(dest, path, interface, method);
296         if (!msg) {
297                 _E("dbus_message_new_method_call(%s:%s-%s)",
298                         path, interface, method);
299                 return -EBADMSG;
300         }
301
302         dbus_message_iter_init_append(msg, &iter);
303         ret = append_variant(&iter, sig, param);
304         if (ret < 0) {
305                 _E("append_variant error(%d)%s %s:%s-%s",
306                         ret, dest, path, interface, method);
307                 dbus_message_unref(msg);
308                 return ret;
309         }
310
311         ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
312         if (!ret) {
313                 dbus_message_unref(msg);
314                 _E("dbus_connection_send error(%s %s:%s-%s)",
315                         dest, path, interface, method);
316                 return -ECOMM;
317         }
318
319         if (cb && pending) {
320                 pdata = malloc(sizeof(struct pending_call_data));
321                 if (!pdata)
322                         return -ENOMEM;
323
324                 pdata->func = cb;
325                 pdata->data = data;
326
327                 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
328                 if (!ret) {
329                         free(pdata);
330                         dbus_message_unref(msg);
331                         dbus_pending_call_cancel(pending);
332                         return -ECOMM;
333                 }
334         }
335
336         return 0;
337 }
338
339 static void __CONSTRUCTOR__ dbus_init(void)
340 {
341         dbus_threads_init_default();
342 }