mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-04 08:20:25 +01:00
eis: don't send a disconnected event when the client requests disconnect
As the protocol spec says, EIS should treat this as already disconnected and not touch the connection. This fixes a memleak if a client connects and immediately disconnects - when EIS processes the EIS_EVENT_CLIENT_CONNECT it may set up a bunch of things like seats (the eis-demo-server does this). Then, later, when the EIS_EVENTE_CLIENT_DISCONNECT is processed, it calls eis_client_disconnect() but we were already in the disconnected state and the seats would not get released.
This commit is contained in:
parent
c8483c3a30
commit
9b390f5703
3 changed files with 38 additions and 18 deletions
|
|
@ -227,6 +227,15 @@ eis_client_connect(struct eis_client *client)
|
|||
client->state = EIS_CLIENT_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
static void
|
||||
client_drop_seats(struct eis_client *client)
|
||||
{
|
||||
struct eis_seat *s;
|
||||
list_for_each_safe(s, &client->seats, link) {
|
||||
eis_seat_drop(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_disconnect(struct eis_client *client,
|
||||
enum eis_connection_disconnect_reason reason,
|
||||
|
|
@ -237,20 +246,29 @@ client_disconnect(struct eis_client *client,
|
|||
/* Client already disconnected? don't bother sending an
|
||||
* event */
|
||||
return;
|
||||
case EIS_CLIENT_STATE_REQUESTED_DISCONNECT:
|
||||
/* Drop the seats again (see client_msg_disconnect) because
|
||||
* the server may have added seats between the client requesting the
|
||||
* disconnect and EIS actually processing that event
|
||||
*/
|
||||
client_drop_seats(client);
|
||||
/* DISCONNECTED event is already in the EIS queue */
|
||||
/* Must not send disconnected to the client */
|
||||
client->connection = eis_connection_unref(client->connection);
|
||||
client->state = EIS_CLIENT_STATE_DISCONNECTED;
|
||||
source_remove(client->source);
|
||||
break;
|
||||
case EIS_CLIENT_STATE_CONNECTING:
|
||||
case EIS_CLIENT_STATE_CONNECTED:
|
||||
{
|
||||
struct eis_seat *s;
|
||||
list_for_each_safe(s, &client->seats, link) {
|
||||
eis_seat_drop(s);
|
||||
}
|
||||
}
|
||||
client_drop_seats(client);
|
||||
eis_queue_disconnect_event(client);
|
||||
eis_connection_event_disconnected(client->connection,
|
||||
client->last_client_serial,
|
||||
reason, explanation);
|
||||
client->connection = eis_connection_unref(client->connection);
|
||||
_fallthrough_;
|
||||
client->state = EIS_CLIENT_STATE_DISCONNECTED;
|
||||
source_remove(client->source);
|
||||
break;
|
||||
case EIS_CLIENT_STATE_NEW:
|
||||
client->state = EIS_CLIENT_STATE_DISCONNECTED;
|
||||
source_remove(client->source);
|
||||
|
|
@ -301,7 +319,15 @@ static struct brei_result *
|
|||
client_msg_disconnect(struct eis_connection *connection)
|
||||
{
|
||||
struct eis_client * client = eis_connection_get_client(connection);
|
||||
client_disconnect(client, EIS_CONNECTION_DISCONNECT_REASON_DISCONNECTED, NULL);
|
||||
|
||||
/* We need to drop the seats because that unrolls the EIS device state
|
||||
* so that EIS gets the correct DEVICE_REMOVED sequence, etc.
|
||||
* Then queue the DISCONNECTED event and wait for EIS to call
|
||||
* eis_client_disconnect()
|
||||
*/
|
||||
client_drop_seats(client);
|
||||
eis_queue_disconnect_event(client);
|
||||
client->state = EIS_CLIENT_STATE_REQUESTED_DISCONNECT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +365,7 @@ static const struct eis_connection_interface *interfaces[] = {
|
|||
[EIS_CLIENT_STATE_NEW] = &intf_state_new,
|
||||
[EIS_CLIENT_STATE_CONNECTING] = &intf_state_connecting,
|
||||
[EIS_CLIENT_STATE_CONNECTED] = &intf_state_connected,
|
||||
[EIS_CLIENT_STATE_REQUESTED_DISCONNECT] = NULL,
|
||||
[EIS_CLIENT_STATE_DISCONNECTED] = NULL,
|
||||
};
|
||||
|
||||
|
|
@ -390,6 +417,7 @@ client_dispatch(struct source *source, void *userdata)
|
|||
"NEW",
|
||||
"CONNECTING",
|
||||
"CONNECTED",
|
||||
"REQUESTED_DISCONNECT",
|
||||
"DISCONNECTED",
|
||||
};
|
||||
if (result)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ enum eis_client_state {
|
|||
EIS_CLIENT_STATE_NEW, /* socket just handed over */
|
||||
EIS_CLIENT_STATE_CONNECTING, /* client completed setup but hasn't been accepted yet */
|
||||
EIS_CLIENT_STATE_CONNECTED, /* caller has done eis_client_connect */
|
||||
EIS_CLIENT_STATE_REQUESTED_DISCONNECT, /* caller has disconnected */
|
||||
EIS_CLIENT_STATE_DISCONNECTED,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -476,16 +476,7 @@ class TestEiProtocol:
|
|||
)
|
||||
|
||||
for call in connection.calllog:
|
||||
if call.name == "Disconnected":
|
||||
assert call.args["explanation"] is None
|
||||
assert (
|
||||
call.args["reason"] == EiConnection.EiDisconnectReason.DISCONNECTED
|
||||
)
|
||||
break
|
||||
else:
|
||||
assert (
|
||||
False
|
||||
), f"Expected Disconnected event, got none in {connection.calllog}"
|
||||
assert call.name != "Disconnected", "No disconnect event allowed here"
|
||||
|
||||
try:
|
||||
ei.send(connection.Disconnect())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue