diff --git a/tests/ibus_live_test.c b/tests/ibus_live_test.c index 6008b88..b94f03e 100644 --- a/tests/ibus_live_test.c +++ b/tests/ibus_live_test.c @@ -19,6 +19,7 @@ enum { + Maxconnections = 16, Calltimeout = 4000, Starttimeout = 8000, Stoptimeout = 3000, @@ -626,6 +627,67 @@ closebus(DBusConnection **conn, Siglog *log) *conn = NULL; } +static int +overflowrejected(char *address) +{ + DBusConnection *conn; + DBusError err; + struct pollfd pfd; + int fd, n, ok, timeout; + int64_t deadline; + + dbus_error_init(&err); + conn = dbus_connection_open_private(address, &err); + if(conn == NULL){ + if(!dbus_error_is_set(&err)){ + dbus_error_free(&err); + return fail("overflow connection failed without a D-Bus error"); + } + dbus_error_free(&err); + return 1; + } + dbus_error_free(&err); + dbus_connection_set_exit_on_disconnect(conn, FALSE); + if(!dbus_connection_get_unix_fd(conn, &fd)){ + dbus_connection_close(conn); + dbus_connection_unref(conn); + return fail("overflow connection has no Unix descriptor"); + } + ok = 0; + deadline = nowms() + Calltimeout; + for(;;){ + if(!dbus_connection_get_is_connected(conn)){ + ok = 1; + break; + } + timeout = leftms(deadline); + if(timeout == 0){ + fail("overflow IBus connection was not rejected"); + break; + } + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + n = poll(&pfd, 1, timeout); + if(n < 0 && errno == EINTR) + continue; + if(n < 0){ + fail("poll overflow IBus connection: %s", strerror(errno)); + break; + } + if(n == 0) + continue; + if(pfd.revents & POLLNVAL){ + fail("overflow IBus descriptor became invalid"); + break; + } + dbus_connection_read_write_dispatch(conn, 0); + } + dbus_connection_close(conn); + dbus_connection_unref(conn); + return ok; +} + static DBusMessage* method(char *path, char *iface, char *member) { @@ -642,9 +704,11 @@ static DBusMessage* sendcall(DBusConnection *conn, DBusMessage *m) { DBusMessage *reply; - DBusError err; + DBusPendingCall *pending; char member[64], path[128]; const char *s; + int timeout; + int64_t deadline; if(m == NULL) return NULL; @@ -652,21 +716,39 @@ sendcall(DBusConnection *conn, DBusMessage *m) snprintf(member, sizeof member, "%s", s != NULL ? s : "method"); s = dbus_message_get_path(m); snprintf(path, sizeof path, "%s", s != NULL ? s : "path"); - dbus_error_init(&err); - reply = dbus_connection_send_with_reply_and_block(conn, m, - Calltimeout, &err); - dbus_message_unref(m); - if(reply == NULL){ - fail("%s on %s: %s: %s", member, path, - err.name != NULL ? err.name : "D-Bus error", - err.message != NULL ? err.message : "no reply"); - dbus_error_free(&err); + pending = NULL; + if(!dbus_connection_send_with_reply(conn, m, &pending, Calltimeout) || + pending == NULL){ + dbus_message_unref(m); + fail("queue %s on %s: out of memory", member, path); + return NULL; + } + dbus_message_unref(m); + deadline = nowms() + Calltimeout; + while(!dbus_pending_call_get_completed(pending)){ + timeout = leftms(deadline); + if(timeout == 0){ + fail("timed out waiting for %s on %s", member, path); + goto fail; + } + if(!dbus_connection_read_write_dispatch(conn, timeout)){ + fail("connection closed waiting for %s on %s", member, path); + goto fail; + } + } + reply = dbus_pending_call_steal_reply(pending); + dbus_pending_call_unref(pending); + if(reply == NULL){ + fail("%s on %s completed without a reply", member, path); return NULL; } - dbus_error_free(&err); while(dbus_connection_get_dispatch_status(conn) == DBUS_DISPATCH_DATA_REMAINS) dbus_connection_dispatch(conn); return reply; +fail: + dbus_pending_call_cancel(pending); + dbus_pending_call_unref(pending); + return NULL; } static int @@ -930,6 +1012,67 @@ expectkey(DBusConnection *conn, Siglog *log, char *path, text[0] != '\0', where); } +static int +runconnectioncapacity(Daemon *d) +{ + DBusConnection *conn[Maxconnections]; + Siglog logs[Maxconnections]; + char names[Maxconnections][32]; + char paths[Maxconnections][96]; + int i, ok; + + for(i = 0; i < Maxconnections; i++) + conn[i] = NULL; + memset(logs, 0, sizeof logs); + ok = 0; + for(i = 0; i < Maxconnections; i++){ + conn[i] = openbus(d->address, &logs[i]); + if(conn[i] == NULL || !hello(conn[i], names[i], sizeof names[i]) || + !createcontext(conn[i], paths[i], sizeof paths[i]) || + !emptycall(conn[i], &logs[i], paths[i], "FocusIn") || + !nosignal(&logs[i], "connection capacity FocusIn") || + !expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "", + "connection capacity key")) + goto out; + } + if(!overflowrejected(d->address)) + goto out; + for(i = 0; i < Maxconnections; i++) + if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "", + "accepted connection after rejection")) + goto out; + closebus(&conn[Maxconnections-1], &logs[Maxconnections-1]); + if(!expectkey(conn[0], &logs[0], paths[0], 0xffe1, 0, 0, "", + "connection close barrier")) + goto out; + conn[Maxconnections-1] = openbus(d->address, + &logs[Maxconnections-1]); + if(conn[Maxconnections-1] == NULL || + !hello(conn[Maxconnections-1], names[Maxconnections-1], + sizeof names[Maxconnections-1]) || + !createcontext(conn[Maxconnections-1], paths[Maxconnections-1], + sizeof paths[Maxconnections-1]) || + !emptycall(conn[Maxconnections-1], &logs[Maxconnections-1], + paths[Maxconnections-1], "FocusIn") || + !nosignal(&logs[Maxconnections-1], "recovered connection FocusIn") || + !expectkey(conn[Maxconnections-1], &logs[Maxconnections-1], + paths[Maxconnections-1], 'n', Ctrlmask, 1, "", + "recovered connection select Japanese") || + !expectkey(conn[Maxconnections-1], &logs[Maxconnections-1], + paths[Maxconnections-1], 'k', 0, 1, "k", + "recovered connection key")) + goto out; + for(i = 0; i < Maxconnections-1; i++) + if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "", + "accepted connection after recovery")) + goto out; + ok = 1; +out: + for(i = 0; i < Maxconnections; i++) + closebus(&conn[i], &logs[i]); + return ok; +} + static int runlifecycle(Daemon *d) { @@ -1060,6 +1203,8 @@ main(int argc, char **argv) return 2; } ok = startdaemon(&daemon, argv[1], argv[2]); + if(ok) + ok = runconnectioncapacity(&daemon); if(ok) ok = runlifecycle(&daemon); if(!ok) @@ -1068,6 +1213,6 @@ main(int argc, char **argv) ok = 0; if(!ok) return 1; - printf("ibus live lifecycle: ok\n"); + printf("ibus live lifecycle and connection capacity: ok\n"); return 0; }