tizen 2.3 release
[kernel/api/system-resource.git] / src / common / edbus-handler.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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 /*
21  * @file edbus-handler.c
22  *
23  * @desc dbus handler using edbus interface
24  *
25  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
26  *
27  */
28
29 #include "trace.h"
30 #include "edbus-handler.h"
31 #include "macro.h"
32 #include "resourced.h"
33
34 #define EDBUS_INIT_RETRY_COUNT 5
35
36 struct edbus_list{
37         char *signal_name;
38         E_DBus_Signal_Handler *handler;
39 };
40
41 static struct edbus_object edbus_objects[] = {
42         { RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP   , NULL, NULL },
43         { RESOURCED_PATH_OOM, RESOURCED_INTERFACE_OOM, NULL, NULL },
44         { RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS, NULL, NULL },
45         { RESOURCED_PATH_NETWORK, RESOURCED_INTERFACE_NETWORK, NULL, NULL },
46         /* Add new object & interface here*/
47 };
48
49 static Eina_List *edbus_handler_list;
50 static int edbus_init_val;
51 static E_DBus_Connection *edbus_conn;
52 static DBusPendingCall *edbus_request_name;
53
54 static int append_variant(DBusMessageIter *iter,
55                 const char *sig, char *param[])
56 {
57         char *ch;
58         int i;
59         int int_type;
60         uint64_t int64_type;
61         DBusMessageIter arr;
62         struct dbus_byte *byte;
63
64         if (!sig || !param)
65                 return 0;
66
67         for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
68                 switch (*ch) {
69                 case 'i':
70                         int_type = atoi(param[i]);
71                         dbus_message_iter_append_basic(iter,
72                                 DBUS_TYPE_INT32, &int_type);
73                         break;
74                 case 'u':
75                         int_type = strtoul(param[i], NULL, 10);
76                         dbus_message_iter_append_basic(iter,
77                                 DBUS_TYPE_UINT32, &int_type);
78                         break;
79                 case 't':
80                         int64_type = atoll(param[i]);
81                         dbus_message_iter_append_basic(iter,
82                                 DBUS_TYPE_UINT64, &int64_type);
83                         break;
84                 case 's':
85                         dbus_message_iter_append_basic(iter,
86                                 DBUS_TYPE_STRING, &param[i]);
87                         break;
88                 case 'a':
89                         ++i, ++ch;
90                         switch (*ch) {
91                         case 'y':
92                                 dbus_message_iter_open_container(iter,
93                                         DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
94                                 byte = (struct dbus_byte*)param[i];
95                                 dbus_message_iter_append_fixed_array(&arr,
96                                         DBUS_TYPE_BYTE, &(byte->data), byte->size);
97                                 dbus_message_iter_close_container(iter, &arr);
98                                 break;
99                         default:
100                                 break;
101                         }
102                         break;
103                 case 'd':
104                         dbus_message_iter_append_basic(iter,
105                                 DBUS_TYPE_INT32, &param[i]);
106                         break;
107
108                 default:
109                         return -EINVAL;
110                 }
111         }
112
113         return 0;
114 }
115
116 void serialize_params(char *params[], size_t n, ...)
117 {
118         va_list va;
119         int i = 0;
120         va_start(va, n);
121         for (i = 0; i < n; ++i) {
122                 params[i] = va_arg(va, char *);
123         }
124         va_end(va);
125 }
126
127 DBusMessage *dbus_method_sync(const char *dest, const char *path,
128                 const char *interface, const char *method,
129                 const char *sig, char *param[])
130 {
131         DBusConnection *conn;
132         DBusMessage *msg;
133         DBusMessageIter iter;
134         DBusMessage *reply;
135         DBusError err;
136         int r;
137
138         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
139         if (!conn) {
140                 _E("dbus_bus_get error");
141                 return NULL;
142         }
143
144         msg = dbus_message_new_method_call(dest, path, interface, method);
145         if (!msg) {
146                 _E("dbus_message_new_method_call(%s:%s-%s)", path, interface, method);
147                 return NULL;
148         }
149
150         dbus_message_iter_init_append(msg, &iter);
151         r = append_variant(&iter, sig, param);
152         if (r < 0) {
153                 _E("append_variant error(%d)", r);
154                 dbus_message_unref(msg);
155                 return NULL;
156         }
157
158         dbus_error_init(&err);
159
160         reply = dbus_connection_send_with_reply_and_block(conn, msg,
161                         DBUS_REPLY_TIMEOUT, &err);
162         if (!reply) {
163                 _E("dbus_connection_send error(No reply)");
164         }
165
166         if (dbus_error_is_set(&err)) {
167                 _E("dbus_connection_send error(%s:%s)", err.name, err.message);
168                 dbus_error_free(&err);
169                 reply = NULL;
170         }
171
172         dbus_message_unref(msg);
173         return reply;
174 }
175
176 int dbus_method_async(const char *dest, const char *path,
177                 const char *interface, const char *method,
178                 const char *sig, char *param[])
179 {
180         DBusConnection *conn;
181         DBusMessage *msg;
182         DBusMessageIter iter;
183         int ret;
184
185         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
186         if (!conn) {
187                 _E("dbus_bus_get error");
188                 return -EPERM;
189         }
190
191         msg = dbus_message_new_method_call(dest, path, interface, method);
192         if (!msg) {
193                 _E("dbus_message_new_method_call(%s:%s-%s)", path, interface, method);
194                 return -EBADMSG;
195         }
196
197         dbus_message_iter_init_append(msg, &iter);
198         ret = append_variant(&iter, sig, param);
199         if (ret < 0) {
200                 _E("append_variant error(%d)", ret);
201                 dbus_message_unref(msg);
202                 return ret;
203         }
204
205         ret = dbus_connection_send(conn, msg, NULL);
206         dbus_message_unref(msg);
207         if (ret != TRUE) {
208                 _E("dbus_connection_send error");
209                 return -ECOMM;
210         }
211
212         return 0;
213 }
214
215 int register_edbus_interface(struct edbus_object *object)
216 {
217         int ret = RESOURCED_ERROR_FAIL;
218
219         if (!object) {
220                 _E("object is invalid value!");
221                 return ret;
222         }
223
224         object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
225         if (!object->obj) {
226                 _E("fail to add edbus obj");
227                 return ret;
228         }
229
230         object->iface = e_dbus_interface_new(object->interface);
231         if (!object->iface) {
232                 _E("fail to add edbus interface");
233                 return ret;
234         }
235
236         e_dbus_object_interface_attach(object->obj, object->iface);
237
238         return 0;
239 }
240
241 E_DBus_Interface *get_edbus_interface(const char *path)
242 {
243         int i;
244
245         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
246                 if (!strcmp(path, edbus_objects[i].path))
247                         return edbus_objects[i].iface;
248
249         return NULL;
250 }
251
252 pid_t get_edbus_sender_pid(DBusMessage *msg)
253 {
254         const char *sender;
255         DBusMessage *send_msg;
256         DBusPendingCall *pending;
257         DBusMessageIter iter;
258         int ret;
259         pid_t pid;
260
261         if (!msg) {
262                 _E("invalid argument!");
263                 return RESOURCED_ERROR_FAIL;
264         }
265
266         sender = dbus_message_get_sender(msg);
267         if (!sender) {
268                 _E("invalid sender!");
269                 return RESOURCED_ERROR_FAIL;
270         }
271
272         send_msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
273                                     DBUS_PATH_DBUS,
274                                     DBUS_INTERFACE_DBUS,
275                                     "GetConnectionUnixProcessID");
276         if (!send_msg) {
277                 _E("invalid send msg!");
278                 return RESOURCED_ERROR_FAIL;
279         }
280
281         ret = dbus_message_append_args(send_msg, DBUS_TYPE_STRING,
282                                     &sender, DBUS_TYPE_INVALID);
283         if (!ret) {
284                 _E("fail to append args!");
285                 dbus_message_unref(send_msg);
286                 return RESOURCED_ERROR_FAIL;
287         }
288
289         pending = e_dbus_message_send(edbus_conn, send_msg, NULL, -1, NULL);
290         if (!pending) {
291                 _E("pending is null!");
292                 dbus_message_unref(send_msg);
293                 return RESOURCED_ERROR_FAIL;
294         }
295
296         dbus_message_unref(send_msg);
297
298         /* block until reply is received */
299         dbus_pending_call_block(pending);
300
301         msg = dbus_pending_call_steal_reply(pending);
302         dbus_pending_call_unref(pending);
303         if (!msg) {
304                 _E("reply msg is null!");
305                 return RESOURCED_ERROR_FAIL;
306         }
307
308         dbus_message_iter_init(msg, &iter);
309         dbus_message_iter_get_basic(&iter, &pid);
310         dbus_message_unref(msg);
311
312         return pid;
313 }
314
315 static void unregister_edbus_signal_handle(void)
316 {
317         Eina_List *search;
318         Eina_List *serach_next;
319         struct edbus_list *entry;
320
321         EINA_LIST_FOREACH_SAFE(edbus_handler_list, search, serach_next, entry) {
322                 if (entry != NULL) {
323                         e_dbus_signal_handler_del(edbus_conn, entry->handler);
324                         edbus_handler_list = eina_list_remove(edbus_handler_list, entry);
325                         free(entry->signal_name);
326                         free(entry);
327                 }
328         }
329 }
330
331 int register_edbus_signal_handler(const char *path, const char *interface,
332                 const char *name, E_DBus_Signal_Cb cb)
333 {
334         Eina_List *search;
335         struct edbus_list *entry;
336         E_DBus_Signal_Handler *handler;
337
338         EINA_LIST_FOREACH(edbus_handler_list, search, entry) {
339                 if (entry != NULL && strncmp(entry->signal_name, name, strlen(name)) == 0)
340                         return RESOURCED_ERROR_FAIL;
341         }
342
343         handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
344                                 interface, name, cb, NULL);
345
346         if (!handler) {
347                 _E("fail to add edbus handler");
348                 return RESOURCED_ERROR_FAIL;
349         }
350
351         entry = malloc(sizeof(struct edbus_list));
352
353         if (!entry) {
354                 _E("Malloc failed");
355                 return RESOURCED_ERROR_FAIL;
356         }
357
358         entry->signal_name = strndup(name, strlen(name));
359
360         if (!entry->signal_name) {
361                 _E("Malloc failed");
362                 free(entry);
363                 return -1;
364         }
365
366         entry->handler = handler;
367         edbus_handler_list = eina_list_prepend(edbus_handler_list, entry);
368         if (!edbus_handler_list) {
369                 _E("eina_list_prepend failed");
370                 free(entry->signal_name);
371                 free(entry);
372                 return RESOURCED_ERROR_FAIL;
373         }
374         return RESOURCED_ERROR_NONE;
375 }
376
377 int broadcast_edbus_signal_str(const char *path, const char *interface,
378                 const char *name, const char *sig, char *param[])
379 {
380         DBusMessage *msg;
381         DBusConnection *conn;
382         DBusMessageIter iter;
383         int r;
384
385         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
386         if (!conn) {
387                 _E("dbus_bus_get error");
388                 return -EPERM;
389         }
390
391         msg = dbus_message_new_signal(path, interface, name);
392         if (!msg) {
393                 _E("fail to allocate new %s.%s signal", interface, name);
394                 return -EPERM;
395         }
396
397         dbus_message_iter_init_append(msg, &iter);
398         r = append_variant(&iter, sig, param);
399         if (r < 0) {
400                 _E("append_variant error(%d)", r);
401                 return -EPERM;
402         }
403
404         r = dbus_connection_send(conn, msg, NULL);
405         dbus_message_unref(msg);
406
407         if (r != TRUE) {
408                 _E("dbus_connection_send error(%s:%s-%s)",
409                         path, interface, name);
410                 return -ECOMM;
411         }
412
413         return RESOURCED_ERROR_NONE;
414 }
415
416 int broadcast_edbus_signal(const char *path, const char *interface,
417                 const char *name, int type, void *value)
418 {
419         DBusConnection *conn;
420         DBusMessage *msg = dbus_message_new_signal(path, interface, name);
421         int r;
422
423         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
424         if (!conn) {
425                 _E("dbus_bus_get error");
426                 return -EPERM;
427         }
428
429         if (!msg) {
430                 _E("fail to allocate new %s.%s signal", interface, name);
431                 return RESOURCED_ERROR_FAIL;
432         }
433
434         dbus_message_append_args(msg, type, value, DBUS_TYPE_INVALID);
435
436         r = dbus_connection_send(conn, msg, NULL);
437         dbus_message_unref(msg);
438
439         if (r != TRUE) {
440                 _E("dbus_connection_send error(%s:%s-%s)",
441                         path, interface, name);
442                 return -ECOMM;
443         }
444
445         return RESOURCED_ERROR_NONE;
446 }
447
448 resourced_ret_c edbus_add_methods(const char *path,
449                        const struct edbus_method *const edbus_methods,
450                        const size_t size)
451 {
452         E_DBus_Interface *iface;
453         int i;
454         int ret;
455
456         iface = get_edbus_interface(path);
457
458         if (!iface) {
459                 _E("Fail to get edbus interface! Path = %s\n", path);
460                 return RESOURCED_ERROR_FAIL;
461         }
462
463         for (i = 0; i < size; i++) {
464                 ret = e_dbus_interface_method_add(iface,
465                                     edbus_methods[i].member,
466                                     edbus_methods[i].signature,
467                                     edbus_methods[i].reply_signature,
468                                     edbus_methods[i].func);
469                 if (!ret) {
470                         _E("Fail to add method %s!\n",
471                                 edbus_methods[i].member);
472                         return RESOURCED_ERROR_FAIL;
473                 }
474         }
475
476         return RESOURCED_ERROR_NONE;
477 }
478
479 static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
480 {
481         DBusError err;
482         unsigned int val;
483         int r;
484
485         if (!msg) {
486                 _D("invalid DBusMessage!");
487                 return;
488         }
489
490         dbus_error_init(&err);
491         r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
492         if (!r) {
493                 _E("no message : [%s:%s]", err.name, err.message);
494                 dbus_error_free(&err);
495                 return;
496         }
497
498         _I("Request Name reply : %d", val);
499 }
500
501 void edbus_init(void)
502 {
503         int retry = RESOURCED_ERROR_NONE;
504         int i;
505 retry_init:
506         edbus_init_val = e_dbus_init();
507         if (edbus_init_val)
508                 goto retry_bus_get;
509         if (retry == EDBUS_INIT_RETRY_COUNT) {
510                 _E("fail to init edbus");
511                 return;
512         }
513         retry++;
514         goto retry_init;
515
516 retry_bus_get:
517         retry = 0;
518         edbus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
519         if (edbus_conn)
520                 goto retry_bus_request;
521         if (retry == EDBUS_INIT_RETRY_COUNT) {
522                 _E("fail to get edbus");
523                 return;
524         }
525         retry++;
526         goto retry_bus_get;
527
528 retry_bus_request:
529         retry = 0;
530         edbus_request_name = e_dbus_request_name(edbus_conn, BUS_NAME,
531                         DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
532         if (edbus_request_name)
533                 goto register_objects;
534         if (retry == EDBUS_INIT_RETRY_COUNT) {
535                 _E("fail to request edbus name");
536                 return;
537         }
538         retry++;
539         goto retry_bus_request;
540
541 register_objects:
542         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
543                 int ret;
544
545                 ret = register_edbus_interface(&edbus_objects[i]);
546                 if (ret < 0) {
547                         _E("fail to add obj & interface for %s",
548                                     edbus_objects[i].interface);
549                         return;
550                 }
551
552                 _I("add new obj for %s", edbus_objects[i].interface);
553         }
554
555         _I("start edbus service");
556 }
557
558 void edbus_exit(void)
559 {
560         unregister_edbus_signal_handle();
561         e_dbus_connection_close(edbus_conn);
562         e_dbus_shutdown();
563 }