Split the ping/pong request into its own interface

Leave the ei_callback as-is and instead add ei_pingpong for the same
thing initiated by the server. The interface is otherwise identical but
for the direction it is supposed to flow.

This reduces the possibility of a client accidentally sending a
request when it is supposed to handle an event or vice versa.
This commit is contained in:
Peter Hutterer 2023-02-14 08:46:35 +10:00
parent f41cc91599
commit 6ed610e30e
16 changed files with 404 additions and 60 deletions

View file

@ -83,6 +83,7 @@ src_libei = files(
'src/libei-fd.c',
'src/libei-keyboard.c',
'src/libei-log.c',
'src/libei-pingpong.c',
'src/libei-pointer.c',
'src/libei-region.c',
'src/libei-region.c',
@ -132,6 +133,7 @@ src_libeis = files(
'src/libeis-fd.c',
'src/libeis-keyboard.c',
'src/libeis-log.c',
'src/libeis-pingpong.c',
'src/libeis-pointer.c',
'src/libeis-region.c',
'src/libeis-seat.c',

View file

@ -366,7 +366,7 @@
a protocol violation to send this event to a client without the
"ei_callback" interface.
</description>
<arg name="callback" type="new_id" interface="ei_callback"
<arg name="ping" type="new_id" interface="ei_pingpong"
summary="callback object for the ping request"/>
<arg name="version" type="uint" summary="the version of the callback object"/>
</event>
@ -382,6 +382,31 @@
support for this interface in ei_connection_setup.interface.
</description>
<!-- ei_callback events version 1 -->
<event name="done" type="destructor" since="1">
<description summary="done event">
Notify the client when the related request is done. Immediately after this event
the ei_callback object is destroyed by the EIS implementation and as such the
client must not attempt to use it after that point.
This event may only be sent on an ei_callback object that was created by the
client.
</description>
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
</event>
</interface>
<interface name="ei_pingpong" version="1">
<description summary="callback object">
Interface for ensuring a roundtrip to the client implementation.
This interface is identical to ei_callback but is intended for
the EIS implementation to enforce a roundtrip to the client.
Note that for a client to receive objects of this type, it must announce
support for this interface in ei_connection_setup.interface.
</description>
<!-- ei_callback client requests version 1 -->
<request name="done" type="destructor" since="1">
@ -397,18 +422,6 @@
</request>
<!-- ei_callback events version 1 -->
<event name="done" type="destructor" since="1">
<description summary="done event">
Notify the client when the related request is done. Immediately after this event
the ei_callback object is destroyed by the EIS implementation and as such the
client must not attempt to use it after that point.
This event may only be sent on an ei_callback object that was created by the
client.
</description>
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
</event>
</interface>
<interface name="ei_seat" version="1">

View file

@ -86,6 +86,7 @@ ei_connection_setup_initialize(struct ei_connection_setup *setup, uint32_t versi
ei_connection_setup_request_interface_version(setup, "ei_connection_setup", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_connection", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_callback", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_pingpong", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_seat", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_device", VERSION_V(1));
ei_connection_setup_request_interface_version(setup, "ei_pointer", VERSION_V(1));

110
src/libei-pingpong.c Normal file
View file

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdbool.h>
#include "util-bits.h"
#include "util-macros.h"
#include "util-mem.h"
#include "util-io.h"
#include "util-strings.h"
#include "util-version.h"
#include "libei-private.h"
#include "ei-proto.h"
static void
ei_pingpong_destroy(struct ei_pingpong *pingpong)
{
struct ei *ei = ei_pingpong_get_context(pingpong);
ei_unregister_object(ei, &pingpong->proto_object);
}
OBJECT_IMPLEMENT_REF(ei_pingpong);
OBJECT_IMPLEMENT_UNREF_CLEANUP(ei_pingpong);
OBJECT_IMPLEMENT_GETTER(ei_pingpong, user_data, void*);
OBJECT_IMPLEMENT_SETTER(ei_pingpong, user_data, void*);
OBJECT_IMPLEMENT_GETTER_AS_REF(ei_pingpong, proto_object, const struct brei_object*);
static
OBJECT_IMPLEMENT_CREATE(ei_pingpong);
static
OBJECT_IMPLEMENT_PARENT(ei_pingpong, ei);
struct ei*
ei_pingpong_get_context(struct ei_pingpong *pingpong)
{
assert(pingpong);
return ei_pingpong_parent(pingpong);
}
uint32_t
ei_pingpong_get_id(struct ei_pingpong *pingpong)
{
return pingpong->proto_object.id;
}
static const struct ei_pingpong_interface interface = {
};
const struct ei_pingpong_interface *
ei_pingpong_get_interface(struct ei_pingpong *pingpong) {
return &interface;
}
struct ei_pingpong *
ei_pingpong_new(struct ei *ei, ei_pingpong_func func, void *pingpong_data)
{
struct ei_pingpong *pingpong = ei_pingpong_create(&ei->object);
pingpong->proto_object.id = ei_get_new_id(ei);
pingpong->proto_object.implementation = pingpong;
pingpong->proto_object.interface = &ei_pingpong_proto_interface;
pingpong->proto_object.version = VERSION_V(1);
pingpong->pingpong_data = pingpong_data;
ei_register_object(ei, &pingpong->proto_object);
pingpong->func = func;
list_init(&pingpong->link);
return pingpong; /* ref owned by caller */
}
struct ei_pingpong *
ei_pingpong_new_for_id(struct ei *ei, uint32_t id, uint32_t version)
{
struct ei_pingpong *pingpong = ei_pingpong_create(&ei->object);
pingpong->proto_object.id = id;
pingpong->proto_object.implementation = pingpong;
pingpong->proto_object.interface = &ei_pingpong_proto_interface;
pingpong->proto_object.version = version; /* FIXME */
ei_register_object(ei, &pingpong->proto_object);
list_init(&pingpong->link);
return pingpong; /* ref owned by caller */
}

62
src/libei-pingpong.h Normal file
View file

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2020 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "util-object.h"
#include "util-list.h"
#include "brei-shared.h"
struct ei;
struct ei_pingpong;
typedef void (*ei_pingpong_func)(struct ei_pingpong *pingpong, void *pingpong_data, uint32_t proto_data);
/* This is a protocol-only object, not exposed in the API */
struct ei_pingpong {
struct object object;
struct brei_object proto_object;
void *user_data; /* Note: user-data is attached to the object */
struct list link; /* for use by the callers, if needed */
ei_pingpong_func func;
void *pingpong_data; /* Note: pingpong-data is attached to the pingpong */
};
OBJECT_DECLARE_GETTER(ei_pingpong, context, struct ei*);
OBJECT_DECLARE_GETTER(ei_pingpong, proto_object, const struct brei_object *);
OBJECT_DECLARE_GETTER(ei_pingpong, id, uint32_t);
OBJECT_DECLARE_GETTER(ei_pingpong, interface, const struct ei_pingpong_interface *);
OBJECT_DECLARE_GETTER(ei_pingpong, user_data, void *);
OBJECT_DECLARE_SETTER(ei_pingpong, user_data, void *);
OBJECT_DECLARE_REF(ei_pingpong);
OBJECT_DECLARE_UNREF(ei_pingpong);
struct ei_pingpong *
ei_pingpong_new(struct ei *ei, ei_pingpong_func func, void *pingpong_data);
struct ei_pingpong *
ei_pingpong_new_for_id(struct ei *ei, uint32_t id, uint32_t version);

View file

@ -42,6 +42,7 @@
#include "libei-device.h"
#include "libei-keyboard.h"
#include "libei-event.h"
#include "libei-pingpong.h"
#include "libei-pointer.h"
#include "libei-region.h"
#include "libei-touchscreen.h"

View file

@ -83,7 +83,7 @@ OBJECT_IMPLEMENT_GETTER(ei, connection, struct ei_connection *);
DEFINE_UNREF_CLEANUP_FUNC(ei_device);
DEFINE_UNREF_CLEANUP_FUNC(ei_region);
DEFINE_UNREF_CLEANUP_FUNC(ei_callback);
DEFINE_UNREF_CLEANUP_FUNC(ei_pingpong);
struct ei *
ei_get_context(struct ei *ei)
@ -675,9 +675,9 @@ static int
handle_msg_ping(struct ei_connection *connection, uint32_t id, uint32_t version)
{
struct ei *ei = ei_connection_get_context(connection);
_unref_(ei_callback) *callback = ei_callback_new_for_id(ei, id, version);
_unref_(ei_pingpong) *pingpong = ei_pingpong_new_for_id(ei, id, version);
ei_callback_request_done(callback, 0);
ei_pingpong_request_done(pingpong, 0);
return 0;
}

View file

@ -80,15 +80,7 @@ eis_callback_get_version(struct eis_callback *callback)
return callback->proto_object.version;
}
static int
client_msg_done(struct eis_callback *callback, uint32_t callback_data)
{
callback->func(callback, callback->callback_data, callback_data);
return 0;
}
static const struct eis_callback_interface interface = {
.done = client_msg_done,
};
const struct eis_callback_interface *
@ -111,21 +103,3 @@ eis_callback_new(struct eis_client *client, uint32_t new_id, uint32_t version)
return callback; /* ref owned by caller */
}
struct eis_callback *
eis_callback_new_with_callback(struct eis_client *client, eis_callback_func func, void *callback_data)
{
struct eis_callback *callback = eis_callback_create(&client->object);
callback->proto_object.id = eis_client_get_new_id(client);
callback->proto_object.implementation = callback;
callback->proto_object.interface = &eis_callback_proto_interface;
callback->proto_object.version = VERSION_V(1); /* FIXME */
callback->callback_data = callback_data;
eis_client_register_object(client, &callback->proto_object);
callback->func = func;
list_init(&callback->link);
return callback; /* ref owned by caller */
}

View file

@ -382,6 +382,7 @@ eis_client_new(struct eis *eis, int fd)
.ei_connection = VERSION_V(1),
.ei_connection_setup = VERSION_V(1),
.ei_callback = VERSION_V(1),
.ei_pingpong = VERSION_V(1),
.ei_seat = VERSION_V(1),
.ei_device = VERSION_V(1),
.ei_pointer = VERSION_V(1),

View file

@ -41,6 +41,7 @@ struct eis_client_interface_versions {
uint32_t ei_connection;
uint32_t ei_connection_setup;
uint32_t ei_callback;
uint32_t ei_pingpong;
uint32_t ei_seat;
uint32_t ei_device;
uint32_t ei_pointer;

View file

@ -145,6 +145,7 @@ client_msg_interface_version(struct eis_connection_setup *setup, const char *nam
.server_version = &setup->server_versions.name_, \
}
VERSION_ENTRY(ei_callback),
VERSION_ENTRY(ei_pingpong),
VERSION_ENTRY(ei_connection),
VERSION_ENTRY(ei_connection_setup),
VERSION_ENTRY(ei_seat),

View file

@ -43,11 +43,11 @@ eis_connection_destroy(struct eis_connection *connection)
struct eis_client *client = eis_connection_get_client(connection);
eis_client_unregister_object(client, &connection->proto_object);
struct eis_callback *cb;
list_for_each_safe(cb, &connection->pending_callbacks, link) {
struct eis_pingpong *cb;
list_for_each_safe(cb, &connection->pending_pingpongs, link) {
list_remove(&cb->link);
free(eis_callback_get_user_data(cb));
eis_callback_unref(cb);
free(eis_pingpong_get_user_data(cb));
eis_pingpong_unref(cb);
}
}
@ -102,29 +102,29 @@ eis_connection_new(struct eis_client *client)
connection->proto_object.version = client->interface_versions.ei_connection;
eis_client_register_object(client, &connection->proto_object);
list_init(&connection->pending_callbacks);
list_init(&connection->pending_pingpongs);
return connection; /* ref owned by caller */
}
struct callback_user_data {
struct pingpong_user_data {
eis_connection_ping_callback_t cb;
void *user_data;
};
static void
ping_callback(struct eis_callback *callback, void *callback_data, uint32_t proto_data)
ping_pingpong(struct eis_pingpong *pingpong, void *pingpong_data, uint32_t proto_data)
{
struct eis_connection *connection = callback_data;
struct eis_connection *connection = pingpong_data;
_cleanup_free_ struct callback_user_data *data = eis_callback_get_user_data(callback);
_cleanup_free_ struct pingpong_user_data *data = eis_pingpong_get_user_data(pingpong);
if (data->cb)
data->cb(connection, data->user_data);
/* remove from pending callbacks */
list_remove(&callback->link);
eis_callback_unref(callback);
list_remove(&pingpong->link);
eis_pingpong_unref(pingpong);
}
void
@ -138,13 +138,13 @@ eis_connection_ping(struct eis_connection *connection, eis_connection_ping_callb
* then we extract the user_data on the object and call into the
* cb supplied to this function.
*/
struct eis_callback *callback = eis_callback_new_with_callback(client, ping_callback, connection);
struct callback_user_data *data = xalloc(sizeof *data);
struct eis_pingpong *pingpong = eis_pingpong_new(client, ping_pingpong, connection);
struct pingpong_user_data *data = xalloc(sizeof *data);
data->cb = cb;
data->user_data = user_data;
eis_callback_set_user_data(callback, data);
list_append(&connection->pending_callbacks, &callback->link);
eis_pingpong_set_user_data(pingpong, data);
list_append(&connection->pending_pingpongs, &pingpong->link);
eis_connection_event_ping(connection, eis_callback_get_id(callback),
eis_callback_get_version(callback));
eis_connection_event_ping(connection, eis_pingpong_get_id(pingpong),
eis_pingpong_get_version(pingpong));
}

View file

@ -36,7 +36,7 @@ struct eis_connection {
struct object object;
struct brei_object proto_object;
struct list pending_callbacks;
struct list pending_pingpongs;
};
OBJECT_DECLARE_GETTER(eis_connection, context, struct eis *);

115
src/libeis-pingpong.c Normal file
View file

@ -0,0 +1,115 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdbool.h>
#include "util-bits.h"
#include "util-macros.h"
#include "util-mem.h"
#include "util-io.h"
#include "util-strings.h"
#include "util-version.h"
#include "libeis-private.h"
#include "eis-proto.h"
static void
eis_pingpong_destroy(struct eis_pingpong *pingpong)
{
struct eis_client * client = eis_pingpong_get_client(pingpong);
eis_client_unregister_object(client, &pingpong->proto_object);
}
OBJECT_IMPLEMENT_REF(eis_pingpong);
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_pingpong);
OBJECT_IMPLEMENT_GETTER_AS_REF(eis_pingpong, proto_object, const struct brei_object *);
OBJECT_IMPLEMENT_GETTER(eis_pingpong, user_data, void *);
OBJECT_IMPLEMENT_SETTER(eis_pingpong, user_data, void *);
static
OBJECT_IMPLEMENT_CREATE(eis_pingpong);
static
OBJECT_IMPLEMENT_PARENT(eis_pingpong, eis_client);
struct eis_client*
eis_pingpong_get_client(struct eis_pingpong *pingpong)
{
return eis_pingpong_parent(pingpong);
}
struct eis*
eis_pingpong_get_context(struct eis_pingpong *pingpong)
{
struct eis_client *client = eis_pingpong_parent(pingpong);
return eis_client_get_context(client);
}
uint32_t
eis_pingpong_get_id(struct eis_pingpong *pingpong)
{
return pingpong->proto_object.id;
}
uint32_t
eis_pingpong_get_version(struct eis_pingpong *pingpong)
{
return pingpong->proto_object.version;
}
static int
client_msg_done(struct eis_pingpong *pingpong, uint32_t pingpong_data)
{
pingpong->func(pingpong, pingpong->pingpong_data, pingpong_data);
return 0;
}
static const struct eis_pingpong_interface interface = {
.done = client_msg_done,
};
const struct eis_pingpong_interface *
eis_pingpong_get_interface(struct eis_pingpong *pingpong) {
return &interface;
}
struct eis_pingpong *
eis_pingpong_new(struct eis_client *client, eis_pingpong_func func, void *pingpong_data)
{
struct eis_pingpong *pingpong = eis_pingpong_create(&client->object);
pingpong->proto_object.id = eis_client_get_new_id(client);
pingpong->proto_object.implementation = pingpong;
pingpong->proto_object.interface = &eis_pingpong_proto_interface;
pingpong->proto_object.version = VERSION_V(1); /* FIXME */
pingpong->pingpong_data = pingpong_data;
eis_client_register_object(client, &pingpong->proto_object);
pingpong->func = func;
list_init(&pingpong->link);
return pingpong; /* ref owned by caller */
}

61
src/libeis-pingpong.h Normal file
View file

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2020 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "util-object.h"
#include "brei-shared.h"
struct eis;
struct eis_client;
struct eis_pingpong;
typedef void (*eis_pingpong_func)(struct eis_pingpong *pingpong, void *pingpong_data, uint32_t proto_data);
/* This is a protocol-only object, not exposed in the API */
struct eis_pingpong {
struct object object;
struct brei_object proto_object;
void *user_data; /* Note: user-data is attached to the object */
struct list link; /* for use by the callers, if needed */
eis_pingpong_func func;
void *pingpong_data; /* Note: pingpong-data is attached to the pingpong */
};
OBJECT_DECLARE_GETTER(eis_pingpong, context, struct eis *);
OBJECT_DECLARE_GETTER(eis_pingpong, client, struct eis_client *);
OBJECT_DECLARE_GETTER(eis_pingpong, id, uint32_t);
OBJECT_DECLARE_GETTER(eis_pingpong, version, uint32_t);
OBJECT_DECLARE_GETTER(eis_pingpong, proto_object, const struct brei_object *);
OBJECT_DECLARE_GETTER(eis_pingpong, interface, const struct eis_pingpong_interface *);
OBJECT_DECLARE_GETTER(eis_pingpong, user_data, void*);
OBJECT_DECLARE_SETTER(eis_pingpong, user_data, void*);
OBJECT_DECLARE_REF(eis_pingpong);
OBJECT_DECLARE_UNREF(eis_pingpong);
struct eis_pingpong *
eis_pingpong_new(struct eis_client *eis_client, eis_pingpong_func func, void *pingpong_data);

View file

@ -41,7 +41,9 @@
#include "libeis-connection-setup.h"
#include "libeis-device.h"
#include "libeis-event.h"
#include "libeis-pingpong.h"
#include "libeis-keyboard.h"
#include "libeis-pingpong.h"
#include "libeis-pointer.h"
#include "libeis-region.h"
#include "libeis-seat.h"