Purge libreis from the repo

libreis was intended for an intermediary to set some information that
the libei client cannot be entrusted with. In particular this was the
application name, the allowed capabilities, and some properties that -
once set - the client could no longer change (appid as probably the only
really useful one). The price for this was a rather complicated version
negotiation dance before the initial CONNECT request.

Now that we have a clear view of what's going to happen -
RemoteDesktop.ConnectToEIS and the InputCapture portal - there is no
longer any need for libreis. The extra information that libreis would've
sent is communicated out-of-band in both portals and are known to the
compositor at the time the connection is being established.

So we can simply drop this, it's no longer required and dropping it
makes the protocol significantly simpler anyway.
This commit is contained in:
Peter Hutterer 2023-01-30 08:58:15 +10:00
parent 8d7d6ca8b7
commit 479bda259a
17 changed files with 11 additions and 855 deletions

View file

@ -2,10 +2,9 @@ libei
=====
**libei** is a library for Emulated Input, primarily aimed at the Wayland
stack. It provides four parts:
stack. It provides three parts:
- 🥚 EI (Emulated Input) for the client side (`libei`)
- 🍦 EIS (Emulated Input Server) for the server side (`libeis`)
- 🍚 REIS (Restrictions for the EIS) for the portal in between (`libreis`)
- 🚌 oeffis is an optional helper library for DBus communication with the
XDG RemoteDesktop portal (`liboeffis`)
@ -15,7 +14,7 @@ for EI, or 🥣 brei. In the future, 🥣 brei may become a stable protocol. For
now, this C library is it.
For the purpose of this document, **libei** refers to the project,
`libei`/`libeis`/`libreis` to the libraries provided.
`libei`/`libeis` to the libraries provided.
Documentation
-------------
@ -165,20 +164,6 @@ For a `synergy` use-case, the setup requires:
captured, it merely provides the transport layer for events once that decision
has been made.
Using REIS
----------
`libreis` is designed to allow a third-party that does not have a full
context to manage restrictions. This is aimed at portals that only have the
file descriptor to the EIS implementation but cannot initiate a full EI
context.
`libreis` works so that this third-party can configure the EIS
implementation to restrict the abilities of an EI client (later) connected
to this implementation. For example, a portal can set the client name
using `libreis` based on the app-id. A client cannot override this name
later.
Differences between XTest vs libei
----------------------------------
@ -245,9 +230,7 @@ The current approach works so that
- `xdg-desktop-portal` provides `org.freedesktop.portal.RemoteDesktop.ConnectToEIS`
- a client connects to the `xdg-desktop-portal` to request emulated input
- `xdg-desktop-portal` authenticates a client and opens the initial
connection to the `libeis` socket. It restricts the capabilities available
on that socket (e.g. sets the client name based on `app-id` using
`libreis`).
connection to the `libeis` socket.
- `xdg-desktop-portal` hands over the file descriptor to the client which
can initialize a `libei` context
- from then on, `libei` and `libeis` talk directly to each other, the portal

View file

@ -55,7 +55,6 @@ config_h.set_quoted('EI_VERSION', meson.project_version())
config_h.set_quoted('EIS_VERSION', meson.project_version())
config_h.set('EI_PROTOCOL_VERSION', protocol_version)
config_h.set('EIS_PROTOCOL_VERSION', protocol_version)
config_h.set('REIS_PROTOCOL_VERSION', protocol_version)
subdir('proto')
@ -171,32 +170,6 @@ pkgconfig.generate(lib_libeis,
],
)
lib_libreis = shared_library('reis',
'src/libreis.h',
'src/libreis.c',
proto_headers,
dependencies: [dep_libutil, dep_protobuf],
gnu_symbol_visibility: 'hidden',
install: true,
include_directories: [inc_src],
)
install_headers('src/libreis.h')
dep_libreis = declare_dependency(link_with: lib_libreis,
include_directories: [inc_src])
meson.override_dependency('libreis', dep_libreis)
pkgconfig.generate(lib_libreis,
filebase: 'libreis',
name: 'libREIS',
description: 'Restriction handler for Emulated Input servers',
version: meson.project_version(),
libraries: lib_libreis,
variables: [
'protocol_version=' + protocol_version.to_string(),
],
)
dep_libxkbcommon = dependency('xkbcommon', required: false)
config_h.set10('HAVE_LIBXKBCOMMON', dep_libxkbcommon.found())
dep_libevdev = dependency('libevdev', required: false)

View file

@ -10,8 +10,7 @@ syntax = "proto3";
* ServerMessage sent from the server to the client
*
* A normal sequence consists of:
* [0. - proxy configures connection, see the section below]
* 1. - client establishes connection to server
* [1. - client establishes connection to server
* 2. - client sends "Connect"
* 2.a - server replies with "Connected" or
* 2.b - server replies with "Disconnected" and closes its end of the socket
@ -32,20 +31,6 @@ syntax = "proto3";
*
* Where a connection error occurs, the library (libei or libeis) will
* unroll the state as seen from the API.
*
* Pre-configuring a connection
* ----------------------------
*
* Where a proxy is in place (e.g. a portal), the client connection can be
* pre-configured to match the permissions model. The proxy opens or obtains a
* socket to the server, writes the Configure* messages onto that socket and
* then passes the fd to the client to create a libei context from that.
*
* The proxy can force a client name and/or restrict other options. This is
* invisible to the client, it does not know what restrictions are in place.
*
* Configure messages may only be sent before the client connection. Sending
* Configure messages after a client has connected will be silently ignored.
*/
/* Request the server version. This request MAY be sent at any time and/or
@ -63,57 +48,6 @@ message GetVersion {
string ei = 1; /* always "EI" */
}
/* Start a transaction of one or more Configure* messages, using the given protocol version.
* This MUST be the first Configure message sent and the transaction MUST be
* concluded by a ConfigureFinish message.
*
* Multiple transactions are permitted.
*/
message ConfigureStart {
fixed32 version = 1; /* Must be equal or less to the server's GetVersion response */
}
/* Signals the end of Configure transaction. Typically, this indicates that the
* connection will be passed to a diffent process (e.g. from a portal to the
* actual EI client).
*
* A new Configure transaction (with a different version, if applicable) may
* start after this transaction.
*/
message ConfigureFinish {
}
/* ConfigureName *must* be sent before the Connect event. Once a name is set,
* subsequent attempts to change the name are ignored, including the name
* provided in the Connect message.
*/
message ConfigureName {
string name = 1;
}
/* Changes the capability policy and allows or denies specific capabilities.
* By default, a client starts with all capabilities permitted. If one or more
* ConfigureCapabilities messages are sent, the allowed capabilities is the
* binary AND of all allowed_capabilities masks.
*
* In other words, it is only possible to remove a capability with
* (subsequent) ConfigureCapabilities messages.
*/
message ConfigureCapabilities {
fixed32 allowed_capabilities = 2;
}
/**
* ConfigureProperty *must* be sent before the Connect event. Once the client
* is connected or if sent outside a ConfigureStart/ConfigureFinish
* transaction, this message is ignored.
*/
message ConfigureProperty {
string name = 1;
string value = 2;
fixed32 permissions = 3;
}
message Connect {
fixed32 version = 1; /* Must be equal or less to the server's GetVersion response */
string name = 2;
@ -241,13 +175,6 @@ message ClientMessage {
TouchMotion touch_motion = 30;
TouchUp touch_up = 31;
Frame frame = 32;
/* Pre-connection configuration */
ConfigureStart configure_start = 100;
ConfigureFinish configure_finish = 101;
ConfigureName configure_name = 102;
ConfigureCapabilities configure_capabilities = 103;
ConfigureProperty configure_property = 104;
}
}

View file

@ -258,11 +258,6 @@ log_wire_message(struct ei *ei, const ClientMessage *msg, int error)
MSG_STRING_CASE(TOUCH_MOTION);
MSG_STRING_CASE(TOUCH_UP);
MSG_STRING_CASE(FRAME);
MSG_STRING_CASE(CONFIGURE_START);
MSG_STRING_CASE(CONFIGURE_FINISH);
MSG_STRING_CASE(CONFIGURE_NAME);
MSG_STRING_CASE(CONFIGURE_CAPABILITIES);
MSG_STRING_CASE(CONFIGURE_PROPERTY);
}
if (message == NULL)
assert(!"Unimplemented message type");

View file

@ -280,8 +280,6 @@ eis_client_disconnect(struct eis_client *client)
eis_queue_disconnect_event(client);
_fallthrough_;
case EIS_CLIENT_STATE_NEW:
case EIS_CLIENT_STATE_CONFIGURING:
case EIS_CLIENT_STATE_CONFIGURED:
client_send_disconnect(client);
client->state = EIS_CLIENT_STATE_DISCONNECTED;
source_remove(client->source);
@ -503,129 +501,6 @@ client_msg_touch_up(struct eis_client *client, uint32_t deviceid, uint32_t touch
return -EINVAL;
}
static tristate
client_is_in_configure_transaction(struct eis_client *client)
{
tristate t = tristate_connected;
switch (client->state) {
case EIS_CLIENT_STATE_NEW:
case EIS_CLIENT_STATE_CONFIGURED:
t = tristate_finished;
break;
case EIS_CLIENT_STATE_CONFIGURING:
t = tristate_started;
break;
case EIS_CLIENT_STATE_CONNECTING:
case EIS_CLIENT_STATE_CONNECTED:
case EIS_CLIENT_STATE_DISCONNECTED:
t = tristate_connected;
break;
}
return t;
}
static int
client_msg_configure_start(struct eis_client *client, uint32_t version)
{
tristate t = client_is_in_configure_transaction(client);
if (tristate_is_started(t))
return -EPROTO;
/* Once the client is connected, we silently ignore all Configure
requests so a broken portal can't accidentally disconnect a client */
if (tristate_is_connected(t))
return 0;
if (version == 0)
return -EINVAL;
client->configure_version = version;
client->state = EIS_CLIENT_STATE_CONFIGURING;
return 0;
}
static int
client_msg_configure_finish(struct eis_client *client)
{
tristate t = client_is_in_configure_transaction(client);
if (tristate_is_finished(t))
return -EPROTO;
/* Once the client is connected, we silently ignore all Configure
requests so a broken portal can't accidentally disconnect a client */
if (tristate_is_connected(t))
return 0;
client->configure_version = 0;
client->state = EIS_CLIENT_STATE_CONFIGURED;
return 0;
}
static int
client_msg_configure_name(struct eis_client *client, const char *name)
{
tristate t = client_is_in_configure_transaction(client);
if (tristate_is_finished(t))
return -EPROTO;
/* Once the client is connected, we silently ignore all Configure
requests so a broken portal can't accidentally disconnect a client */
if (tristate_is_connected(t))
return 0;
if (client->name)
return 0;
client->name = xstrdup(name);
return 0;
}
static int
client_msg_configure_capabilities(struct eis_client *client, uint32_t allowed_caps)
{
tristate t = client_is_in_configure_transaction(client);
if (tristate_is_finished(t))
return -EPROTO;
/* Once the client is connected, we silently ignore all Configure
requests so a broken portal can't accidentally disconnect a client */
if (tristate_is_connected(t))
return 0;
/* restrictions can only be reduced */
client->restrictions.cap_allow_mask &= allowed_caps;
return 0;
}
static int
client_msg_configure_property(struct eis_client *client,
const char *name, const char *value,
uint32_t permissions)
{
tristate t = client_is_in_configure_transaction(client);
if (tristate_is_finished(t))
return -EPROTO;
/* Once the client is connected, we silently ignore all Configure
requests so a broken portal can't accidentally disconnect a client */
if (tristate_is_connected(t))
return 0;
eis_property_update_from_client(client, name, value, permissions);
return 0;
}
static int
client_msg_connect(struct eis_client *client, uint32_t version,
const char *name, bool is_sender)
@ -691,24 +566,12 @@ static const struct eis_proto_interface intf_state_new = {
.connect_done = client_msg_connect_done,
.disconnect = client_msg_disconnect,
.get_version = client_msg_get_version,
.configure_start = client_msg_configure_start,
.configure_finish = client_msg_configure_finish,
.configure_name = client_msg_configure_name,
.configure_capabilities = client_msg_configure_capabilities,
.configure_property = client_msg_configure_property,
};
/* Client is waiting for us, shouldn't send anything except disconnect */
static const struct eis_proto_interface intf_state_connecting = {
.disconnect = client_msg_disconnect,
.get_version = client_msg_get_version,
.configure_start = client_msg_configure_start,
.configure_finish = client_msg_configure_finish,
.configure_name = client_msg_configure_name,
.configure_capabilities = client_msg_configure_capabilities,
.configure_property = client_msg_configure_property,
};
static const struct eis_proto_interface intf_state_connected = {
@ -732,19 +595,10 @@ static const struct eis_proto_interface intf_state_connected = {
.touch_motion = client_msg_touch_motion,
.touch_up = client_msg_touch_up,
.frame = client_msg_frame,
/* configuration */
.configure_start = client_msg_configure_start,
.configure_finish = client_msg_configure_finish,
.configure_name = client_msg_configure_name,
.configure_capabilities = client_msg_configure_capabilities,
.configure_property = client_msg_configure_property,
};
static const struct eis_proto_interface *interfaces[] = {
[EIS_CLIENT_STATE_NEW] = &intf_state_new,
[EIS_CLIENT_STATE_CONFIGURING] = &intf_state_new,
[EIS_CLIENT_STATE_CONFIGURED] = &intf_state_new,
[EIS_CLIENT_STATE_CONNECTING] = &intf_state_connecting,
[EIS_CLIENT_STATE_CONNECTED] = &intf_state_connected,
[EIS_CLIENT_STATE_DISCONNECTED] = NULL,

View file

@ -58,8 +58,6 @@ struct eis {
enum eis_client_state {
EIS_CLIENT_STATE_NEW, /* just connected */
EIS_CLIENT_STATE_CONFIGURING, /* in a Configure transaction */
EIS_CLIENT_STATE_CONFIGURED, /* finished a Configure transaction */
EIS_CLIENT_STATE_CONNECTING, /* client requested connect */
EIS_CLIENT_STATE_CONNECTED, /* server has sent connect */
EIS_CLIENT_STATE_DISCONNECTED,

View file

@ -616,26 +616,6 @@ eis_proto_handle_message(struct eis_client *client,
case CLIENT_MESSAGE__MSG_FRAME:
rc = call(frame, client, proto->frame->deviceid, proto->frame->timestamp);
break;
case CLIENT_MESSAGE__MSG_CONFIGURE_START:
rc = call(configure_start, client,
proto->configure_start->version);
break;
case CLIENT_MESSAGE__MSG_CONFIGURE_FINISH:
rc = call(configure_finish, client);
break;
case CLIENT_MESSAGE__MSG_CONFIGURE_NAME:
rc = call(configure_name, client,
proto->configure_name->name);
break;
case CLIENT_MESSAGE__MSG_CONFIGURE_CAPABILITIES:
rc = call(configure_capabilities, client,
proto->configure_capabilities->allowed_capabilities);
break;
case CLIENT_MESSAGE__MSG_CONFIGURE_PROPERTY:
rc = call(configure_property, client, proto->configure_property->name,
proto->configure_property->value[0] ? proto->configure_property->value : NULL,
proto->configure_property->permissions);
break;
default:
rc = -EBADMSG;
break;

View file

@ -61,14 +61,6 @@ struct eis_proto_interface {
uint32_t tid, double x, double y);
int (*touch_up)(struct eis_client *client, uint32_t deviceid, uint32_t tid);
int (*frame) (struct eis_client *client, uint32_t deviceid, uint64_t time);
/* configuration */
int (*configure_start)(struct eis_client *client, uint32_t version);
int (*configure_finish)(struct eis_client *client);
int (*configure_name)(struct eis_client *client, const char *name);
int (*configure_capabilities)(struct eis_client *client, uint32_t allow);
int (*configure_property)(struct eis_client *client, const char *name,
const char *value, uint32_t permissions);
};
struct eis_proto_requests {

View file

@ -404,9 +404,7 @@ const char *
eis_client_property_get(struct eis_client *client, const char *property);
/**
* Returns true if the client is allowed this capability. By default, clients
* can use any capability but where a reis intermediary is present, those
* capabilities may be reduced.
* Returns true if the client is allowed this capability.
*/
bool
eis_client_has_capability(struct eis_client *client,

View file

@ -1,199 +0,0 @@
/* 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.
*/
#include <config.h>
#include "libreis.h"
#include "util-bits.h"
#include "util-object.h"
#include "util-macros.h"
#include "util-strings.h"
#include "util-mem.h"
#include "util-io.h"
#include "util-version.h"
#include "proto/ei.pb-c.h"
struct reis {
struct object object;
int eisfd;
uint32_t version;
bool in_transaction;
};
static void
reis_destroy(struct reis *reis)
{
xclose(reis->eisfd);
}
_public_
OBJECT_IMPLEMENT_UNREF_CLEANUP(reis);
static
OBJECT_IMPLEMENT_CREATE(reis);
static int
send_msg(int fd, const ClientMessage *msg)
{
size_t msglen = client_message__get_packed_size(msg);
uint8_t buf[4 + msglen];
*(uint32_t*)buf = msglen;
client_message__pack(msg, buf + 4);
return min(0, xsend(fd, buf, sizeof(buf)));
}
_public_ struct reis *
reis_new(int eisfd)
{
_unref_(reis) *reis = reis_create(NULL);
reis->eisfd = xdup(eisfd);
if (reis->eisfd == -1)
return NULL;
/* FIXME: technically we should check the server's version before we
* send our own, but that requires adding reis_dispatch() and the code
* in the caller for this too.
*
* Since all we support right now is version 1 and any server will
* support that, so we don't need to care much.
*/
reis->version = VERSION_V(REIS_PROTOCOL_VERSION);
return steal(&reis);
}
#define prepare_msg(_type, _struct, _field) \
ClientMessage msg = CLIENT_MESSAGE__INIT; \
_struct _field = _type##__INIT; \
msg.msg_case = CLIENT_MESSAGE__MSG_##_type; \
msg._field = &_field
static int
reis_start(struct reis *reis)
{
if (reis->in_transaction)
return 0;
reis->in_transaction = true;
prepare_msg(CONFIGURE_START, ConfigureStart, configure_start);
configure_start.version = reis->version;
return send_msg(reis->eisfd, &msg);
}
static int
reis_finish(struct reis *reis)
{
if (!reis->in_transaction)
return 0;
reis->in_transaction = false;
prepare_msg(CONFIGURE_FINISH, ConfigureFinish, configure_finish);
return send_msg(reis->eisfd, &msg);
}
_public_ int
reis_set_property_with_permissions(struct reis *reis,
const char *name, const char *value,
uint32_t permissions)
{
int rc;
if ((rc = reis_start(reis)) != 0)
return rc;
prepare_msg(CONFIGURE_PROPERTY, ConfigureProperty, configure_property);
configure_property.name = (char*)name;
configure_property.value = value ? (char*)value : "";
configure_property.permissions = permissions;
rc = send_msg(reis->eisfd, &msg);
if (rc == 0)
return rc;
return reis_finish(reis);
}
_public_ int
reis_set_name(struct reis *reis, const char *name)
{
int rc;
if ((rc = reis_start(reis)) != 0)
return rc;
prepare_msg(CONFIGURE_NAME, ConfigureName, configure_name);
configure_name.name = (char*)name;
rc = send_msg(reis->eisfd, &msg);
if (rc == 0)
return rc;
return reis_finish(reis);
}
_public_ int
reis_allow_capability(struct reis *reis, enum reis_device_capability capability, ...)
{
int rc;
if ((rc = reis_start(reis)) != 0)
return rc;
enum reis_device_capability cap = capability;
uint32_t caps = 0;
va_list args;
va_start(args, capability);
do {
switch (cap) {
case REIS_DEVICE_CAP_POINTER:
case REIS_DEVICE_CAP_POINTER_ABSOLUTE:
case REIS_DEVICE_CAP_KEYBOARD:
case REIS_DEVICE_CAP_TOUCH:
caps |= bit(cap);
break;
default:
return -EINVAL;
}
} while ((cap = va_arg(args, enum reis_device_capability)) > 0);
va_end(args);
prepare_msg(CONFIGURE_CAPABILITIES, ConfigureCapabilities, configure_capabilities);
configure_capabilities.allowed_capabilities = caps;
rc = send_msg(reis->eisfd, &msg);
if (rc)
return rc;
return reis_finish(reis);
}

View file

@ -1,125 +0,0 @@
/* 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 <stdint.h>
#define _sentinel_ __attribute__((sentinel))
/**
* REIS is the library for Restrictions for EIS. This library is used by
* intermediaries between EI and EIS to reduce the capabilities that an EI
* client has available.
*
* It is a helper library that does not initiate a full EI or EIS
* context but works on the file descriptor instead.
*
* Restricting capabilities is a one-way-road. A default EIS context has
* full permissions, consecutive calls can only restrict the current
* permissions but not loosen them.
*/
struct reis;
enum reis_device_capability {
REIS_DEVICE_CAP_POINTER = 1,
REIS_DEVICE_CAP_POINTER_ABSOLUTE,
REIS_DEVICE_CAP_KEYBOARD,
REIS_DEVICE_CAP_TOUCH,
REIS_DEVICE_CAP_ALL = ~0,
};
/**
* @enum reis_property_permission
*
* A set of masks for operations permitted on properties. Note that property
* permissions only affect the libreis client, the server has full access to the
* properties at any time.
*/
enum reis_property_permission {
REIS_PROPERTY_PERM_NONE = 0,
REIS_PROPERTY_PERM_READ = (1 << 0),
REIS_PROPERTY_PERM_WRITE = (1 << 1),
REIS_PROPERTY_PERM_DELETE = (1 << 2),
REIS_PROPERTY_PERM_ALL = (REIS_PROPERTY_PERM_READ|REIS_PROPERTY_PERM_WRITE|REIS_PROPERTY_PERM_DELETE),
};
/**
* Create a new reis context based on the EIS connection at the other end of
* @a eisfd. The EIS context does not need to be in any
* specific state and no checking is done that there is indeed an EIS
* context at the other end of the fd.
*/
struct reis *
reis_new(int eisfd);
struct reis *
reis_unref(struct reis* reis);
/**
* See ei_property_set_with_permissions(), but the permissions are
* left as-is. If the property does not exist, it is created with permissions
* @ref REIS_PROPERTY_PERM_ALL.
*/
int
reis_set_property_with_permissions(struct reis *reis,
const char *property, const char *value,
uint32_t permission);
/**
* Set the name for the client on this connection.
*
* This function has no effect if the EI client has already sent the
* connection message to the server. IOW this can only be used to *set* the
* name but not to *change* the name of the client.
*
* Calling this function multiple times has no effect, only the first name
* is used.
*
* @return zero on success or a negative errno otherwise
*/
int
reis_set_name(struct reis *reis, const char *name);
/**
* Explicitly allow the given capabilities. The argument list must be
* terminated with zero.
*
* By default, an EIS implementation will allow any capability. Calling this
* function changes the EIS implementation's default behavior to deny all
* capabilities EXCEPT the ones given in this call. For example, the following
* code only allows the pointer and keyboard capabilty:
*
* @code
* reis_allow_capability(reis, REIS_DEVICE_CAP_POINTER,
* REIS_DEVICE_CAP_KEYBOARD, 0);
* @endcode
*
* @return Zero on success or a negative errno on failure
*/
_sentinel_ int
reis_allow_capability(struct reis *reis, enum reis_device_capability cap, ...);

View file

@ -7,10 +7,6 @@
#include <libeis.h>
#endif
#if INCLUDE_LIBREIS
#include <libreis.h>
#endif
int main(int argc, char **argv) {
return 0;
}

View file

@ -48,7 +48,6 @@ struct peck {
struct object object;
struct ei *ei;
struct eis *eis;
struct reis *reis;
uint32_t eis_behavior;
uint32_t ei_behavior;
struct logger *logger;
@ -120,7 +119,6 @@ peck_destroy(struct peck *peck)
ei_unref(peck->ei);
eis_unref(peck->eis);
reis_unref(peck->reis);
logger_unref(peck->logger);
}
@ -129,7 +127,6 @@ OBJECT_IMPLEMENT_CREATE(peck);
OBJECT_IMPLEMENT_UNREF(peck);
OBJECT_IMPLEMENT_GETTER(peck, ei, struct ei*);
OBJECT_IMPLEMENT_GETTER(peck, eis, struct eis*);
OBJECT_IMPLEMENT_GETTER(peck, reis, struct reis*);
void
peck_drop_ei(struct peck *peck)
@ -338,7 +335,7 @@ peck_log_handler(struct logger *logger,
}
static struct peck *
new_context(enum peck_ei_mode ei_mode, bool with_reis)
new_context(enum peck_ei_mode ei_mode)
{
struct peck *peck = peck_create(NULL);
@ -362,27 +359,15 @@ new_context(enum peck_ei_mode ei_mode, bool with_reis)
ei_log_set_handler(ei, peck_ei_log_handler);
ei_log_set_priority(ei, EI_LOG_PRIORITY_DEBUG);
ei_configure_name(ei, "eierpecken test context");
/* Setting up a backend sends out the CONNECT event - if
we want libreis do so something beforehand we need to
keep the fd and set up the backend later */
if (!with_reis) {
rc = ei_setup_backend_fd(ei, fd);
munit_assert_int(rc, ==, 0);
peck->ei_socket_fd = -1;
} else {
peck->ei_socket_fd = fd;
}
rc = ei_setup_backend_fd(ei, fd);
munit_assert_int(rc, ==, 0);
peck->ei_socket_fd = -1;
peck->ei = ei;
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_CONNECT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOSEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOSTART);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_FRAME);
if (with_reis) {
struct reis *reis = reis_new(fd);
peck->reis = reis;
}
peck->logger = logger_new("peck", peck);
logger_set_handler(peck->logger, peck_log_handler);
logger_set_priority(peck->logger, LOGGER_DEBUG);
@ -393,7 +378,7 @@ new_context(enum peck_ei_mode ei_mode, bool with_reis)
struct peck *
peck_new_context(enum peck_ei_mode ei_mode)
{
return new_context(ei_mode, false);
return new_context(ei_mode);
}
struct peck *
@ -402,12 +387,6 @@ peck_new(void)
return peck_new_context(PECK_EI_SENDER);
}
struct peck *
peck_new_context_with_reis(enum peck_ei_mode ei_mode)
{
return new_context(ei_mode, true);
}
void
peck_ei_connect(struct peck *peck)
{

View file

@ -29,7 +29,6 @@
#include "libei.h"
#include "libeis.h"
#include "libreis.h"
#include "util-mem.h"
@ -144,9 +143,6 @@ peck_new(void);
struct peck *
peck_new_context(enum peck_ei_mode ei_mode);
struct peck *
peck_new_context_with_reis(enum peck_ei_mode ei_mode);
void
peck_ei_connect(struct peck *peck);
@ -163,9 +159,6 @@ peck_enable_ei_behavior(struct peck *peck, enum peck_ei_behavior behavior);
struct ei *
peck_get_ei(struct peck *peck);
struct reis *
peck_get_reis(struct peck *peck);
void
peck_drop_ei(struct peck *peck);
@ -341,7 +334,6 @@ DEFINE_UNREF_CLEANUP_FUNC(eis_region);
of a test handles server vs client */
#define with_server(peck_) for (struct eis *eis = peck_get_eis(peck_); eis; eis = NULL)
#define with_client(peck_) for (struct ei *ei = peck_get_ei(peck_); ei; ei = NULL)
#define with_reis(peck_) for (struct reis *reis = peck_get_reis(peck_); reis; reis = NULL)
#define with_emulation(d_) for (bool _loop = ({ ei_device_start_emulating(d_); true;});\
_loop; \
({ ei_device_stop_emulating(d_); _loop = false; }))

View file

@ -64,7 +64,7 @@ lib_eierpecken = static_library('eierpecken',
'eierpecken.h',
'eierpecken.c',
include_directories: [inc_src, inc_builddir],
dependencies: [munit, dep_libutil, dep_libei, dep_libeis, dep_libreis],
dependencies: [munit, dep_libutil, dep_libei, dep_libeis],
)
test('eierpecken',
@ -74,7 +74,6 @@ test('eierpecken',
'test-ei-device.c',
'test-ei-seat.c',
'test-eis.c',
'test-reis.c',
link_with: lib_eierpecken,
include_directories: [inc_builddir],
dependencies: [dep_unittest, dep_libei, dep_libeis]))
@ -107,13 +106,6 @@ executable('test-build-libeis',
c_args : ['-Werror', '-DINCLUDE_LIBEIS=1'],
install : false)
executable('test-build-libreis',
'buildtest.c',
dependencies : [dep_libreis],
include_directories : [inc_src],
c_args : ['-Werror', '-DINCLUDE_LIBREIS=1'],
install : false)
if add_languages('cpp', required: false)
executable('test-build-cxx',
'buildtest.cc',

View file

@ -373,60 +373,3 @@ MUNIT_TEST(eistest_device_ignore_paused_device)
return MUNIT_OK;
}
MUNIT_TEST(eistest_property_list_on_connect)
{
_unref_(peck) *peck = peck_new_context_with_reis(PECK_EI_RECEIVER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_reis(peck) {
reis_set_property_with_permissions(reis, "testprop.all", "all", REIS_PROPERTY_PERM_ALL);
reis_set_property_with_permissions(reis, "testprop.r", "r", REIS_PROPERTY_PERM_READ);
reis_set_property_with_permissions(reis, "testprop.rw", "rw", REIS_PROPERTY_PERM_READ|REIS_PROPERTY_PERM_WRITE);
reis_set_property_with_permissions(reis, "testprop.w", "w", REIS_PROPERTY_PERM_WRITE);
}
peck_ei_connect(peck);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *connect = peck_ei_next_event(ei, EI_EVENT_CONNECT);
_unref_(ei_event) *prop_all = peck_ei_next_event(ei, EI_EVENT_PROPERTY);
_unref_(ei_event) *prop_r = peck_ei_next_event(ei, EI_EVENT_PROPERTY);
_unref_(ei_event) *prop_rw = peck_ei_next_event(ei, EI_EVENT_PROPERTY);
const char *name, *value;
uint32_t perms;
name = ei_event_property_get_name(prop_all);
value = ei_event_property_get_value(prop_all);
perms = ei_event_property_get_permissions(prop_all);
munit_assert_string_equal(name, "testprop.all");
munit_assert_string_equal(value, "all");
munit_assert_uint32(perms, ==, EI_PROPERTY_PERM_ALL);
name = ei_event_property_get_name(prop_r);
value = ei_event_property_get_value(prop_r);
perms = ei_event_property_get_permissions(prop_r);
munit_assert_string_equal(name, "testprop.r");
munit_assert_string_equal(value, "r");
munit_assert_uint32(perms, ==, EI_PROPERTY_PERM_READ);
name = ei_event_property_get_name(prop_rw);
value = ei_event_property_get_value(prop_rw);
perms = ei_event_property_get_permissions(prop_rw);
munit_assert_string_equal(name, "testprop.rw");
munit_assert_string_equal(value, "rw");
munit_assert_uint32(perms, ==, EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_WRITE);
peck_assert_no_ei_events(ei);
}
return MUNIT_OK;
}

View file

@ -1,122 +0,0 @@
/* 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.
*/
#include "config.h"
#include "util-munit.h"
#include "eierpecken.h"
MUNIT_TEST(test_reis_set_name)
{
_unref_(peck) *peck = peck_new_context_with_reis(PECK_EI_SENDER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_client(peck) {
/* Not sent until CONNECT */
ei_configure_name(ei, "gohan");
}
with_reis(peck) {
reis_set_name(reis, "meshi");
}
peck_ei_connect(peck);
with_reis(peck) {
/* After connect, should be ignored */
reis_set_name(reis, "kome");
}
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
struct eis_client *client = peck_eis_get_default_client(peck);
munit_assert_string_equal(eis_client_get_name(client), "meshi");
}
return MUNIT_OK;
}
MUNIT_TEST(test_reis_set_capabilities)
{
_unref_(peck) *peck = peck_new_context_with_reis(PECK_EI_SENDER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_reis(peck) {
reis_allow_capability(reis, REIS_DEVICE_CAP_POINTER, REIS_DEVICE_CAP_TOUCH, NULL);
}
peck_ei_connect(peck);
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
struct eis_client *client = peck_eis_get_default_client(peck);
munit_assert_true(eis_client_has_capability(client, EIS_DEVICE_CAP_POINTER));
munit_assert_true(eis_client_has_capability(client, EIS_DEVICE_CAP_TOUCH));
munit_assert_false(eis_client_has_capability(client, EIS_DEVICE_CAP_KEYBOARD));
munit_assert_false(eis_client_has_capability(client, EIS_DEVICE_CAP_POINTER_ABSOLUTE));
}
return MUNIT_OK;
}
MUNIT_TEST(test_reis_set_capabilities_reducing)
{
_unref_(peck) *peck = peck_new_context_with_reis(PECK_EI_SENDER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_reis(peck) {
reis_allow_capability(reis, REIS_DEVICE_CAP_POINTER, REIS_DEVICE_CAP_TOUCH, NULL);
/* now reduce even further */
reis_allow_capability(reis, REIS_DEVICE_CAP_POINTER, NULL);
}
peck_ei_connect(peck);
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
struct eis_client *client = peck_eis_get_default_client(peck);
munit_assert_true(eis_client_has_capability(client, EIS_DEVICE_CAP_POINTER));
munit_assert_false(eis_client_has_capability(client, EIS_DEVICE_CAP_TOUCH));
munit_assert_false(eis_client_has_capability(client, EIS_DEVICE_CAP_KEYBOARD));
munit_assert_false(eis_client_has_capability(client, EIS_DEVICE_CAP_POINTER_ABSOLUTE));
}
return MUNIT_OK;
}