1 #include "qemu/osdep.h" 2 #include "qemu/dbus.h" 3 #include <gio/gio.h> 4 #include <gio/gunixfdlist.h> 5 #include "libqtest.h" 6 #include "ui/dbus-display1.h" 7 8 static GDBusConnection* 9 test_dbus_p2p_from_fd(int fd) 10 { 11 g_autoptr(GError) err = NULL; 12 g_autoptr(GSocket) socket = NULL; 13 g_autoptr(GSocketConnection) socketc = NULL; 14 GDBusConnection *conn; 15 16 socket = g_socket_new_from_fd(fd, &err); 17 g_assert_no_error(err); 18 19 socketc = g_socket_connection_factory_create_connection(socket); 20 g_assert(socketc != NULL); 21 22 conn = g_dbus_connection_new_sync( 23 G_IO_STREAM(socketc), NULL, 24 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | 25 G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING, 26 NULL, NULL, &err); 27 g_assert_no_error(err); 28 29 return conn; 30 } 31 32 static void 33 test_setup(QTestState **qts, GDBusConnection **conn) 34 { 35 int pair[2]; 36 37 *qts = qtest_init("-display dbus,p2p=yes -name dbus-test"); 38 39 g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); 40 41 qtest_qmp_add_client(*qts, "@dbus-display", pair[1]); 42 43 *conn = test_dbus_p2p_from_fd(pair[0]); 44 g_dbus_connection_start_message_processing(*conn); 45 } 46 47 static void 48 test_dbus_display_vm(void) 49 { 50 g_autoptr(GError) err = NULL; 51 g_autoptr(GDBusConnection) conn = NULL; 52 g_autoptr(QemuDBusDisplay1VMProxy) vm = NULL; 53 QTestState *qts = NULL; 54 55 test_setup(&qts, &conn); 56 57 vm = QEMU_DBUS_DISPLAY1_VM_PROXY( 58 qemu_dbus_display1_vm_proxy_new_sync( 59 conn, 60 G_DBUS_PROXY_FLAGS_NONE, 61 NULL, 62 DBUS_DISPLAY1_ROOT "/VM", 63 NULL, 64 &err)); 65 g_assert_no_error(err); 66 67 g_assert_cmpstr( 68 qemu_dbus_display1_vm_get_name(QEMU_DBUS_DISPLAY1_VM(vm)), 69 ==, 70 "dbus-test"); 71 qtest_quit(qts); 72 } 73 74 typedef struct TestDBusConsoleRegister { 75 GMainLoop *loop; 76 GThread *thread; 77 GDBusConnection *listener_conn; 78 GDBusObjectManagerServer *server; 79 } TestDBusConsoleRegister; 80 81 static gboolean listener_handle_scanout( 82 QemuDBusDisplay1Listener *object, 83 GDBusMethodInvocation *invocation, 84 guint arg_width, 85 guint arg_height, 86 guint arg_stride, 87 guint arg_pixman_format, 88 GVariant *arg_data, 89 TestDBusConsoleRegister *test) 90 { 91 g_main_loop_quit(test->loop); 92 93 return DBUS_METHOD_INVOCATION_HANDLED; 94 } 95 96 static void 97 test_dbus_console_setup_listener(TestDBusConsoleRegister *test) 98 { 99 g_autoptr(GDBusObjectSkeleton) listener = NULL; 100 g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL; 101 102 test->server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT); 103 listener = g_dbus_object_skeleton_new(DBUS_DISPLAY1_ROOT "/Listener"); 104 iface = QEMU_DBUS_DISPLAY1_LISTENER_SKELETON( 105 qemu_dbus_display1_listener_skeleton_new()); 106 g_object_connect(iface, 107 "signal::handle-scanout", listener_handle_scanout, test, 108 NULL); 109 g_dbus_object_skeleton_add_interface(listener, 110 G_DBUS_INTERFACE_SKELETON(iface)); 111 g_dbus_object_manager_server_export(test->server, listener); 112 g_dbus_object_manager_server_set_connection(test->server, 113 test->listener_conn); 114 115 g_dbus_connection_start_message_processing(test->listener_conn); 116 } 117 118 static void 119 test_dbus_console_registered(GObject *source_object, 120 GAsyncResult *res, 121 gpointer user_data) 122 { 123 TestDBusConsoleRegister *test = user_data; 124 g_autoptr(GError) err = NULL; 125 126 qemu_dbus_display1_console_call_register_listener_finish( 127 QEMU_DBUS_DISPLAY1_CONSOLE(source_object), 128 NULL, res, &err); 129 g_assert_no_error(err); 130 131 test->listener_conn = g_thread_join(test->thread); 132 test_dbus_console_setup_listener(test); 133 } 134 135 static gpointer 136 test_dbus_p2p_server_setup_thread(gpointer data) 137 { 138 return test_dbus_p2p_from_fd(GPOINTER_TO_INT(data)); 139 } 140 141 static void 142 test_dbus_display_console(void) 143 { 144 g_autoptr(GError) err = NULL; 145 g_autoptr(GDBusConnection) conn = NULL; 146 g_autoptr(QemuDBusDisplay1ConsoleProxy) console = NULL; 147 g_autoptr(GUnixFDList) fd_list = NULL; 148 g_autoptr(GMainLoop) loop = NULL; 149 QTestState *qts = NULL; 150 int pair[2], idx; 151 TestDBusConsoleRegister test; 152 153 test_setup(&qts, &conn); 154 155 g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); 156 fd_list = g_unix_fd_list_new(); 157 idx = g_unix_fd_list_append(fd_list, pair[1], NULL); 158 159 console = QEMU_DBUS_DISPLAY1_CONSOLE_PROXY( 160 qemu_dbus_display1_console_proxy_new_sync( 161 conn, 162 G_DBUS_PROXY_FLAGS_NONE, 163 NULL, 164 "/org/qemu/Display1/Console_0", 165 NULL, 166 &err)); 167 g_assert_no_error(err); 168 169 test.loop = loop = g_main_loop_new(NULL, FALSE); 170 test.thread = g_thread_new(NULL, test_dbus_p2p_server_setup_thread, 171 GINT_TO_POINTER(pair[0])); 172 173 qemu_dbus_display1_console_call_register_listener( 174 QEMU_DBUS_DISPLAY1_CONSOLE(console), 175 g_variant_new_handle(idx), 176 G_DBUS_CALL_FLAGS_NONE, 177 -1, 178 fd_list, 179 NULL, 180 test_dbus_console_registered, 181 &test); 182 183 g_main_loop_run(loop); 184 185 g_clear_object(&test.server); 186 g_clear_object(&test.listener_conn); 187 qtest_quit(qts); 188 } 189 190 static void 191 test_dbus_display_keyboard(void) 192 { 193 g_autoptr(GError) err = NULL; 194 g_autoptr(GDBusConnection) conn = NULL; 195 g_autoptr(QemuDBusDisplay1KeyboardProxy) keyboard = NULL; 196 QTestState *qts = NULL; 197 198 test_setup(&qts, &conn); 199 200 keyboard = QEMU_DBUS_DISPLAY1_KEYBOARD_PROXY( 201 qemu_dbus_display1_keyboard_proxy_new_sync( 202 conn, 203 G_DBUS_PROXY_FLAGS_NONE, 204 NULL, 205 "/org/qemu/Display1/Console_0", 206 NULL, 207 &err)); 208 g_assert_no_error(err); 209 210 211 g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 0); 212 g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0); 213 214 qemu_dbus_display1_keyboard_call_press_sync( 215 QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard), 216 0x1C, /* qnum enter */ 217 G_DBUS_CALL_FLAGS_NONE, 218 -1, 219 NULL, 220 &err); 221 g_assert_no_error(err); 222 223 /* may be should wait for interrupt? */ 224 g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1); 225 g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */ 226 227 qemu_dbus_display1_keyboard_call_release_sync( 228 QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard), 229 0x1C, /* qnum enter */ 230 G_DBUS_CALL_FLAGS_NONE, 231 -1, 232 NULL, 233 &err); 234 g_assert_no_error(err); 235 236 g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1); 237 g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0xF0); /* scan code 2 release */ 238 g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */ 239 240 g_assert_cmpint(qemu_dbus_display1_keyboard_get_modifiers( 241 QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard)), ==, 0); 242 243 qtest_quit(qts); 244 } 245 246 int 247 main(int argc, char **argv) 248 { 249 g_test_init(&argc, &argv, NULL); 250 251 qtest_add_func("/dbus-display/vm", test_dbus_display_vm); 252 qtest_add_func("/dbus-display/console", test_dbus_display_console); 253 qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard); 254 255 return g_test_run(); 256 } 257