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