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