add plist
[adaptation/xorg/driver/xserver-xorg-module-xdbg.git] / dbus / xdbg_dbus_server.c
1 /**************************************************************************
2
3 xdbg
4
5 Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
6
7 Contact: Boram Park <boram1288.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 "xdbg_dbus_server.h"
45
46 #define ARGV_NUM        128
47 #define REP_MSG_SIZE    8192
48 #define STR_LEN         128
49
50 #define RECONNECT_TIME  1000
51 #define DISPATCH_TIME   50
52
53 typedef struct _XDbgDBusServerInfo
54 {
55     OsTimerPtr timer;
56     DBusConnection *conn;
57     XDbgDbusServerMethod *methods;
58     char rule[STR_LEN];
59     int fd;
60 } XDbgDBusServerInfo;
61
62 static XDbgDBusServerInfo server_info;
63
64 static CARD32 _xDbgDBusServerTimeout (OsTimerPtr timer, CARD32 time, pointer arg);
65 static Bool _xDbgDBusServerInit (XDbgDBusServerInfo *info);
66 static void _xDbgDBusServerDeinit (XDbgDBusServerInfo *info);
67
68 static Bool
69 _xDbgDBusServerReplyMessage (XDbgDBusServerInfo *info, DBusMessage *msg, char *reply)
70 {
71     DBusMessage *reply_msg = NULL;
72     DBusMessageIter iter;
73
74     XDBG_RETURN_VAL_IF_FAIL (info->conn != NULL, FALSE);
75
76     reply_msg = dbus_message_new_method_return (msg);
77     XDBG_RETURN_VAL_IF_FAIL (reply_msg != NULL, FALSE);
78
79     dbus_message_iter_init_append (reply_msg, &iter);
80     if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reply))
81     {
82         XDBG_ERROR (MDBUS, "[SERVER] out of memory\n");
83         dbus_message_unref (reply_msg);
84         return FALSE;
85     }
86
87     if (!dbus_connection_send (info->conn, reply_msg, NULL))
88     {
89         XDBG_ERROR (MDBUS, "[SERVER] failed: send reply\n");
90         dbus_message_unref (reply_msg);
91         return FALSE;
92     }
93
94     XDBG_INFO (MDBUS, "[SERVER] send reply\n");
95
96     dbus_connection_flush (info->conn);
97     dbus_message_unref (reply_msg);
98
99     return TRUE;
100 }
101
102 static void
103 _xDbgDBusServerProcessMessage (XDbgDBusServerInfo *info, DBusMessage *msg)
104 {
105     XDbgDbusServerMethod **prev;
106     DBusError err;
107     char err_buf[REP_MSG_SIZE] = {0,};
108     char *argv[ARGV_NUM] = {0,};
109     int argc = 0;
110     int i;
111
112     snprintf (err_buf, REP_MSG_SIZE, "error message!\n");
113
114     dbus_error_init (&err);
115
116     XDBG_INFO (MDBUS, "[SERVER] Process a message (%s.%s)\n",
117                dbus_message_get_interface (msg), dbus_message_get_member (msg));
118
119     XDBG_RETURN_IF_FAIL (info->conn != NULL);
120
121     for (prev = &info->methods; *prev; prev = &(*prev)->next)
122     {
123         XDbgDbusServerMethod *method = *prev;
124
125         if (!strcmp (dbus_message_get_member (msg), method->name))
126         {
127             DBusMessageIter iter;
128             char reply[REP_MSG_SIZE] = {0,};
129             char *p;
130             int   len;
131
132             if (!dbus_message_iter_init (msg, &iter))
133             {
134                 XDBG_ERROR (MDBUS, "[SERVER] Message has no arguments!\n");
135                 snprintf (err_buf, REP_MSG_SIZE, "Message has no arguments!\n");
136                 goto send_fail;
137             }
138
139             do
140             {
141                 p = NULL;
142
143                 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
144                 {
145                     XDBG_ERROR (MDBUS, "[SERVER] Argument is not string!\n");
146                     snprintf (err_buf, REP_MSG_SIZE, "Argument is not string!\n");
147                     goto send_fail;
148                 }
149
150                 dbus_message_iter_get_basic (&iter, &p);
151
152                 if (!p)
153                 {
154                     XDBG_ERROR (MDBUS, "[SERVER] Can't get string!\n");
155                     snprintf (err_buf, REP_MSG_SIZE, "Can't get string!\n");
156                     goto send_fail;
157                 }
158
159                 argv[argc] = strdup (p);
160                 argc++;
161             } while (dbus_message_iter_has_next (&iter) &&
162                    dbus_message_iter_next (&iter) &&
163                    argc < ARGV_NUM);
164
165             len = REP_MSG_SIZE - 1;
166
167             if (method->func)
168                 method->func (method->data, argc, argv, reply, &len);
169
170             _xDbgDBusServerReplyMessage (info, msg, reply);
171
172             for (i = 0; i < ARGV_NUM; i++)
173                 if (argv[i])
174                     free (argv[i]);
175             dbus_error_free (&err);
176
177             return;
178         }
179     }
180
181     return;
182
183 send_fail:
184    _xDbgDBusServerReplyMessage (info, msg, err_buf);
185
186     for (i = 0; i < ARGV_NUM; i++)
187         if (argv[i])
188             free (argv[i]);
189     dbus_error_free (&err);
190 }
191
192 static void
193 _xDbgDBusServerWakeupHandler (pointer data, int error, pointer pRead)
194 {
195     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
196
197     if (!info || !info->conn || info->fd < 0)
198         return;
199
200     if (FD_ISSET(info->fd, (fd_set*)pRead))
201     {
202         dbus_connection_ref (info->conn);
203
204         do {
205             dbus_connection_read_write_dispatch (info->conn, 0);
206         } while (info->conn &&
207                  dbus_connection_get_is_connected (info->conn) &&
208                  dbus_connection_get_dispatch_status (info->conn) ==
209                  DBUS_DISPATCH_DATA_REMAINS);
210
211         dbus_connection_unref (info->conn);
212     }
213 }
214
215 static DBusHandlerResult
216 _xDbgDBusServerMsgHandler (DBusConnection *connection, DBusMessage *msg, void *data)
217 {
218     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
219
220     if (!info || !info->conn || !msg)
221         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
222
223     XDBG_INFO (MDBUS, "[SERVER] Got a message (%s.%s)\n",
224                dbus_message_get_interface (msg), dbus_message_get_member (msg));
225
226     if (!dbus_message_is_method_call (msg, XDBG_DBUS_INTERFACE, XDBG_DBUS_METHOD))
227         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
228
229     _xDbgDBusServerProcessMessage (info, msg);
230
231     return DBUS_HANDLER_RESULT_HANDLED;
232 }
233
234 static DBusHandlerResult
235 _xDbgDBusServerMsgFilter (DBusConnection *conn, DBusMessage *msg, void *data)
236 {
237     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
238
239     if (!info)
240         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
241
242     if (dbus_message_is_signal (msg, DBUS_INTERFACE_LOCAL, "Disconnected"))
243     {
244         XDBG_INFO (MDBUS, "[SERVER] disconnected by signal\n");
245         _xDbgDBusServerDeinit (info);
246
247         if (info->timer)
248             TimerFree(info->timer);
249         info->timer = TimerSet(NULL, 0, 1, _xDbgDBusServerTimeout, info);
250
251         return DBUS_HANDLER_RESULT_HANDLED;
252     }
253
254     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
255 }
256
257 static CARD32
258 _xDbgDBusServerTimeout (OsTimerPtr timer, CARD32 time, pointer arg)
259 {
260     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)arg;
261
262     if (!info)
263         return 0;
264
265     XDBG_DEBUG (MDBUS, "[SERVER] timeout\n");
266
267     if (_xDbgDBusServerInit (info))
268     {
269         TimerFree (info->timer);
270         info->timer = NULL;
271         return 0;
272     }
273
274     return RECONNECT_TIME;
275 }
276
277 static Bool
278 _xDbgDBusServerInit (XDbgDBusServerInfo *info)
279 {
280     DBusObjectPathVTable vtable = {.message_function = _xDbgDBusServerMsgHandler, };
281     DBusError err;
282     int ret;
283
284     dbus_error_init (&err);
285
286     XDBG_RETURN_VAL_IF_FAIL (info->conn == NULL, FALSE);
287
288     info->conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
289     if (dbus_error_is_set (&err))
290     {
291         XDBG_ERROR (MDBUS, "[SERVER] failed: connection (%s)\n", err.message);
292         goto free_err;
293     }
294     if (!info->conn)
295     {
296         XDBG_ERROR (MDBUS, "[SERVER] failed: connection NULL\n");
297         goto free_err;
298     }
299
300     ret = dbus_bus_request_name (info->conn, XDBG_DBUS_SERVER,
301                                  DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
302     if (dbus_error_is_set (&err))
303     {
304         XDBG_ERROR (MDBUS, "[SERVER] failed: request name (%s)\n", err.message);
305         goto free_conn;
306     }
307     if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
308     {
309         XDBG_ERROR (MDBUS, "[SERVER] failed: Not Primary Owner (%d)\n", ret);
310         goto free_conn;
311     }
312
313         snprintf (info->rule, sizeof (info->rule), "type='method_call',interface='%s'",
314               XDBG_DBUS_INTERFACE);
315
316     /* blocks until we get a reply. */
317     dbus_bus_add_match (info->conn, info->rule, &err);
318     if (dbus_error_is_set (&err))
319     {
320         XDBG_ERROR (MDBUS, "[SERVER] failed: add match (%s)\n", err.message);
321         goto free_name;
322     }
323
324     if (!dbus_connection_register_object_path (info->conn,
325                                                XDBG_DBUS_PATH, &vtable,
326                                                info))
327     {
328         XDBG_ERROR (MDBUS, "[SERVER] failed: register object path\n");
329         goto free_match;
330     }
331
332     dbus_connection_set_exit_on_disconnect (info->conn, FALSE);
333
334     if (!dbus_connection_add_filter (info->conn, _xDbgDBusServerMsgFilter, info, NULL))
335     {
336         XDBG_ERROR (MDBUS, "[SERVER] failed: add filter (%s)\n", err.message);
337         goto free_register;
338     }
339
340         if (!dbus_connection_get_unix_fd (info->conn, &info->fd) || info->fd < 0)
341     {
342         XDBG_ERROR (MDBUS, "[SERVER] failed: get fd\n");
343         goto free_filter;
344     }
345
346     AddGeneralSocket (info->fd);
347     RegisterBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
348                                     _xDbgDBusServerWakeupHandler, info);
349
350     XDBG_INFO (MDBUS, "[SERVER] connected\n");
351
352     dbus_error_free (&err);
353
354     return TRUE;
355
356 free_filter:
357     dbus_connection_remove_filter (info->conn, _xDbgDBusServerMsgFilter, info);
358 free_register:
359     dbus_connection_unregister_object_path (info->conn, XDBG_DBUS_PATH);
360 free_match:
361     dbus_bus_remove_match (info->conn, info->rule, &err);
362     dbus_error_free (&err);
363 free_name:
364     dbus_bus_release_name (info->conn, XDBG_DBUS_SERVER, &err);
365     dbus_error_free (&err);
366 free_conn:
367     dbus_connection_close (info->conn);
368 free_err:
369     dbus_error_free (&err);
370     info->conn = NULL;
371     info->fd = -1;
372
373     return FALSE;
374 }
375
376 static void
377 _xDbgDBusServerDeinit (XDbgDBusServerInfo *info)
378 {
379     if (info->timer)
380     {
381         TimerFree (info->timer);
382         info->timer = NULL;
383     }
384
385     if (info->conn)
386     {
387         DBusError err;
388         dbus_error_init (&err);
389         dbus_connection_remove_filter (info->conn, _xDbgDBusServerMsgFilter, info);
390         dbus_connection_unregister_object_path (info->conn, XDBG_DBUS_PATH);
391         dbus_bus_remove_match (info->conn, info->rule, &err);
392         dbus_error_free (&err);
393         dbus_bus_release_name (info->conn, XDBG_DBUS_SERVER, &err);
394         dbus_error_free (&err);
395         dbus_connection_unref (info->conn);
396         info->conn = NULL;
397     }
398
399     RemoveBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
400                                    _xDbgDBusServerWakeupHandler, info);
401     if (info->fd >= 0)
402     {
403         RemoveGeneralSocket (info->fd);
404         info->fd = -1;
405     }
406
407     XDBG_INFO (MDBUS, "[SERVER] disconnected\n");
408 }
409
410 Bool
411 xDbgDBusServerConnect (void)
412 {
413     XDBG_DEBUG (MDBUS, "[SERVER] connecting\n");
414
415     memset (&server_info, 0, sizeof(server_info));
416
417     server_info.fd = -1;
418     server_info.timer = TimerSet (NULL, 0, 1, _xDbgDBusServerTimeout, &server_info);
419
420     return TRUE;
421 }
422
423 void
424 xDbgDBusServerDisconnect (void)
425 {
426     XDBG_DEBUG (MDBUS, "[SERVER] disconnecting\n");
427
428     _xDbgDBusServerDeinit (&server_info);
429 }
430
431 Bool
432 xDbgDBusServerAddMethod (XDbgDbusServerMethod *method)
433 {
434     XDbgDbusServerMethod **prev;
435
436     for (prev = &server_info.methods; *prev; prev = &(*prev)->next);
437
438     method->next = NULL;
439     *prev = method;
440
441     return TRUE;
442 }
443
444 void
445 xDbgDBusServerRemoveMethod (XDbgDbusServerMethod *method)
446 {
447     XDbgDbusServerMethod **prev;
448
449     for (prev = &server_info.methods; *prev; prev = &(*prev)->next)
450         if (*prev == method)
451         {
452             *prev = method->next;
453             break;
454         }
455 }