tizen 2.4 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 #include <fcntl.h>
43
44 #include "xdbg.h"
45 #include "xdbg_types.h"
46 #include "xdbg_dbus_server.h"
47
48 #define ARGV_NUM        128
49 #define REP_MSG_SIZE    8192
50 #define STR_LEN         128
51
52 #define RECONNECT_TIME  1000
53 #define DISPATCH_TIME   50
54
55 extern _X_EXPORT char *display;
56
57 typedef struct _XDbgDBusServerInfo
58 {
59     OsTimerPtr timer;
60     DBusConnection *conn;
61     XDbgDbusServerMethod *methods;
62     char rule[STR_LEN];
63     int fd;
64     char xdbg_dbus_server[STR_LEN];
65     char xdbg_dbus_path[STR_LEN];
66 } XDbgDBusServerInfo;
67
68 static XDbgDBusServerInfo server_info;
69
70 static CARD32 _xDbgDBusServerTimeout (OsTimerPtr timer, CARD32 time, pointer arg);
71 static Bool _xDbgDBusServerInit (XDbgDBusServerInfo *info);
72 static void _xDbgDBusServerDeinit (XDbgDBusServerInfo *info);
73
74 static uint32_t
75 _xdbgDBusServerGetClientPID(DBusConnection *conn, char *client_name)
76 {
77     DBusMessage *msg = NULL;
78     DBusMessage *reply_msg = NULL;
79     DBusMessageIter iter;
80     DBusError err;
81     uint32_t pid = 0;
82
83     RETURN_VAL_IF_FAIL (client_name != NULL, 0);
84
85     dbus_error_init (&err);
86
87     msg = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus",
88                                         "org.freedesktop.DBus", "GetConnectionUnixProcessID");
89
90     GOTO_IF_FAIL (msg != NULL, err_send);
91
92     dbus_message_iter_init_append (msg, &iter);
93
94     if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &client_name))
95     {
96         XDBG_ERROR (MDBUS, "[SERVER] failed: append\n");
97         goto err_send;
98     }
99
100     reply_msg = dbus_connection_send_with_reply_and_block (conn, msg,
101                                                            1000, &err);
102
103     if (dbus_error_is_set (&err))
104     {
105         XDBG_ERROR (MDBUS, "[SERVER] failed: send (%s)\n",  err.message);
106         goto err_send;
107     }
108     GOTO_IF_FAIL (reply_msg != NULL, err_send);
109
110     if (!dbus_message_iter_init (reply_msg, &iter))
111     {
112         XDBG_ERROR (MDBUS, "[SERVER] Message has no arguments\n");
113         goto err_send;
114     }
115
116     if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
117     {
118         XDBG_ERROR (MDBUS, "[SERVER] Argument is not unint32!\n");
119         goto err_send;
120     }
121
122     dbus_message_iter_get_basic (&iter, &pid);
123     if (!pid)
124     {
125         XDBG_ERROR (MDBUS, "[SERVER] pid is 0\n");
126         goto err_send;
127     }
128
129     XDBG_DEBUG (MDBUS, "[SERVER] Get Client name:%s pid:%u\n", client_name, pid);
130
131     return pid;
132
133 err_send:
134     if (msg)
135         dbus_message_unref(msg);
136     if (reply_msg)
137         dbus_message_unref(reply_msg);
138
139     return 0;
140 }
141
142
143 static Bool
144 _xDbgDBusServerCheckSmackLabel (DBusConnection *connection)
145 {
146     char xdbg_client_name[STR_LEN];
147     char label_path[STR_LEN];
148     char label[STR_LEN];
149     uint32_t pid = 0;
150     int fd = -1;
151     int i;
152
153     snprintf(xdbg_client_name, sizeof(xdbg_client_name), "org.x.dbg.client%d", atoi(display));
154
155     pid = _xdbgDBusServerGetClientPID (connection, xdbg_client_name);
156     if (!pid)
157     {
158         XDBG_ERROR (MDBUS, "[SERVER] failed: Get client PID\n");
159         return FALSE;
160     }
161
162     snprintf(label_path, sizeof(label_path), "/proc/%u/attr/current", pid);
163
164     fd = open(label_path, O_RDONLY);
165     if (fd < 0)
166     {
167
168         XDBG_ERROR (MDBUS, "[SERVER] Failed: Open client smack label path\n");
169         return FALSE;
170     }
171
172     i = read(fd, label, sizeof(label));
173     close(fd);
174
175     if (i < 0)
176     {
177         XDBG_ERROR (MDBUS, "[SERVER] Failed: Read client smack label\n");
178         return FALSE;
179     }
180
181     if (i < STR_LEN)
182         label[i] = '\0';
183
184     if (strcmp(label, "xorg"))
185     {
186         XDBG_ERROR (MDBUS, "[SERVER] Deny  smack label:%s\n", label);
187         return FALSE;
188     }
189
190     XDBG_DEBUG (MDBUS, "[SERVER] Get client  smack label:%s\n", label);
191
192     return TRUE;
193 }
194
195 static Bool
196 _xDbgDBusServerReplyMessage (XDbgDBusServerInfo *info, DBusMessage *msg, char *reply)
197 {
198     DBusMessage *reply_msg = NULL;
199     DBusMessageIter iter;
200
201     XDBG_RETURN_VAL_IF_FAIL (info->conn != NULL, FALSE);
202
203     reply_msg = dbus_message_new_method_return (msg);
204     XDBG_RETURN_VAL_IF_FAIL (reply_msg != NULL, FALSE);
205
206     dbus_message_iter_init_append (reply_msg, &iter);
207     if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reply))
208     {
209         XDBG_ERROR (MDBUS, "[SERVER] out of memory\n");
210         dbus_message_unref (reply_msg);
211         return FALSE;
212     }
213
214     if (!dbus_connection_send (info->conn, reply_msg, NULL))
215     {
216         XDBG_ERROR (MDBUS, "[SERVER] failed: send reply\n");
217         dbus_message_unref (reply_msg);
218         return FALSE;
219     }
220
221     XDBG_DEBUG (MDBUS, "[SERVER] send reply\n");
222
223     dbus_connection_flush (info->conn);
224     dbus_message_unref (reply_msg);
225
226     return TRUE;
227 }
228
229 static void
230 _xDbgDBusServerProcessMessage (XDbgDBusServerInfo *info, DBusMessage *msg)
231 {
232     XDbgDbusServerMethod **prev;
233     DBusError err;
234     char err_buf[REP_MSG_SIZE] = {0,};
235     char *argv[ARGV_NUM] = {0,};
236     int argc = 0;
237     int i;
238
239     snprintf (err_buf, REP_MSG_SIZE, "error message!\n");
240
241     dbus_error_init (&err);
242
243     XDBG_DEBUG (MDBUS, "[SERVER] Process a message (%s.%s)\n",
244                dbus_message_get_interface (msg), dbus_message_get_member (msg));
245
246     XDBG_RETURN_IF_FAIL (info->conn != NULL);
247
248     for (prev = &info->methods; *prev; prev = &(*prev)->next)
249     {
250         XDbgDbusServerMethod *method = *prev;
251
252         if (!strcmp (dbus_message_get_member (msg), method->name))
253         {
254             DBusMessageIter iter;
255             char reply[REP_MSG_SIZE] = {0,};
256             char *p;
257             int   len;
258
259             if (!dbus_message_iter_init (msg, &iter))
260             {
261                 XDBG_ERROR (MDBUS, "[SERVER] Message has no arguments!\n");
262                 snprintf (err_buf, REP_MSG_SIZE, "Message has no arguments!\n");
263                 goto send_fail;
264             }
265
266             do
267             {
268                 p = NULL;
269
270                 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
271                 {
272                     XDBG_ERROR (MDBUS, "[SERVER] Argument is not string!\n");
273                     snprintf (err_buf, REP_MSG_SIZE, "Argument is not string!\n");
274                     goto send_fail;
275                 }
276
277                 dbus_message_iter_get_basic (&iter, &p);
278
279                 if (!p)
280                 {
281                     XDBG_ERROR (MDBUS, "[SERVER] Can't get string!\n");
282                     snprintf (err_buf, REP_MSG_SIZE, "Can't get string!\n");
283                     goto send_fail;
284                 }
285
286                 argv[argc] = strdup (p);
287                 argc++;
288             } while (dbus_message_iter_has_next (&iter) &&
289                    dbus_message_iter_next (&iter) &&
290                    argc < ARGV_NUM);
291
292             len = REP_MSG_SIZE - 1;
293
294             if (method->func)
295                 method->func (method->data, argc, argv, reply, &len);
296
297             _xDbgDBusServerReplyMessage (info, msg, reply);
298
299             for (i = 0; i < ARGV_NUM; i++)
300                 if (argv[i])
301                     free (argv[i]);
302             dbus_error_free (&err);
303
304             return;
305         }
306     }
307
308     return;
309
310 send_fail:
311    _xDbgDBusServerReplyMessage (info, msg, err_buf);
312
313     for (i = 0; i < ARGV_NUM; i++)
314         if (argv[i])
315             free (argv[i]);
316     dbus_error_free (&err);
317 }
318
319 static void
320 _xDbgDBusServerWakeupHandler (pointer data, int error, pointer pRead)
321 {
322     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
323
324     if (!info || !info->conn || info->fd < 0)
325         return;
326
327     if (FD_ISSET(info->fd, (fd_set*)pRead))
328     {
329         do {
330             dbus_connection_read_write_dispatch (info->conn, 0);
331         } while (info->conn &&
332                  dbus_connection_get_is_connected (info->conn) &&
333                  dbus_connection_get_dispatch_status (info->conn) ==
334                  DBUS_DISPATCH_DATA_REMAINS);
335
336         /* DON'T use info->conn from here. info->conn becomes NULL by
337          * dbus_connection_read_write_dispatch(_xDbgDBusServerMsgFilter)
338          */
339     }
340 }
341
342 static DBusHandlerResult
343 _xDbgDBusServerMsgHandler (DBusConnection *connection, DBusMessage *msg, void *data)
344 {
345     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
346
347     if (!info || !info->conn || !msg)
348         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
349
350     XDBG_DEBUG (MDBUS, "[SERVER] Got a message (%s.%s)\n",
351                dbus_message_get_interface (msg), dbus_message_get_member (msg));
352
353     if (!_xDbgDBusServerCheckSmackLabel(connection))
354         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
355
356     if (!dbus_message_is_method_call (msg, XDBG_DBUS_INTERFACE, XDBG_DBUS_METHOD))
357         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
358
359     _xDbgDBusServerProcessMessage (info, msg);
360
361     return DBUS_HANDLER_RESULT_HANDLED;
362 }
363
364 static DBusHandlerResult
365 _xDbgDBusServerMsgFilter (DBusConnection *conn, DBusMessage *msg, void *data)
366 {
367     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)data;
368
369     if (!info)
370         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
371
372     if (dbus_message_is_signal (msg, DBUS_INTERFACE_LOCAL, "Disconnected"))
373     {
374         XDBG_DEBUG (MDBUS, "[SERVER] disconnected by signal\n");
375         _xDbgDBusServerDeinit (info);
376
377         if (info->timer)
378             TimerFree(info->timer);
379         info->timer = TimerSet(NULL, 0, 1, _xDbgDBusServerTimeout, info);
380
381         return DBUS_HANDLER_RESULT_HANDLED;
382     }
383
384     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
385 }
386
387 static CARD32
388 _xDbgDBusServerTimeout (OsTimerPtr timer, CARD32 time, pointer arg)
389 {
390     XDbgDBusServerInfo *info = (XDbgDBusServerInfo*)arg;
391
392     if (!info)
393         return 0;
394
395     XDBG_DEBUG (MDBUS, "[SERVER] timeout\n");
396
397     if (_xDbgDBusServerInit (info))
398     {
399         TimerFree (info->timer);
400         info->timer = NULL;
401         return 0;
402     }
403
404     return RECONNECT_TIME;
405 }
406
407 static Bool
408 _xDbgDBusServerInit (XDbgDBusServerInfo *info)
409 {
410     DBusObjectPathVTable vtable = {.message_function = _xDbgDBusServerMsgHandler, };
411     DBusError err;
412     int ret;
413
414     dbus_error_init (&err);
415
416     XDBG_RETURN_VAL_IF_FAIL (info->conn == NULL, FALSE);
417
418     snprintf(info->xdbg_dbus_server, sizeof(info->xdbg_dbus_server), "org.x.dbg.server%d", atoi(display));
419     snprintf(info->xdbg_dbus_path, sizeof(info->xdbg_dbus_path), "/org/x/dbg/path/%d", atoi(display));
420
421     XDBG_DEBUG (MDBUS, "[SERVER] display number %d\n", atoi(display));
422
423     info->conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
424     if (dbus_error_is_set (&err))
425     {
426         XDBG_ERROR (MDBUS, "[SERVER] failed: connection (%s)\n", err.message);
427         goto free_err;
428     }
429     if (!info->conn)
430     {
431         XDBG_ERROR (MDBUS, "[SERVER] failed: connection NULL\n");
432         goto free_err;
433     }
434
435     ret = dbus_bus_request_name (info->conn, info->xdbg_dbus_server,
436                                  DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
437     if (dbus_error_is_set (&err))
438     {
439         XDBG_ERROR (MDBUS, "[SERVER] failed: request name (%s)\n", err.message);
440         goto free_conn;
441     }
442     if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
443     {
444         XDBG_ERROR (MDBUS, "[SERVER] failed: Not Primary Owner (%d)\n", ret);
445         goto free_conn;
446     }
447
448         snprintf (info->rule, sizeof (info->rule), "type='method_call',interface='%s'",
449               XDBG_DBUS_INTERFACE);
450
451     /* blocks until we get a reply. */
452     dbus_bus_add_match (info->conn, info->rule, &err);
453     if (dbus_error_is_set (&err))
454     {
455         XDBG_ERROR (MDBUS, "[SERVER] failed: add match (%s)\n", err.message);
456         goto free_name;
457     }
458
459     if (!dbus_connection_register_object_path (info->conn,
460                                                info->xdbg_dbus_path, &vtable,
461                                                info))
462     {
463         XDBG_ERROR (MDBUS, "[SERVER] failed: register object path\n");
464         goto free_match;
465     }
466
467     dbus_connection_set_exit_on_disconnect (info->conn, FALSE);
468
469     if (!dbus_connection_add_filter (info->conn, _xDbgDBusServerMsgFilter, info, NULL))
470     {
471         XDBG_ERROR (MDBUS, "[SERVER] failed: add filter (%s)\n", err.message);
472         goto free_register;
473     }
474
475         if (!dbus_connection_get_unix_fd (info->conn, &info->fd) || info->fd < 0)
476     {
477         XDBG_ERROR (MDBUS, "[SERVER] failed: get fd\n");
478         goto free_filter;
479     }
480
481     AddGeneralSocket (info->fd);
482     RegisterBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
483                                     _xDbgDBusServerWakeupHandler, info);
484
485     XDBG_INFO (MDBUS, "[SERVER] connected\n");
486
487     dbus_error_free (&err);
488
489     return TRUE;
490
491 free_filter:
492     dbus_connection_remove_filter (info->conn, _xDbgDBusServerMsgFilter, info);
493 free_register:
494     dbus_connection_unregister_object_path (info->conn, info->xdbg_dbus_path);
495 free_match:
496     dbus_bus_remove_match (info->conn, info->rule, &err);
497     dbus_error_free (&err);
498 free_name:
499     dbus_bus_release_name (info->conn, info->xdbg_dbus_server, &err);
500     dbus_error_free (&err);
501 free_conn:
502     dbus_connection_close (info->conn);
503 free_err:
504     dbus_error_free (&err);
505     info->conn = NULL;
506     info->fd = -1;
507
508     return FALSE;
509 }
510
511 static void
512 _xDbgDBusServerDeinit (XDbgDBusServerInfo *info)
513 {
514     if (info->timer)
515     {
516         TimerFree (info->timer);
517         info->timer = NULL;
518     }
519
520     if (info->conn)
521     {
522         DBusError err;
523         dbus_error_init (&err);
524         dbus_connection_remove_filter (info->conn, _xDbgDBusServerMsgFilter, info);
525         dbus_connection_unregister_object_path (info->conn, info->xdbg_dbus_path);
526         dbus_bus_remove_match (info->conn, info->rule, &err);
527         dbus_error_free (&err);
528         dbus_bus_release_name (info->conn, info->xdbg_dbus_server, &err);
529         dbus_error_free (&err);
530         dbus_connection_unref (info->conn);
531         info->conn = NULL;
532     }
533
534     RemoveBlockAndWakeupHandlers ((BlockHandlerProcPtr)NoopDDA,
535                                    _xDbgDBusServerWakeupHandler, info);
536     if (info->fd >= 0)
537     {
538         RemoveGeneralSocket (info->fd);
539         info->fd = -1;
540     }
541
542     XDBG_INFO (MDBUS, "[SERVER] disconnected\n");
543 }
544
545 Bool
546 xDbgDBusServerConnect (void)
547 {
548     XDBG_DEBUG (MDBUS, "[SERVER] connecting\n");
549
550     memset (&server_info, 0, sizeof(server_info));
551
552     server_info.fd = -1;
553     server_info.timer = TimerSet (NULL, 0, 1, _xDbgDBusServerTimeout, &server_info);
554
555     return TRUE;
556 }
557
558 void
559 xDbgDBusServerDisconnect (void)
560 {
561     XDBG_DEBUG (MDBUS, "[SERVER] disconnecting\n");
562
563     _xDbgDBusServerDeinit (&server_info);
564 }
565
566 Bool
567 xDbgDBusServerAddMethod (XDbgDbusServerMethod *method)
568 {
569     XDbgDbusServerMethod **prev;
570
571     for (prev = &server_info.methods; *prev; prev = &(*prev)->next);
572
573     method->next = NULL;
574     *prev = method;
575
576     return TRUE;
577 }
578
579 void
580 xDbgDBusServerRemoveMethod (XDbgDbusServerMethod *method)
581 {
582     XDbgDbusServerMethod **prev;
583
584     for (prev = &server_info.methods; *prev; prev = &(*prev)->next)
585         if (*prev == method)
586         {
587             *prev = method->next;
588             break;
589         }
590 }