75461755bdf2b1a71cc6a462396e54396762b4a3
[platform/core/system/system-server.git] / src / core / edbus-handler.c
1 /*
2  * deviced
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 "core/log.h"
21 #include "core/data.h"
22 #include "core/edbus-handler.h"
23 #include "core/common.h"
24 #include "core/devices.h"
25 #include "core/device-notifier.h"
26 #include "core/list.h"
27
28 #define EDBUS_INIT_RETRY_COUNT 5
29 #define NAME_OWNER_CHANGED "NameOwnerChanged"
30 #define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus',\
31         path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',\
32         member='NameOwnerChanged',arg0='%s'"
33
34
35 struct edbus_list{
36         char *signal_name;
37         E_DBus_Signal_Handler *handler;
38 };
39
40 static struct edbus_object {
41         const char *path;
42         const char *interface;
43         E_DBus_Object *obj;
44         E_DBus_Interface *iface;
45 } edbus_objects[] = {
46         { DEVICED_PATH_CORE   , DEVICED_INTERFACE_CORE   , NULL, NULL },
47         { DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY, NULL, NULL },
48         { DEVICED_PATH_STORAGE, DEVICED_INTERFACE_STORAGE, NULL, NULL },
49         /* Add new object & interface here*/
50 };
51
52 static Eina_List *edbus_handler_list;
53 static Eina_List *edbus_watch_list;
54 static int edbus_init_val;
55 static DBusConnection *conn;
56 static E_DBus_Connection *edbus_conn;
57 static DBusPendingCall *edbus_request_name;
58
59 static int register_edbus_interface(struct edbus_object *object)
60 {
61         int ret;
62
63         if (!object) {
64                 _E("object is invalid value!");
65                 return -1;
66         }
67
68         object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
69         if (!object->obj) {
70                 _E("fail to add edbus obj");
71                 return -1;
72         }
73
74         object->iface = e_dbus_interface_new(object->interface);
75         if (!object->iface) {
76                 _E("fail to add edbus interface");
77                 return -1;
78         }
79
80         e_dbus_object_interface_attach(object->obj, object->iface);
81
82         return 0;
83 }
84
85 E_DBus_Interface *get_edbus_interface(const char *path)
86 {
87         int i;
88
89         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
90                 if (!strcmp(path, edbus_objects[i].path))
91                         return edbus_objects[i].iface;
92
93         return NULL;
94 }
95
96 pid_t get_edbus_sender_pid(DBusMessage *msg)
97 {
98         const char *sender;
99         DBusMessage *send_msg;
100         DBusPendingCall *pending;
101         DBusMessageIter iter;
102         int ret;
103         pid_t pid;
104
105         if (!msg) {
106                 _E("invalid argument!");
107                 return -1;
108         }
109
110         sender = dbus_message_get_sender(msg);
111         if (!sender) {
112                 _E("invalid sender!");
113                 return -1;
114         }
115
116         send_msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
117                                     DBUS_PATH_DBUS,
118                                     DBUS_INTERFACE_DBUS,
119                                     "GetConnectionUnixProcessID");
120         if (!send_msg) {
121                 _E("invalid send msg!");
122                 return -1;
123         }
124
125         ret = dbus_message_append_args(send_msg, DBUS_TYPE_STRING,
126                                     &sender, DBUS_TYPE_INVALID);
127         if (!ret) {
128                 _E("fail to append args!");
129                 dbus_message_unref(send_msg);
130                 return -1;
131         }
132
133         pending = e_dbus_message_send(edbus_conn, send_msg, NULL, -1, NULL);
134         if (!pending) {
135                 _E("pending is null!");
136                 dbus_message_unref(send_msg);
137                 return -1;
138         }
139
140         dbus_message_unref(send_msg);
141
142         /* block until reply is received */
143         dbus_pending_call_block(pending);
144
145         msg = dbus_pending_call_steal_reply(pending);
146         dbus_pending_call_unref(pending);
147         if (!msg) {
148                 _E("reply msg is null!");
149                 return -1;
150         }
151
152         dbus_message_iter_init(msg, &iter);
153         dbus_message_iter_get_basic(&iter, &pid);
154         dbus_message_unref(msg);
155
156         return pid;
157 }
158
159 static void unregister_edbus_signal_handle(void)
160 {
161         Eina_List *tmp;
162         Eina_List *tmp_next;
163         struct edbus_list *entry;
164
165         EINA_LIST_FOREACH_SAFE(edbus_handler_list, tmp, tmp_next, entry) {
166                 if (entry != NULL) {
167                         e_dbus_signal_handler_del(edbus_conn, entry->handler);
168                         edbus_handler_list = eina_list_remove(edbus_handler_list, entry);
169                         free(entry->signal_name);
170                         free(entry);
171                 }
172         }
173 }
174
175 int register_edbus_signal_handler(const char *path, const char *interface,
176                 const char *name, E_DBus_Signal_Cb cb)
177 {
178         Eina_List *tmp;
179         struct edbus_list *entry;
180         E_DBus_Signal_Handler *handler;
181
182         EINA_LIST_FOREACH(edbus_handler_list, tmp, entry) {
183                 if (entry != NULL && strncmp(entry->signal_name, name, strlen(name)) == 0)
184                         return -1;
185         }
186
187         handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
188                                 interface, name, cb, NULL);
189
190         if (!handler) {
191                 _E("fail to add edbus handler");
192                 return -1;
193         }
194
195         _E("add edbus service: %s", name);
196
197         entry = malloc(sizeof(struct edbus_list));
198
199         if (!entry) {
200                 _E("Malloc failed");
201                 return -1;
202         }
203
204         entry->signal_name = strndup(name, strlen(name));
205
206         if (!entry->signal_name) {
207                 _E("Malloc failed");
208                 free(entry);
209                 return -1;
210         }
211
212         entry->handler = handler;
213         edbus_handler_list = eina_list_prepend(edbus_handler_list, entry);
214         if (!edbus_handler_list) {
215                 _E("eina_list_prepend failed");
216                 free(entry->signal_name);
217                 free(entry);
218                 return -1;
219         }
220         return 0;
221 }
222
223 int broadcast_edbus_signal(const char *path, const char *interface,
224                 const char *name, int type, void *value)
225 {
226         DBusMessage *signal;
227         DBusMessageIter iter;
228         DBusMessageIter val;
229         char sig[2] = {type, '\0'};
230
231         signal = dbus_message_new_signal(path, interface, name);
232         if (!signal) {
233                 _E("fail to allocate new %s.%s signal", interface, name);
234                 return -1;
235         }
236
237         dbus_message_append_args(signal, type, value, DBUS_TYPE_INVALID);
238
239         e_dbus_message_send(edbus_conn, signal, NULL, -1, NULL);
240
241         dbus_message_unref(signal);
242         return 0;
243 }
244
245 int register_edbus_watch(DBusMessage *msg)
246 {
247         char match[256];
248         const char *sender, *watch;
249         Eina_List *l;
250
251         if (!msg) {
252                 _E("invalid argument!");
253                 return -EINVAL;
254         }
255
256         sender = dbus_message_get_sender(msg);
257         if (!sender) {
258                 _E("invalid sender!");
259                 return -EINVAL;
260         }
261
262         /* check the sender is already registered */
263         EINA_LIST_FOREACH(edbus_watch_list, l, watch) {
264                 if (strcmp(sender, watch)) continue;
265
266                 _I("%s is already watched!", watch);
267                 return 0;
268         }
269
270         watch = strndup(sender, strlen(sender));
271         if (!watch) {
272                 _E("Malloc failed");
273                 return -ENOMEM;
274         }
275
276         /* Add sender to watch list */
277         EINA_LIST_APPEND(edbus_watch_list, watch);
278
279         snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch);
280         dbus_bus_add_match(conn, match, NULL);
281
282         _I("%s is watched by dbus!", watch);
283 }
284
285 static DBusHandlerResult message_filter(DBusConnection *connection,
286                 DBusMessage *message, void *data)
287 {
288         char match[256];
289         int ret;
290         const char *iface, *member, *watch, *arg = NULL;
291         Eina_List *l;
292
293         if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
294                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
295
296         iface = dbus_message_get_interface(message);
297         member = dbus_message_get_member(message);
298
299         if (strcmp(iface, DBUS_INTERFACE_DBUS))
300                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
301
302         if (strcmp(member, NAME_OWNER_CHANGED))
303                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
304
305         ret = dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
306                     DBUS_TYPE_INVALID);
307         if (!ret) {
308                 _E("no message");
309                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
310         }
311
312         _D("Argument : %s", arg);
313
314         EINA_LIST_FOREACH(edbus_watch_list, l, watch) {
315                 if (strcmp(arg, watch)) continue;
316
317                 /* notify 'process terminated' to device notifiers */
318                 device_notify(DEVICE_NOTIFIER_PROCESS_TERMINATED, watch);
319
320                 /* remove registered sender */
321                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch);
322                 dbus_bus_remove_match(conn, match, NULL);
323                 EINA_LIST_REMOVE(edbus_watch_list, watch);
324                 free(watch);
325                 break;
326         }
327
328         return DBUS_HANDLER_RESULT_HANDLED;
329 }
330
331 static unregister_edbus_watch_all(void)
332 {
333         char match[256];
334         Eina_List *n, *next;
335         struct edbus_list *watch;
336
337         EINA_LIST_FOREACH_SAFE(edbus_watch_list, n, next, watch) {
338                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch);
339                 dbus_bus_remove_match(conn, match, NULL);
340                 EINA_LIST_REMOVE(edbus_watch_list, watch);
341                 free(watch);
342         }
343 }
344
345 static void edbus_init(void *data)
346 {
347         int retry = EDBUS_INIT_RETRY_COUNT;
348         int i, r;
349
350         while (--retry) {
351                 edbus_init_val = e_dbus_init();
352                 if (edbus_init_val)
353                         break;
354                 if (!retry) {
355                         _E("fail to init edbus");
356                         return;
357                 }
358         }
359
360         retry = EDBUS_INIT_RETRY_COUNT;
361         while (--retry) {
362                 edbus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
363                 if (edbus_conn)
364                         break;
365                 if (!retry) {
366                         _E("fail to get edbus");
367                         goto err_dbus_shutdown;
368                 }
369         }
370
371         retry = EDBUS_INIT_RETRY_COUNT;
372         while (--retry) {
373                 edbus_request_name = e_dbus_request_name(edbus_conn, BUS_NAME, 0, NULL, NULL);
374                 if (edbus_request_name)
375                         break;
376                 if (!retry) {
377                         _E("fail to request edbus name");
378                         goto err_dbus_close;
379                 }
380         }
381
382         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
383                 r = register_edbus_interface(&edbus_objects[i]);
384                 if (r < 0)
385                         _E("fail to add obj & interface for %s",
386                                     edbus_objects[i].interface);
387
388                 _I("add new obj for %s", edbus_objects[i].interface);
389         }
390
391         _D("start edbus service");
392         return;
393
394 err_dbus_close:
395         e_dbus_connection_close(edbus_conn);
396 err_dbus_shutdown:
397         e_dbus_shutdown();
398         return;
399 }
400
401 static void edbus_exit(void *data)
402 {
403         unregister_edbus_signal_handle();
404         dbus_connection_remove_filter(conn, message_filter, NULL);
405         unregister_edbus_watch_all();
406         e_dbus_connection_close(edbus_conn);
407         e_dbus_shutdown();
408 }
409
410 const struct device_ops edbus_device_ops = {
411         .init = edbus_init,
412         .exit = edbus_exit,
413 };