1 /* Regression test for passing unmodified messages between connections 2 * 3 * Author: Simon McVittie <simon.mcvittie (at) collabora.co.uk> 4 * Copyright 2010-2011 Nokia Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person 7 * obtaining a copy of this software and associated documentation files 8 * (the "Software"), to deal in the Software without restriction, 9 * including without limitation the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 * SOFTWARE. 25 */ 26 27 #include <config.h> 28 29 #include <glib.h> 30 31 #include <dbus/dbus.h> 32 #include <dbus/dbus-glib-lowlevel.h> 33 34 /* This is basically a miniature dbus-daemon. We relay messages from the client 35 * on the left to the client on the right. 36 * 37 * left socket left dispatch right socket right 38 * client ===========> server --------------> server ===========> client 39 * conn conn conn conn 40 * 41 * In the real dbus-daemon, the client connections would be out-of-process, 42 * but here we're cheating and doing everything in-process. 43 */ 44 45 typedef struct { 46 DBusError e; 47 48 DBusServer *server; 49 50 DBusConnection *left_client_conn; 51 DBusConnection *left_server_conn; 52 53 DBusConnection *right_server_conn; 54 DBusConnection *right_client_conn; 55 /* queue of DBusMessage received by right_client_conn */ 56 GQueue messages; 57 } Fixture; 58 59 static void 60 assert_no_error (const DBusError *e) 61 { 62 if (G_UNLIKELY (dbus_error_is_set (e))) 63 g_error ("expected success but got error: %s: %s", e->name, e->message); 64 } 65 66 static DBusHandlerResult 67 server_message_cb (DBusConnection *server_conn, 68 DBusMessage *message, 69 void *data) 70 { 71 Fixture *f = data; 72 73 g_assert (server_conn == f->left_server_conn); 74 g_assert (f->right_server_conn != NULL); 75 76 dbus_connection_send (f->right_server_conn, message, NULL); 77 78 return DBUS_HANDLER_RESULT_HANDLED; 79 } 80 81 static DBusHandlerResult 82 right_client_message_cb (DBusConnection *client_conn, 83 DBusMessage *message, 84 void *data) 85 { 86 Fixture *f = data; 87 88 g_assert (client_conn == f->right_client_conn); 89 g_queue_push_tail (&f->messages, dbus_message_ref (message)); 90 91 return DBUS_HANDLER_RESULT_HANDLED; 92 } 93 94 static void 95 new_conn_cb (DBusServer *server, 96 DBusConnection *server_conn, 97 void *data) 98 { 99 Fixture *f = data; 100 dbus_bool_t have_mem; 101 102 if (f->left_server_conn == NULL) 103 { 104 f->left_server_conn = dbus_connection_ref (server_conn); 105 106 have_mem = dbus_connection_add_filter (server_conn, 107 server_message_cb, f, NULL); 108 g_assert (have_mem); 109 } 110 else 111 { 112 g_assert (f->right_server_conn == NULL); 113 f->right_server_conn = dbus_connection_ref (server_conn); 114 } 115 116 dbus_connection_setup_with_g_main (server_conn, NULL); 117 } 118 119 static void 120 setup (Fixture *f, 121 gconstpointer data G_GNUC_UNUSED) 122 { 123 dbus_error_init (&f->e); 124 g_queue_init (&f->messages); 125 126 f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e); 127 assert_no_error (&f->e); 128 g_assert (f->server != NULL); 129 130 dbus_server_set_new_connection_function (f->server, 131 new_conn_cb, f, NULL); 132 dbus_server_setup_with_g_main (f->server, NULL); 133 } 134 135 static void 136 test_connect (Fixture *f, 137 gconstpointer data G_GNUC_UNUSED) 138 { 139 dbus_bool_t have_mem; 140 char *address; 141 142 g_assert (f->left_server_conn == NULL); 143 g_assert (f->right_server_conn == NULL); 144 145 address = dbus_server_get_address (f->server); 146 g_assert (address != NULL); 147 148 f->left_client_conn = dbus_connection_open_private (address, &f->e); 149 assert_no_error (&f->e); 150 g_assert (f->left_client_conn != NULL); 151 dbus_connection_setup_with_g_main (f->left_client_conn, NULL); 152 153 while (f->left_server_conn == NULL) 154 { 155 g_print ("."); 156 g_main_context_iteration (NULL, TRUE); 157 } 158 159 f->right_client_conn = dbus_connection_open_private (address, &f->e); 160 assert_no_error (&f->e); 161 g_assert (f->right_client_conn != NULL); 162 dbus_connection_setup_with_g_main (f->right_client_conn, NULL); 163 164 dbus_free (address); 165 166 while (f->right_server_conn == NULL) 167 { 168 g_print ("."); 169 g_main_context_iteration (NULL, TRUE); 170 } 171 172 have_mem = dbus_connection_add_filter (f->right_client_conn, 173 right_client_message_cb, f, NULL); 174 g_assert (have_mem); 175 } 176 177 static dbus_uint32_t 178 send_one (Fixture *f, 179 const char *member) 180 { 181 dbus_bool_t have_mem; 182 dbus_uint32_t serial; 183 DBusMessage *outgoing; 184 185 outgoing = dbus_message_new_signal ("/com/example/Hello", 186 "com.example.Hello", member); 187 g_assert (outgoing != NULL); 188 189 have_mem = dbus_connection_send (f->left_client_conn, outgoing, &serial); 190 g_assert (have_mem); 191 g_assert (serial != 0); 192 193 dbus_message_unref (outgoing); 194 return serial; 195 } 196 197 static void 198 test_relay (Fixture *f, 199 gconstpointer data) 200 { 201 DBusMessage *incoming; 202 203 test_connect (f, data); 204 205 send_one (f, "First"); 206 send_one (f, "Second"); 207 208 while (g_queue_get_length (&f->messages) < 2) 209 { 210 g_print ("."); 211 g_main_context_iteration (NULL, TRUE); 212 } 213 214 g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 2); 215 216 incoming = g_queue_pop_head (&f->messages); 217 g_assert_cmpstr (dbus_message_get_member (incoming), ==, "First"); 218 dbus_message_unref (incoming); 219 220 incoming = g_queue_pop_head (&f->messages); 221 g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Second"); 222 dbus_message_unref (incoming); 223 } 224 225 /* An arbitrary number of messages */ 226 #define MANY 8192 227 228 static void 229 test_limit (Fixture *f, 230 gconstpointer data) 231 { 232 DBusMessage *incoming; 233 guint i; 234 235 test_connect (f, data); 236 237 /* This was an attempt to reproduce fd.o #34393. It didn't work. */ 238 g_test_bug ("34393"); 239 dbus_connection_set_max_received_size (f->left_server_conn, 1); 240 g_main_context_iteration (NULL, TRUE); 241 242 for (i = 0; i < MANY; i++) 243 { 244 gchar *buf = g_strdup_printf ("Message%u", i); 245 246 send_one (f, buf); 247 g_free (buf); 248 } 249 250 i = 0; 251 252 while (i < MANY) 253 { 254 while (g_queue_is_empty (&f->messages)) 255 { 256 g_main_context_iteration (NULL, TRUE); 257 } 258 259 while ((incoming = g_queue_pop_head (&f->messages)) != NULL) 260 { 261 i++; 262 dbus_message_unref (incoming); 263 } 264 } 265 } 266 267 static void 268 teardown (Fixture *f, 269 gconstpointer data G_GNUC_UNUSED) 270 { 271 if (f->left_client_conn != NULL) 272 { 273 dbus_connection_close (f->left_client_conn); 274 dbus_connection_unref (f->left_client_conn); 275 f->left_client_conn = NULL; 276 } 277 278 if (f->right_client_conn != NULL) 279 { 280 dbus_connection_close (f->right_client_conn); 281 dbus_connection_unref (f->right_client_conn); 282 f->right_client_conn = NULL; 283 } 284 285 if (f->left_server_conn != NULL) 286 { 287 dbus_connection_close (f->left_server_conn); 288 dbus_connection_unref (f->left_server_conn); 289 f->left_server_conn = NULL; 290 } 291 292 if (f->right_server_conn != NULL) 293 { 294 dbus_connection_close (f->right_server_conn); 295 dbus_connection_unref (f->right_server_conn); 296 f->right_server_conn = NULL; 297 } 298 299 if (f->server != NULL) 300 { 301 dbus_server_disconnect (f->server); 302 dbus_server_unref (f->server); 303 f->server = NULL; 304 } 305 } 306 307 int 308 main (int argc, 309 char **argv) 310 { 311 g_test_init (&argc, &argv, NULL); 312 g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); 313 314 g_test_add ("/connect", Fixture, NULL, setup, 315 test_connect, teardown); 316 g_test_add ("/relay", Fixture, NULL, setup, 317 test_relay, teardown); 318 g_test_add ("/limit", Fixture, NULL, setup, 319 test_limit, teardown); 320 321 return g_test_run (); 322 } 323