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:
Peter Hutterer 2023-02-02 11:58:08 +10:00
parent 9cbce95326
commit db786c7822
11 changed files with 465 additions and 163 deletions

View file

@ -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',

View file

@ -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>

View 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 */
}

View 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);

View file

@ -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 */

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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, ...);

View 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 */
}

View 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);

View file

@ -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"