tizen 2.4 release
[adaptation/xorg/driver/xserver-xorg-module-lazyload.git] / src / module_lazyload_dbus.c
1 /**************************************************************************
2
3 xserver-xorg-module-lazyload
4
5 Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
6
7 Contact: Sung-Jin Park <sj76.park@samsung.com>
8          Sangjin LEE <lsj119@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <dbus/dbus.h>
40 #include <os.h>
41 #include <dix.h>
42
43 #include <xdbg.h>
44 #include "module_lazyload_main.h"
45 #include "module_lazyload_dbus.h"
46
47 #define ARGV_NUM        128
48 #define REP_MSG_SIZE    8192
49 #define STR_LEN         128
50
51 #define RECONNECT_TIME  500
52 #define DISPATCH_TIME   50
53
54 typedef struct _ModuleLazyloadDbusInfo
55 {
56     OsTimerPtr timer;
57     DBusConnection *conn;
58     ModuleLazyloadDbusMethod *methods;
59     char rule[STR_LEN];
60     int fd;
61 } ModuleLazyloadDbusInfo;
62
63 static ModuleLazyloadDbusInfo server_info;
64
65 static CARD32 _moduleLazyloadDbusTimeout (OsTimerPtr timer, CARD32 time, pointer arg);
66 static Bool _moduleLazyloadDbusInit (ModuleLazyloadDbusInfo *info);
67 static void _moduleLazyloadDbusDeinit (ModuleLazyloadDbusInfo *info);
68
69 static Bool
70 _moduleLazyloadDbusReplyMessage (ModuleLazyloadDbusInfo *info, DBusMessage *msg, char *reply)
71 {
72     DBusMessage *reply_msg = NULL;
73     DBusMessageIter iter;
74
75     XDBG_RETURN_VAL_IF_FAIL (info->conn != NULL, FALSE);
76
77     reply_msg = dbus_message_new_method_return (msg);
78     XDBG_RETURN_VAL_IF_FAIL (reply_msg != NULL, FALSE);
79
80     dbus_message_iter_init_append (reply_msg, &iter);
81     if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reply))
82     {
83         XDBG_ERROR (MLAZY, "[SERVER] out of memory\n");
84         dbus_message_unref (reply_msg);
85         return FALSE;
86     }
87
88     if (!dbus_connection_send (info->conn, reply_msg, NULL))
89     {
90         XDBG_ERROR (MLAZY, "[SERVER] failed: send reply\n");
91         dbus_message_unref (reply_msg);
92         return FALSE;
93     }
94
95     XDBG_DEBUG (MLAZY, "[SERVER] send reply\n");
96
97     dbus_connection_flush (info->conn);
98     dbus_message_unref (reply_msg);
99
100     return TRUE;
101 }
102
103 static void
104 _moduleLazyloadDbusProcessMessage (ModuleLazyloadDbusInfo *info, DBusMessage *msg)
105 {
106     ModuleLazyloadDbusMethod **prev;
107     DBusError err;
108     char err_buf[REP_MSG_SIZE] = {0,};
109     char *argv[ARGV_NUM] = {0,};
110     int argc = 0;
111     int i;
112
113     snprintf (err_buf, REP_MSG_SIZE, "error message!\n");
114
115     dbus_error_init (&err);
116
117     XDBG_DEBUG (MLAZY, "[SERVER] Process a message (%s.%s)\n",
118                dbus_message_get_interface (msg), dbus_message_get_member (msg));
119
120     XDBG_RETURN_IF_FAIL (info->conn != NULL);
121
122     for (prev = &info->methods; *prev; prev = &(*prev)->next)
123     {
124         ModuleLazyloadDbusMethod *method = *prev;
125
126         if (!strcmp (dbus_message_get_member (msg), method->name))
127         {
128             DBusMessageIter iter;
129             char reply[REP_MSG_SIZE] = {0,};
130             char *p;
131             int   len;
132
133             if (!dbus_message_iter_init (msg, &iter))
134             {
135                 XDBG_ERROR (MLAZY, "[SERVER] Message has no arguments!\n");
136                 snprintf (err_buf, REP_MSG_SIZE, "Message has no arguments!\n");
137                 goto send_fail;
138             }
139
140             do
141             {
142                 p = NULL;
143
144                 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
145                 {
146                     XDBG_ERROR (MLAZY, "[SERVER] Argument is not string!\n");
147                     snprintf (err_buf, REP_MSG_SIZE, "Argument is not string!\n");
148                     goto send_fail;
149                 }
150
151                 dbus_message_iter_get_basic (&iter, &p);
152
153                 if (!p)
154                 {
155                     XDBG_ERROR (MLAZY, "[SERVER] Can't get string!\n");
156                     snprintf (err_buf, REP_MSG_SIZE, "Can't get string!\n");
157                     goto send_fail;
158                 }
159
160                 argv[argc] = strdup (p);
161                 argc++;
162             } while (dbus_message_iter_has_next (&iter) &&
163                    dbus_message_iter_next (&iter) &&
164                    argc < ARGV_NUM);
165
166             len = REP_MSG_SIZE - 1;
167
168             if (method->func)
169                 method->func (method->data, argc, argv, reply, &len);
170
171             _moduleLazyloadDbusReplyMessage (info, msg, reply);
172
173             for (i = 0; i < ARGV_NUM; i++)
174                 if (argv[i])
175                     free (argv[i]);
176             dbus_error_free (&err);
177
178             return;
179         }
180     }
181
182     return;
183
184 send_fail:
185    _moduleLazyloadDbusReplyMessage (info, msg, err_buf);
186
187     for (i = 0; i < ARGV_NUM; i++)
188         if (argv[i])
189             free (argv[i]);
190     dbus_error_free (&err);
191 }
192
193 static void
194 _moduleLazyloadDbusWakeupHandler (pointer data, int error, pointer pRead)
195 {
196     ModuleLazyloadDbusInfo *info = (ModuleLazyloadDbusInfo*)data;
197
198     if (!info || !info->conn || info->fd < 0)
199         return;
200
201     if (FD_ISSET(info->fd, (fd_set*)pRead))
202     {
203         do {
204             dbus_connection_read_write_dispatch (info->conn, 0);
205         } while (info->conn &&
206                  dbus_connection_get_is_connected (info->conn) &&
207                  dbus_connection_get_dispatch_status (info->conn) ==
208                  DBUS_DISPATCH_DATA_REMAINS);
209
210         /* DON'T use info->conn from here. info->conn becomes NULL by
211          * dbus_connection_read_write_dispatch(_moduleLazyloadDbusMsgFilter)
212          */
213     }
214 }
215
216 static DBusHandlerResult
217 _moduleLazyloadDbusMsgHandler (DBusConnection *connection, DBusMessage *msg, void *data)
218 {
219     ModuleLazyloadDbusInfo *info = (ModuleLazyloadDbusInfo*)data;
220
221     if (!info || !info->conn || !msg)
222         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
223
224     XDBG_DEBUG (MLAZY, "[SERVER] Got a message (%s.%s)\n",
225                dbus_message_get_interface (msg), dbus_message_get_member (msg));
226
227     if (!dbus_message_is_method_call (msg, LAZYLOAD_DBUS_INTERFACE, LAZYLOAD_DBUS_METHOD))
228         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
229
230     _moduleLazyloadDbusProcessMessage (info, msg);
231
232     return DBUS_HANDLER_RESULT_HANDLED;
233 }
234
235 static DBusHandlerResult
236 _moduleLazyloadDbusMsgFilter (DBusConnection *conn, DBusMessage *msg, void *data)
237 {
238     ModuleLazyloadDbusInfo *info = (ModuleLazyloadDbusInfo*)data;
239
240     if (!info)
241         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
242
243     if (dbus_message_is_signal (msg, DBUS_INTERFACE_LOCAL, "Disconnected"))
244     {
245         XDBG_DEBUG (MLAZY, "[SERVER] disconnected by signal\n");
246         _moduleLazyloadDbusDeinit (info);
247
248         if (info->timer)
249             TimerFree(info->timer);
250         info->timer = TimerSet(NULL, 0, 1, _moduleLazyloadDbusTimeout, info);
251
252         return DBUS_HANDLER_RESULT_HANDLED;
253     }
254
255     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
256 }
257
258 static CARD32
259 _moduleLazyloadDbusTimeout (OsTimerPtr timer, CARD32 time, pointer arg)
260 {
261     ModuleLazyloadDbusInfo *info = (ModuleLazyloadDbusInfo*)arg;
262
263     if (!info)
264         return 0;
265
266     XDBG_DEBUG (MLAZY, "[SERVER] timeout\n");
267
268     if (_moduleLazyloadDbusInit (info))
269     {
270         TimerFree (info->timer);
271         info->timer = NULL;
272         return 0;
273     }
274
275     return RECONNECT_TIME;
276 }
277
278 static Bool
279 _moduleLazyloadDbusInit (ModuleLazyloadDbusInfo *info)
280 {
281     DBusObjectPathVTable vtable = {.message_function = _moduleLazyloadDbusMsgHandler, };
282     DBusError err;
283     int ret;
284
285     dbus_error_init (&err);
286
287     XDBG_RETURN_VAL_IF_FAIL (info->conn == NULL, FALSE);
288
289     info->conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
290     if (dbus_error_is_set (&err))
291     {
292         XDBG_ERROR (MLAZY, "[SERVER] failed: connection (%s)\n", err.message);
293         goto free_err;
294     }
295     if (!info->conn)
296     {
297         XDBG_ERROR (MLAZY, "[SERVER] failed: connection NULL\n");
298         goto free_err;
299     }
300
301     ret = dbus_bus_request_name (info->conn, LAZYLOAD_DBUS_SERVER,
302                                  DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
303     if (dbus_error_is_set (&err))
304     {
305         XDBG_ERROR (MLAZY, "[SERVER] failed: request name (%s)\n", err.message);
306         goto free_conn;
307     }
308     if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
309     {
310         XDBG_ERROR (MLAZY, "[SERVER] failed: Not Primary Owner (%d)\n", ret);
311         goto free_conn;
312     }
313
314         snprintf (info->rule, sizeof (info->rule), "type='method_call',interface='%s'",
315               LAZYLOAD_DBUS_INTERFACE);
316
317     /* blocks until we get a reply. */
318     dbus_bus_add_match (info->conn, info->rule, &err);
319     if (dbus_error_is_set (&err))
320     {
321         XDBG_ERROR (MLAZY, "[SERVER] failed: add match (%s)\n", err.message);
322         goto free_name;
323     }
324
325     if (!dbus_connection_register_object_path (info->conn,
326                                                LAZYLOAD_DBUS_PATH, &vtable,
327                                                info))
328     {
329         XDBG_ERROR (MLAZY, "[SERVER] failed: register object path\n");
330         goto free_match;
331     }
332
333     dbus_connection_set_exit_on_disconnect (info->conn, FALSE);
334
335     if (!dbus_connection_add_filter (info->conn, _moduleLazyloadDbusMsgFilter, info, NULL))
336     {
337         XDBG_ERROR (MLAZY, "[SERVER] failed: add filter (%s)\n", err.message);
338         goto free_register;
339     }
340
341         if (!dbus_connection_get_unix_fd (info->conn, &info->fd) || info->fd < 0)
342     {
343         XDBG_ERROR (MLAZY, "[SERVER] failed: get fd\n");
344         goto free_filter;
345     }
346
347     AddGeneralSocket (info->fd);
348     RegisterBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
349                                     _moduleLazyloadDbusWakeupHandler, info);
350
351     XDBG_INFO (MLAZY, "[SERVER] connected\n");
352
353     dbus_error_free (&err);
354
355     return TRUE;
356
357 free_filter:
358     dbus_connection_remove_filter (info->conn, _moduleLazyloadDbusMsgFilter, info);
359 free_register:
360     dbus_connection_unregister_object_path (info->conn, LAZYLOAD_DBUS_PATH);
361 free_match:
362     dbus_bus_remove_match (info->conn, info->rule, &err);
363     dbus_error_free (&err);
364 free_name:
365     dbus_bus_release_name (info->conn, LAZYLOAD_DBUS_SERVER, &err);
366     dbus_error_free (&err);
367 free_conn:
368     dbus_connection_close (info->conn);
369 free_err:
370     dbus_error_free (&err);
371     info->conn = NULL;
372     info->fd = -1;
373
374     return FALSE;
375 }
376
377 static void
378 _moduleLazyloadDbusDeinit (ModuleLazyloadDbusInfo *info)
379 {
380     if (info->timer)
381     {
382         TimerFree (info->timer);
383         info->timer = NULL;
384     }
385
386     if (info->conn)
387     {
388         DBusError err;
389         dbus_error_init (&err);
390         dbus_connection_remove_filter (info->conn, _moduleLazyloadDbusMsgFilter, info);
391         dbus_connection_unregister_object_path (info->conn, LAZYLOAD_DBUS_PATH);
392         dbus_bus_remove_match (info->conn, info->rule, &err);
393         dbus_error_free (&err);
394         dbus_bus_release_name (info->conn, LAZYLOAD_DBUS_SERVER, &err);
395         dbus_error_free (&err);
396         dbus_connection_unref (info->conn);
397         info->conn = NULL;
398     }
399
400     RemoveBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
401                                    _moduleLazyloadDbusWakeupHandler, info);
402     if (info->fd >= 0)
403     {
404         RemoveGeneralSocket (info->fd);
405         info->fd = -1;
406     }
407
408     XDBG_INFO (MLAZY, "[SERVER] disconnected\n");
409 }
410
411 Bool
412 moduleLazyloadDbusConnect (void)
413 {
414     XDBG_DEBUG (MLAZY, "[SERVER] connecting\n");
415
416     memset (&server_info, 0, sizeof(server_info));
417
418     server_info.fd = -1;
419     server_info.timer = TimerSet (NULL, 0, 1, _moduleLazyloadDbusTimeout, &server_info);
420
421     return TRUE;
422 }
423
424 void
425 moduleLazyloadDbusDisconnect (void)
426 {
427     XDBG_DEBUG (MLAZY, "[SERVER] disconnecting\n");
428
429     _moduleLazyloadDbusDeinit (&server_info);
430 }
431
432 Bool
433 moduleLazyloadDbusAddMethod (ModuleLazyloadDbusMethod *method)
434 {
435     ModuleLazyloadDbusMethod **prev;
436
437     for (prev = &server_info.methods; *prev; prev = &(*prev)->next);
438
439     method->next = NULL;
440     *prev = method;
441
442     return TRUE;
443 }
444
445 void
446 moduleLazyloadDbusRemoveMethod (ModuleLazyloadDbusMethod *method)
447 {
448     ModuleLazyloadDbusMethod **prev;
449
450     for (prev = &server_info.methods; *prev; prev = &(*prev)->next)
451         if (*prev == method)
452         {
453             *prev = method->next;
454             break;
455         }
456 }