mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-11 15:30:24 +01:00
protocol: add a ei_connection_setup interface
This replaces the connect/connect_done and version/get_version requests. Immediately after connecting, the server sends an ei_protocol_setup event to the client with the ID of the object and the server's highest supported version number (of this object). This is a one-shot object that the client can use to configure its name and whether it is a sender or receiver context. Once .done is sent, the object is discarded. The server version is sent along to the client to allow for requests to be added to this object in the future. As a fixme left: the client now assumes to be connected as soon as the .done request is sent and the following sync event is received. The EIS implementation will not have actually eis_client_connect()ed the client yet, but it's good enough for now. Arguably, the CONNECTED event is superfluous anyway since *any* event other than DISCONNECTED indicates connected status. CONNECTED is a leftover from when the client created devices and needed to know if it's worth doing so.
This commit is contained in:
parent
9cbce95326
commit
db786c7822
11 changed files with 465 additions and 163 deletions
|
|
@ -76,6 +76,7 @@ src_libei = files(
|
|||
'src/brei-shared.c',
|
||||
'src/libei.c',
|
||||
'src/libei-callback.c',
|
||||
'src/libei-connection-setup.c',
|
||||
'src/libei-connection.c',
|
||||
'src/libei-device.c',
|
||||
'src/libei-event.c',
|
||||
|
|
@ -121,6 +122,7 @@ src_libeis = files(
|
|||
'src/libeis.c',
|
||||
'src/libeis-callback.c',
|
||||
'src/libeis-client.c',
|
||||
'src/libeis-connection-setup.c',
|
||||
'src/libeis-connection.c',
|
||||
'src/libeis-device.c',
|
||||
'src/libeis-event.c',
|
||||
|
|
|
|||
|
|
@ -83,18 +83,6 @@
|
|||
summary="callback object for the sync request"/>
|
||||
</request>
|
||||
|
||||
<request name="get_version">
|
||||
</request>
|
||||
|
||||
<request name="connect">
|
||||
<arg name="version" type="uint"/>
|
||||
<arg name="name" type="string"/>
|
||||
<arg name="is_sender" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="connect_done">
|
||||
</request>
|
||||
|
||||
<request name="disconnect">
|
||||
</request>
|
||||
|
||||
|
|
@ -184,11 +172,25 @@
|
|||
<arg name="micros" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="version">
|
||||
<arg name="version" type="uint"/>
|
||||
</event>
|
||||
<event name="connection_setup">
|
||||
<description summary="initial connection setup">
|
||||
Provides the client with an object to initialize and setup the connection.
|
||||
This event is sent immediately after the client connects to the EIS
|
||||
implementation.
|
||||
|
||||
<event name="connected">
|
||||
A client should configure itself through that object, if applicable,
|
||||
and complete this configuration with the ei_connection_setup.done event.
|
||||
The object returned by this request will be destroyed by the
|
||||
EIS implementation after that done event and a client must not
|
||||
attempt to use it after that point.
|
||||
|
||||
The version sent by the server is the highest supported version
|
||||
of the connection setup interface. A client must only use
|
||||
requests supported by that version (or any lower version).
|
||||
</description>
|
||||
<arg name="setup" type="new_id" interface="ei_connection_setup"
|
||||
summary="the connection setup object" />
|
||||
<arg name="version" type="uint" summary="the version of the connection setup object"/>
|
||||
</event>
|
||||
|
||||
<event name="disconnected">
|
||||
|
|
@ -346,5 +348,47 @@
|
|||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_connection_setup" version="1">
|
||||
<description summary="connection setup object">
|
||||
</description>
|
||||
|
||||
<request name="done" since="1">
|
||||
<description summary="done request">
|
||||
Notify the EIS implementation that configuration is complete.
|
||||
|
||||
The ei_conection_setup object will be destroyed by the
|
||||
EIS implementation after this request is processed and
|
||||
the client must not attempt to use it after that point.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="context_type" since="1">
|
||||
<entry name="receiver" value="0"/>
|
||||
<entry name="sender" value="1"/>
|
||||
</enum>
|
||||
|
||||
<request name="type" since="1">
|
||||
<description summary="type request">
|
||||
Notify the EIS implementation of the type of this context.
|
||||
|
||||
This request is optional, the default client type is context_type.receiver.
|
||||
This request must not be sent more than once.
|
||||
</description>
|
||||
<arg name="context_type" type="uint" enum="context_type" summary="the client context type"/>
|
||||
</request>
|
||||
|
||||
<request name="name" since="1">
|
||||
<description summary="type request">
|
||||
Notify the EIS implementation of the client name. The name is a
|
||||
human-presentable UTF-8 string. There is no requirement
|
||||
for the EIS implementation to use this name.
|
||||
|
||||
This request is optional, the default client name is implementation-defined.
|
||||
This request must not be sent more than once.
|
||||
</description>
|
||||
<arg name="name" type="string" summary="the client name"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
|
||||
|
|
|
|||
91
src/libei-connection-setup.c
Normal file
91
src/libei-connection-setup.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* 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_setup 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 "libei-private.h"
|
||||
#include "ei-proto.h"
|
||||
|
||||
static void
|
||||
ei_connection_setup_destroy(struct ei_connection_setup *connection_setup)
|
||||
{
|
||||
struct ei *ei = ei_connection_setup_get_context(connection_setup);
|
||||
ei_unregister_object(ei, &connection_setup->proto_object);
|
||||
}
|
||||
|
||||
OBJECT_IMPLEMENT_REF(ei_connection_setup);
|
||||
OBJECT_IMPLEMENT_UNREF_CLEANUP(ei_connection_setup);
|
||||
OBJECT_IMPLEMENT_GETTER(ei_connection_setup, user_data, void*);
|
||||
OBJECT_IMPLEMENT_SETTER(ei_connection_setup, user_data, void*);
|
||||
OBJECT_IMPLEMENT_GETTER_AS_REF(ei_connection_setup, proto_object, const struct brei_object *);
|
||||
|
||||
static
|
||||
OBJECT_IMPLEMENT_CREATE(ei_connection_setup);
|
||||
static
|
||||
OBJECT_IMPLEMENT_PARENT(ei_connection_setup, ei);
|
||||
|
||||
struct ei*
|
||||
ei_connection_setup_get_context(struct ei_connection_setup *connection_setup)
|
||||
{
|
||||
assert(connection_setup);
|
||||
return ei_connection_setup_parent(connection_setup);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ei_connection_setup_get_version(struct ei_connection_setup *connection_setup)
|
||||
{
|
||||
return connection_setup->proto_object.version;
|
||||
}
|
||||
|
||||
static const struct ei_connection_setup_interface interface = {
|
||||
/* no events */
|
||||
};
|
||||
|
||||
const struct ei_connection_setup_interface *
|
||||
ei_connection_setup_get_interface(struct ei_connection_setup *connection_setup) {
|
||||
return &interface;
|
||||
}
|
||||
|
||||
struct ei_connection_setup *
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t id, uint32_t version)
|
||||
{
|
||||
struct ei_connection_setup *connection_setup = ei_connection_setup_create(&ei->object);
|
||||
|
||||
connection_setup->proto_object.id = id;
|
||||
connection_setup->proto_object.implementation = connection_setup;
|
||||
connection_setup->proto_object.interface = &ei_connection_setup_proto_interface;
|
||||
connection_setup->proto_object.version = version;
|
||||
ei_register_object(ei, &connection_setup->proto_object);
|
||||
|
||||
return connection_setup; /* ref owned by caller */
|
||||
}
|
||||
55
src/libei-connection-setup.h
Normal file
55
src/libei-connection-setup.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
/* 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_setup 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_connection_setup;
|
||||
|
||||
typedef void (*ei_connection_setup_func)(struct ei_connection_setup *connection_setup, void *connection_setup_data, uint32_t proto_data);
|
||||
|
||||
/* This is a protocol-only object, not exposed in the API */
|
||||
struct ei_connection_setup {
|
||||
struct object object;
|
||||
struct brei_object proto_object;
|
||||
void *user_data; /* Note: user-data is attached to the object */
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, context, struct ei*);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, proto_object, const struct brei_object *);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, id, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, version, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, interface, const struct ei_connection_setup_interface *);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_setup, user_data, void*);
|
||||
OBJECT_DECLARE_SETTER(ei_connection_setup, user_data, void*);
|
||||
OBJECT_DECLARE_REF(ei_connection_setup);
|
||||
OBJECT_DECLARE_UNREF(ei_connection_setup);
|
||||
|
||||
struct ei_connection_setup *
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t id, uint32_t version);
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "libei-callback.h"
|
||||
#include "libei-connection.h"
|
||||
#include "libei-connection-setup.h"
|
||||
#include "libei-seat.h"
|
||||
#include "libei-device.h"
|
||||
#include "libei-event.h"
|
||||
|
|
@ -49,7 +50,6 @@ struct ei_backend_interface {
|
|||
enum ei_state {
|
||||
EI_STATE_NEW, /* No backend yet */
|
||||
EI_STATE_BACKEND, /* We have a backend */
|
||||
EI_STATE_VERSION_QUERY, /* Waiting for server version */
|
||||
EI_STATE_CONNECTING, /* client requested connect */
|
||||
EI_STATE_CONNECTED, /* server has sent connect */
|
||||
EI_STATE_DISCONNECTING, /* in the process of cleaning up */
|
||||
|
|
|
|||
113
src/libei.c
113
src/libei.c
|
|
@ -50,9 +50,6 @@ _Static_assert(sizeof(enum ei_keymap_type) == sizeof(int), "Invalid enum size");
|
|||
_Static_assert(sizeof(enum ei_event_type) == sizeof(int), "Invalid enum size");
|
||||
_Static_assert(sizeof(enum ei_log_priority) == sizeof(int), "Invalid enum size");
|
||||
|
||||
static int
|
||||
ei_finish_set_socket(struct ei *ei, uint32_t version);
|
||||
|
||||
static struct ei_seat *
|
||||
ei_find_seat(struct ei *ei, uint32_t seatid)
|
||||
{
|
||||
|
|
@ -1112,15 +1109,6 @@ ei_peek_event(struct ei *ei)
|
|||
return ei_event_ref(e);
|
||||
}
|
||||
|
||||
static int handle_msg_connected(struct ei_connection *connection)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
ei->state = EI_STATE_CONNECTED;
|
||||
queue_connect_event(ei);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_msg_disconnected(struct ei_connection *connection)
|
||||
{
|
||||
return -ECANCELED;
|
||||
|
|
@ -1338,59 +1326,52 @@ handle_msg_touch_up(struct ei_connection *connection, uint32_t deviceid, uint32_
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_version(struct ei_connection *connection, uint32_t version)
|
||||
static void
|
||||
connected(struct ei_connection *connection, void *user_data)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
if (version == 0) {
|
||||
log_bug(ei, "server version is zero");
|
||||
return -EINVAL;
|
||||
} else if (ei->server_version && ei->server_version != version) {
|
||||
log_bug(ei, "server version is not constant (was %u, now %u)",
|
||||
ei->server_version, version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_debug(ei, "server protocol version: %u", version);
|
||||
ei->server_version = version;
|
||||
/* FIXME: the connected event *should* mean that the server
|
||||
* has accepted us but we don't currently have any event
|
||||
* for this to hook onto. So let's just assume "connected" means
|
||||
* the server has seen our messages.
|
||||
*/
|
||||
ei->state = EI_STATE_CONNECTED;
|
||||
queue_connect_event(ei);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_connection_setup(struct ei_connection *connection, uint32_t new_id, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
struct ei_connection_setup *setup = ei_connection_setup_new(ei, new_id, version);
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_TYPE_SINCE_VERSION)
|
||||
ei_connection_setup_request_type(setup, ei->is_sender ? EI_CONNECTION_SETUP_CONTEXT_TYPE_SENDER : EI_CONNECTION_SETUP_CONTEXT_TYPE_RECEIVER);
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_NAME_SINCE_VERSION)
|
||||
ei_connection_setup_request_name(setup, ei->name);
|
||||
ei_connection_setup_request_done(setup);
|
||||
ei_connection_setup_unref(setup);
|
||||
|
||||
ei->state = EI_STATE_CONNECTING;
|
||||
|
||||
ei_connection_sync(ei->connection, connected, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_version_during_connection(struct ei_connection *connection, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
int rc = handle_msg_version(connection, version);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
const uint32_t our_version = VERSION_V(1);
|
||||
|
||||
ei->client_version = min(our_version, version);
|
||||
|
||||
return ei_finish_set_socket(ei, ei->client_version);
|
||||
}
|
||||
|
||||
static const struct ei_connection_interface intf_state_backend = {
|
||||
.version = handle_msg_version_during_connection,
|
||||
.connection_setup = handle_msg_connection_setup,
|
||||
/* Everything triggers -EPROTO */
|
||||
.connected = NULL,
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface intf_state_version_query = {
|
||||
.version = handle_msg_version_during_connection,
|
||||
/* Everything else triggers -EPROTO */
|
||||
.connected = NULL,
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface intf_state_connecting = {
|
||||
.connected = handle_msg_connected,
|
||||
.connection_setup = handle_msg_connection_setup,
|
||||
.disconnected = handle_msg_disconnected,
|
||||
.version = handle_msg_version,
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface intf_state_connected = {
|
||||
.connection_setup = NULL, /* EPROTO */
|
||||
.disconnected = handle_msg_disconnected,
|
||||
.seat_added = handle_msg_seat_added,
|
||||
.seat_removed = handle_msg_seat_removed,
|
||||
|
|
@ -1402,7 +1383,6 @@ static const struct ei_connection_interface intf_state_connected = {
|
|||
.device_keymap = handle_msg_device_keymap,
|
||||
.device_done = handle_msg_device_added_done,
|
||||
.keyboard_modifiers = handle_msg_keyboard_modifiers,
|
||||
.version = handle_msg_version,
|
||||
|
||||
/* events */
|
||||
.start_emulating = handle_msg_start_emulating,
|
||||
|
|
@ -1423,7 +1403,6 @@ static const struct ei_connection_interface intf_state_connected = {
|
|||
static const struct ei_connection_interface *interfaces[] = {
|
||||
[EI_STATE_NEW] = NULL,
|
||||
[EI_STATE_BACKEND] = &intf_state_backend,
|
||||
[EI_STATE_VERSION_QUERY] = &intf_state_version_query,
|
||||
[EI_STATE_CONNECTING] = &intf_state_connecting,
|
||||
[EI_STATE_CONNECTED] = &intf_state_connected,
|
||||
[EI_STATE_DISCONNECTING] = NULL,
|
||||
|
|
@ -1509,18 +1488,12 @@ ei_set_socket(struct ei *ei, int fd)
|
|||
ei->source = source_ref(source);
|
||||
ei->state = EI_STATE_BACKEND;
|
||||
|
||||
/* The server SHOULD have sent the version number, let's
|
||||
* process that. If it's ready, we don't need a full roundtrip.
|
||||
/* The server SHOULD have already sent the connection setup, let's
|
||||
* process that. If not ready, it'll happen in the next dispatch.
|
||||
*
|
||||
* FIXME: this will block if O_NONBLOCK is missing
|
||||
*/
|
||||
ei_dispatch(ei);
|
||||
|
||||
if (ei->state == EI_STATE_BACKEND) {
|
||||
/* The server didn't send the version number, so request it. */
|
||||
rc = ei_connection_request_get_version(ei->connection);
|
||||
ei->state = EI_STATE_VERSION_QUERY;
|
||||
}
|
||||
}
|
||||
|
||||
source_unref(source);
|
||||
|
|
@ -1528,28 +1501,6 @@ ei_set_socket(struct ei *ei, int fd)
|
|||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ei_finish_set_socket(struct ei *ei, uint32_t version)
|
||||
{
|
||||
int rc = ei_connection_request_connect(ei->connection, version, ei->name, ei->is_sender);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = ei_connection_request_connect_done(ei->connection);
|
||||
}
|
||||
if (rc == 0) {
|
||||
ei->state = EI_STATE_CONNECTING;
|
||||
/* This isn't needed, but it's the ideal point to send a sync to make sure
|
||||
* the other side of the socket supports this part of the protocol */
|
||||
ei_connection_sync(ei->connection, NULL, NULL);
|
||||
}
|
||||
if (rc != 0) {
|
||||
log_error(ei, "message failed to send: %s\n", strerror(-rc));
|
||||
ei_disconnect(ei);
|
||||
}
|
||||
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
_public_ void
|
||||
ei_configure_name(struct ei *ei, const char *name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ DEFINE_TRISTATE(started, finished, connected);
|
|||
static void
|
||||
eis_client_destroy(struct eis_client *client)
|
||||
{
|
||||
eis_connection_setup_unref(client->setup);
|
||||
eis_connection_unref(client->connection);
|
||||
free(client->name);
|
||||
source_remove(client->source);
|
||||
|
|
@ -185,9 +186,11 @@ eis_client_send_message(struct eis_client *client, uint32_t object_id,
|
|||
}
|
||||
|
||||
static int
|
||||
client_send_version(struct eis_client *client, uint32_t version)
|
||||
client_send_connection_setup(struct eis_client *client, struct eis_connection_setup *setup)
|
||||
{
|
||||
return eis_connection_event_version(client->connection, version);
|
||||
return eis_connection_event_connection_setup(client->connection,
|
||||
eis_connection_setup_get_id(setup),
|
||||
eis_connection_setup_get_version(setup));
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -196,12 +199,6 @@ client_send_disconnect(struct eis_client *client)
|
|||
return eis_connection_event_disconnected(client->connection);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_connect(struct eis_client *client)
|
||||
{
|
||||
return eis_connection_event_connected(client->connection);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_seat_added(struct eis_client *client, struct eis_seat *seat)
|
||||
{
|
||||
|
|
@ -277,14 +274,7 @@ eis_client_connect(struct eis_client *client)
|
|||
"%s: client already connected", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = client_send_connect(client);
|
||||
if (rc) {
|
||||
log_debug(eis_client_get_context(client), "Message failed to send: %s", strerror(-rc));
|
||||
eis_client_disconnect(client);
|
||||
} else {
|
||||
client->state = EIS_CLIENT_STATE_CONNECTED;
|
||||
}
|
||||
client->state = EIS_CLIENT_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -315,6 +305,17 @@ eis_client_disconnect(struct eis_client *client)
|
|||
eis_client_unref(client);
|
||||
}
|
||||
|
||||
void
|
||||
eis_client_setup_done(struct eis_client *client, const char *name, bool is_sender)
|
||||
{
|
||||
client->setup = NULL; /* connection object cleans itself up */
|
||||
client->name = xstrdup(name);
|
||||
client->is_sender = is_sender;
|
||||
|
||||
eis_queue_connect_event(client);
|
||||
client->state = EIS_CLIENT_STATE_CONNECTING;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_close_device(struct eis_connection *connection, uint32_t deviceid)
|
||||
{
|
||||
|
|
@ -555,49 +556,12 @@ client_msg_touch_up(struct eis_connection *connection, uint32_t deviceid, uint32
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_connect(struct eis_connection *connection, uint32_t version,
|
||||
const char *name, uint32_t is_sender)
|
||||
{
|
||||
struct eis_client *client = eis_connection_get_client(connection);
|
||||
|
||||
if (client->version > EIS_PROTOCOL_VERSION)
|
||||
return -EPROTO;
|
||||
|
||||
client->version = version;
|
||||
|
||||
if (client->name == NULL)
|
||||
client->name = xstrdup(name);
|
||||
|
||||
client->is_sender = !!is_sender;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_connect_done(struct eis_connection *connection)
|
||||
{
|
||||
struct eis_client *client = eis_connection_get_client(connection);
|
||||
|
||||
eis_queue_connect_event(client);
|
||||
client->state = EIS_CLIENT_STATE_CONNECTING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_disconnect(struct eis_connection *connection)
|
||||
{
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_get_version(struct eis_connection *connection)
|
||||
{
|
||||
struct eis_client *client = eis_connection_get_client(connection);
|
||||
return client_send_version(client, EI_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_sync(struct eis_connection *connection, uint32_t new_id)
|
||||
{
|
||||
|
|
@ -614,17 +578,13 @@ client_msg_sync(struct eis_connection *connection, uint32_t new_id)
|
|||
|
||||
static const struct eis_connection_interface intf_state_new = {
|
||||
.sync = client_msg_sync,
|
||||
.connect = client_msg_connect,
|
||||
.connect_done = client_msg_connect_done,
|
||||
.disconnect = client_msg_disconnect,
|
||||
.get_version = client_msg_get_version,
|
||||
};
|
||||
|
||||
/* Client is waiting for us, shouldn't send anything except disconnect */
|
||||
static const struct eis_connection_interface intf_state_connecting = {
|
||||
.sync = client_msg_sync,
|
||||
.disconnect = client_msg_disconnect,
|
||||
.get_version = client_msg_get_version,
|
||||
};
|
||||
|
||||
static const struct eis_connection_interface intf_state_connected = {
|
||||
|
|
@ -632,7 +592,6 @@ static const struct eis_connection_interface intf_state_connected = {
|
|||
.disconnect = client_msg_disconnect,
|
||||
.bind_seat = client_msg_bind_seat,
|
||||
.close_device = client_msg_close_device,
|
||||
.get_version = client_msg_get_version,
|
||||
|
||||
/* events */
|
||||
.start_emulating = client_msg_start_emulating,
|
||||
|
|
@ -694,8 +653,6 @@ client_dispatch(struct source *source, void *userdata)
|
|||
|
||||
static const char *client_states[] = {
|
||||
"NEW",
|
||||
"CONFIGURING",
|
||||
"CONFIGURED",
|
||||
"CONNECTING",
|
||||
"CONNECTED",
|
||||
"DISCONNECTED",
|
||||
|
|
@ -749,8 +706,10 @@ eis_client_new(struct eis *eis, int fd)
|
|||
|
||||
source_unref(s);
|
||||
|
||||
/* Immediately send our version so the client doesn't need a roundtrip */
|
||||
client_send_version(client, EI_PROTOCOL_VERSION);
|
||||
/* Send the event for the connection setup interface */
|
||||
struct eis_connection_setup *setup = eis_connection_setup_new(client, eis_client_get_new_id(client));
|
||||
client_send_connection_setup(client, setup);
|
||||
client->setup = setup;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@
|
|||
#include "util-list.h"
|
||||
|
||||
enum eis_client_state {
|
||||
EIS_CLIENT_STATE_NEW, /* just connected */
|
||||
EIS_CLIENT_STATE_CONNECTING, /* client requested connect */
|
||||
EIS_CLIENT_STATE_CONNECTED, /* server has sent connect */
|
||||
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_DISCONNECTED,
|
||||
};
|
||||
|
||||
|
|
@ -44,6 +44,8 @@ struct eis_client {
|
|||
struct list proto_objects; /* struct brei_objects list */
|
||||
uint32_t next_object_id;
|
||||
|
||||
struct eis_connection_setup *setup;
|
||||
|
||||
void *user_data;
|
||||
struct list link;
|
||||
struct source *source;
|
||||
|
|
@ -86,6 +88,9 @@ eis_client_unregister_object(struct eis_client *client, struct brei_object *obje
|
|||
void
|
||||
eis_add_client(struct eis *eis, struct eis_client *client);
|
||||
|
||||
void
|
||||
eis_client_setup_done(struct eis_client *client, const char *name, bool is_sender);
|
||||
|
||||
int
|
||||
eis_client_send_message(struct eis_client *client, uint32_t object_id,
|
||||
uint32_t opcode, const char *signature, size_t nargs, ...);
|
||||
|
|
|
|||
140
src/libeis-connection-setup.c
Normal file
140
src/libeis-connection-setup.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* 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_setup 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_connection_setup_destroy(struct eis_connection_setup *setup)
|
||||
{
|
||||
struct eis_client * client = eis_connection_setup_get_client(setup);
|
||||
eis_client_unregister_object(client, &setup->proto_object);
|
||||
|
||||
free(setup->name);
|
||||
}
|
||||
|
||||
OBJECT_IMPLEMENT_REF(eis_connection_setup);
|
||||
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_connection_setup);
|
||||
OBJECT_IMPLEMENT_GETTER(eis_connection_setup, version, uint32_t);
|
||||
OBJECT_IMPLEMENT_GETTER_AS_REF(eis_connection_setup, proto_object, const struct brei_object *);
|
||||
|
||||
static
|
||||
OBJECT_IMPLEMENT_CREATE(eis_connection_setup);
|
||||
static
|
||||
OBJECT_IMPLEMENT_PARENT(eis_connection_setup, eis_client);
|
||||
|
||||
struct eis_client*
|
||||
eis_connection_setup_get_client(struct eis_connection_setup *setup)
|
||||
{
|
||||
return eis_connection_setup_parent(setup);
|
||||
}
|
||||
|
||||
struct eis*
|
||||
eis_connection_setup_get_context(struct eis_connection_setup *setup)
|
||||
{
|
||||
struct eis_client *client = eis_connection_setup_parent(setup);
|
||||
return eis_client_get_context(client);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
eis_connection_setup_get_id(struct eis_connection_setup *setup)
|
||||
{
|
||||
return setup->proto_object.id;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_done(struct eis_connection_setup *setup)
|
||||
{
|
||||
struct eis_client *client = eis_connection_setup_get_client(setup);
|
||||
|
||||
eis_client_setup_done(client, setup->name, setup->is_sender);
|
||||
|
||||
eis_connection_setup_unref(setup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_name(struct eis_connection_setup *setup, const char *name)
|
||||
{
|
||||
if (setup->name)
|
||||
return -EPROTO;
|
||||
|
||||
setup->name = xstrdup(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_type(struct eis_connection_setup *setup, uint32_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case EIS_CONNECTION_SETUP_CONTEXT_TYPE_SENDER:
|
||||
case EIS_CONNECTION_SETUP_CONTEXT_TYPE_RECEIVER:
|
||||
setup->is_sender = !!type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
static const struct eis_connection_setup_interface interface = {
|
||||
.done = client_msg_done,
|
||||
.type = client_msg_type,
|
||||
.name = client_msg_name,
|
||||
};
|
||||
|
||||
const struct eis_connection_setup_interface *
|
||||
eis_connection_setup_get_interface(struct eis_connection_setup *setup) {
|
||||
return &interface;
|
||||
}
|
||||
|
||||
struct eis_connection_setup *
|
||||
eis_connection_setup_new(struct eis_client *client, uint32_t new_id)
|
||||
{
|
||||
struct eis_connection_setup *setup = eis_connection_setup_create(&client->object);
|
||||
|
||||
setup->proto_object.id = new_id;
|
||||
setup->proto_object.implementation = setup;
|
||||
setup->proto_object.interface = &eis_connection_setup_proto_interface;
|
||||
list_init(&setup->proto_object.link);
|
||||
|
||||
setup->version = VERSION_V(1);
|
||||
|
||||
eis_client_register_object(client, &setup->proto_object);
|
||||
|
||||
return setup; /* ref owned by caller */
|
||||
}
|
||||
54
src/libeis-connection-setup.h
Normal file
54
src/libeis-connection-setup.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
/* 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_setup 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;
|
||||
|
||||
/* This is a protocol-only object, not exposed in the API */
|
||||
struct eis_connection_setup {
|
||||
struct object object;
|
||||
struct brei_object proto_object;
|
||||
|
||||
uint32_t version;
|
||||
char *name;
|
||||
bool is_sender;
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, context, struct eis *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, client, struct eis_client *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, id, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, version, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, proto_object, const struct brei_object *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_setup, interface, const struct eis_connection_setup_interface *);
|
||||
OBJECT_DECLARE_REF(eis_connection_setup);
|
||||
OBJECT_DECLARE_UNREF(eis_connection_setup);
|
||||
|
||||
struct eis_connection_setup *
|
||||
eis_connection_setup_new(struct eis_client *client, uint32_t new_id);
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "libeis-callback.h"
|
||||
#include "libeis-client.h"
|
||||
#include "libeis-connection.h"
|
||||
#include "libeis-connection-setup.h"
|
||||
#include "libeis-device.h"
|
||||
#include "libeis-event.h"
|
||||
#include "libeis-region.h"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue