1 /*
2 * Copyright © 2010-2012 Mike Gorse
3 * Copyright © 2011-2018 Collabora Ltd.
4 *
5 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <dbus/dbus.h>
32 #include <glib.h>
33 #include <dbus-gmain/dbus-gmain.h>
34 #include "util.h"
35
36 DBusConnection *bus;
37 GMainContext *main_context;
38
39 typedef struct _SpiReentrantCallClosure
40 {
41 GMainLoop *loop;
42 DBusMessage *reply;
43 } SpiReentrantCallClosure;
44
45 static void
set_reply(DBusPendingCall * pending,void * user_data)46 set_reply (DBusPendingCall * pending, void *user_data)
47 {
48 SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data;
49
50 closure->reply = dbus_pending_call_steal_reply (pending);
51 DBUS_GMAIN_FUNCTION_NAME (set_up_connection) (bus, NULL);
52
53 g_main_loop_quit (closure->loop);
54 }
55
56 static DBusMessage *
send_and_allow_reentry(DBusConnection * bus,DBusMessage * message,dbus_bool_t switch_after_send)57 send_and_allow_reentry (DBusConnection * bus, DBusMessage * message,
58 dbus_bool_t switch_after_send)
59 {
60 DBusPendingCall *pending;
61 SpiReentrantCallClosure closure;
62
63 closure.loop = g_main_loop_new (main_context, FALSE);
64 DBUS_GMAIN_FUNCTION_NAME (set_up_connection) (bus,
65 (switch_after_send ? NULL :
66 main_context));
67
68 if (!dbus_connection_send_with_reply (bus, message, &pending, 3000))
69 {
70 DBUS_GMAIN_FUNCTION_NAME (set_up_connection) (bus, NULL);
71 return NULL;
72 }
73 dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL);
74 if (switch_after_send)
75 DBUS_GMAIN_FUNCTION_NAME (set_up_connection) (bus, main_context);
76 g_main_loop_run (closure.loop);
77
78 g_main_loop_unref (closure.loop);
79 dbus_pending_call_unref (pending);
80 return closure.reply;
81 }
82
83 static void
send_test_message(dbus_bool_t switch_after_send)84 send_test_message (dbus_bool_t switch_after_send)
85 {
86 DBusMessage *message, *reply;
87 const char *str;
88 DBusError error;
89
90 dbus_error_init (&error);
91 message = dbus_message_new_method_call ("org.freedesktop.DBus",
92 "/org/freedesktop/DBus",
93 DBUS_INTERFACE_DBUS, "GetId");
94 reply = send_and_allow_reentry (bus, message, switch_after_send);
95 if (!reply)
96 {
97 fprintf(stderr, "Got no reply from send_and_allow_reentry\n");
98 exit(1);
99 }
100 if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
101 {
102 char *err = NULL;
103 dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &err, DBUS_TYPE_INVALID);
104 fprintf (stderr, "Got error: %s\n", err);
105 exit(1);
106 }
107 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
108 {
109 fprintf(stderr, "Sorry; can't communicate: %s\n", error.message);
110 exit(1);
111 }
112 dbus_message_unref (reply);
113 dbus_message_unref (message);
114 }
115
116 int
main(int argc,const char * argv[])117 main(int argc, const char *argv[])
118 {
119 DBusError error;
120
121 main_context = g_main_context_new ();
122 dbus_error_init (&error);
123 bus = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
124 if (!bus)
125 {
126 fprintf(stderr, "Couldn't connect to bus: %s\n", error.name);
127 return 1;
128 }
129 DBUS_GMAIN_FUNCTION_NAME (set_up_connection) (bus, NULL);
130 send_test_message (FALSE);
131 send_test_message (FALSE);
132 send_test_message (TRUE);
133
134 test_run_until_disconnected (bus, NULL);
135 dbus_connection_unref (bus);
136
137 dbus_shutdown ();
138 g_main_context_unref (main_context);
139
140 return 0;
141 }
142