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