protocol: make the connection setup the zero object with a proper handover

This changes the initial connection negotiation to have the
ei_connection_setup as the pre-existing object id 0. Once the client has
sent all the data to set up the connection, the EIS implementation
replies with a new object ID that is the ei_connection protocol object,
i.e. the main object.

This allows for version negotiation of our main protocol object.
This commit is contained in:
Peter Hutterer 2023-02-06 13:56:22 +10:00
parent 23433d3aff
commit 0a347f433f
12 changed files with 302 additions and 213 deletions

View file

@ -37,7 +37,7 @@
EIS implementation's native byte order.
- length is the length of the message in bytes, including the 12 header bytes
- sender-id is the id of the object sending the request/event. The sender-id
0 is reserved for the special "ei" object.
0 is reserved for the special "ei_connection_setup" object.
- opcode is the event or requeset-specific opcode, starting at 0
requests and events have overlapping opcode ranges, i.e. the first request
and the first event both have opcode 0.
@ -45,125 +45,42 @@
Types:
- 'uint': a 32-bit unsigned integer
- 'uint': a 32-bit signed integer
- 'int': a 32-bit signed integer
- 'float': a 32-bit IEEE-754 float
- 'fd': a file descriptor. Zero bytes in the message itself, transmitted
in the overhead
- 'string': a length-prefix zero-terminated string. Encoded as
one 32-bit unsigned integer for the length followed by the string.
The string is padded to the nearest 4-byte units, for example the string
"hello" is of length 6 but is zero-padded to 8 bytes. Full (le) encoding:
"hello" is of length 6 but is zero-padded to 8 bytes and with the 4-byte
length field thus takes 12 bytes in total. Full (le) encoding:
[0x06, 0x00, 0x00, 0x00, 'h', 'e', 'l', 'l', 'o', '\0', '\0\, '\0']
- 'new_id': an object id allocated by the caller. Client-allocated IDs begin
at 1 and must be less than 0xff000000.
IDs allocated by the EIS implementation start at and must not be less
than 0xff000000.
- 'object_id': a previously allocated object id
The initial connection is a two-step process:
An ei_connection_setup object with the special ID 0 is guaranteed to
exists. The client must send the appropriate requests to set up
its connection, followed by the .done request. The server replies
by creating the ei_connection object with the client-requested version
(or any lower version) that is the connection for the remainder of this
client.
-->
<interface name="ei_connection" version="1">
<description summary="core global object">
The core global object. This is a special singleton object. It
is used for internal ei protocol features.
</description>
<request name="sync" since="1">
<description summary="asynchronous roundtrip">
The sync request asks the EIS implementation to emit the 'done' event
on the returned ei_callback object. Since requests are
handled in-order and events are delivered in-order, this can
be used as a synchronization point to ensure all previous requests and the
resulting events have been handled.
The object returned by this request will be destroyed by the
EIS implementation after the callback is fired and as such the client must not
attempt to use it after that point.
<!-- FIXME: this needs to be something useful, but we don't have anything
useful to send yet -->
The callback_data passed in the callback is always zero.
</description>
<arg name="callback" type="new_id" interface="ei_callback"
summary="callback object for the sync request"/>
</request>
<request name="disconnect">
</request>
<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.
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>
<enum name="disconnect_reason">
<description summary="disconnection reason">
A reason why a client was disconnected.
</description>
<entry name="disconnected" value="0" help="client was purposely disconnected"/>
<entry name="error" value="1" help="an error caused the disconnection"/>
</enum>
<event name="disconnected">
<description summary="disconnection event">
This event may be sent by the EIS implementation immediately before
the client is disconnected.
Where a client is disconnected by EIS directly, the reason is
disconnect_reason.disconnected and the explanation is NULL.
Where a client is disconnected due to some invalid request or other
protocol error, the reason is disconnect_reason.error and
explanation may contain a string explaining why. This string is
intended to help debugging only and is not guaranteed to stay constant.
There is no guarantee this event is sent - the connection may be closed
without a disconnection event.
</description>
<arg name="reason" type="uint" enum="disconnect_reason"/>
<arg name="explanation" type="string"/>
</event>
<event name="seat" since="1">
<description summary="Seat presence notification">
Notification that a new seat has been added.
The interface version is equal or less to the client-supported
version in ei_connection_setup.interface for the "ei_seat"
interface.
</description>
<arg name="seat" type="new_id" interface="ei_seat"/>
<arg name="version" type="uint" summary="the interface version"/>
</event>
</interface>
<interface name="ei_callback" version="1">
<description summary="callback object">
Clients can handle the 'done' event to get notified when
the related request is done.
</description>
<event name="done" type="destructor">
<description summary="done event">
Notify the client when the related request is done.
</description>
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
</event>
</interface>
<interface name="ei_connection_setup" version="1">
<description summary="connection setup object">
This is a special interface to setup the client as seen by the EIS
implementation. The object for this interface has the fixed object
id 0 and only exists until the connection has been set up, see the
ei_connection_setup.connection event.
Once set up, the connection setup hands over to the main
ei_connection object which is the top-level object for all future
requests and events.
</description>
<request name="done" since="1">
@ -220,6 +137,129 @@
<arg name="name" type="string" summary="the interface name"/>
<arg name="version" type="uint" summary="the interface version"/>
</request>
<event name="version" since="1">
<description summary="the connection setup version">
The highest supported version of this interface
by the EIS implementation. Any requests
send by the client must be provided in this version
or any lower version.
This event is sent immediately after connection. A client
should not issue any requests until processing this version.
Note that the EIS implementation assumes that the supported
client version of this interface is 1 until the client announces
a higher version of this interface in the
ei_connection_setup.interface request.
</description>
<arg name="version" type="uint"
summary="the highest version supported by the EIS implementation"/>
</event>
<event name="connection">
<description summary="the core connection object">
Provides the client with the connection object that is the top-level
object for all future requests and events.
This event is sent immediately after the client sends the
ei_connection_setup.done request to the EIS implementation.
The ei_connection_setup object will be destroyed by the
EIS implementation immediately after this event has been sent, a
client must not attempt to use it after that point.
The version sent by the server is the version of the ei_connection
interface as announced by ei_connection_setup.interface, or any
lower version.
</description>
<arg name="connection" type="new_id" interface="ei_connection"
summary="the connection object" />
<arg name="version" type="uint" summary="the version of the connection object"/>
</event>
</interface>
<interface name="ei_connection" version="1">
<description summary="core global object">
The core global object. This is a special singleton object. It
is used for internal ei protocol features.
</description>
<request name="sync" since="1">
<description summary="asynchronous roundtrip">
The sync request asks the EIS implementation to emit the 'done' event
on the returned ei_callback object. Since requests are
handled in-order and events are delivered in-order, this can
be used as a synchronization point to ensure all previous requests and the
resulting events have been handled.
The object returned by this request will be destroyed by the
EIS implementation after the callback is fired and as such the client must not
attempt to use it after that point.
<!-- FIXME: this needs to be something useful, but we don't have anything
useful to send yet -->
The callback_data passed in the callback is always zero.
</description>
<arg name="callback" type="new_id" interface="ei_callback"
summary="callback object for the sync request"/>
</request>
<request name="disconnect">
</request>
<enum name="disconnect_reason">
<description summary="disconnection reason">
A reason why a client was disconnected.
</description>
<entry name="disconnected" value="0" help="client was purposely disconnected"/>
<entry name="error" value="1" help="an error caused the disconnection"/>
</enum>
<event name="disconnected">
<description summary="disconnection event">
This event may be sent by the EIS implementation immediately before
the client is disconnected.
Where a client is disconnected by EIS directly, the reason is
disconnect_reason.disconnected and the explanation is NULL.
Where a client is disconnected due to some invalid request or other
protocol error, the reason is disconnect_reason.error and
explanation may contain a string explaining why. This string is
intended to help debugging only and is not guaranteed to stay constant.
There is no guarantee this event is sent - the connection may be closed
without a disconnection event.
</description>
<arg name="reason" type="uint" enum="disconnect_reason"/>
<arg name="explanation" type="string"/>
</event>
<event name="seat" since="1">
<description summary="Seat presence notification">
Notification that a new seat has been added.
The interface version is equal or less to the client-supported
version in ei_connection_setup.interface for the "ei_seat"
interface.
</description>
<arg name="seat" type="new_id" interface="ei_seat"/>
<arg name="version" type="uint" summary="the interface version"/>
</event>
</interface>
<interface name="ei_callback" version="1">
<description summary="callback object">
Clients can handle the 'done' event to get notified when
the related request is done.
</description>
<event name="done" type="destructor">
<description summary="done event">
Notify the client when the related request is done.
</description>
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
</event>
</interface>
<interface name="ei_seat" version="1">

View file

@ -32,6 +32,7 @@
#include "util-mem.h"
#include "util-io.h"
#include "util-strings.h"
#include "util-version.h"
#include "libei-private.h"
#include "ei-proto.h"
@ -67,8 +68,82 @@ ei_connection_setup_get_version(struct ei_connection_setup *connection_setup)
return connection_setup->proto_object.version;
}
static int
ei_connection_setup_initialize(struct ei_connection_setup *setup, uint32_t version)
{
struct ei *ei = ei_connection_setup_get_context(setup);
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);
if (version >= EI_CONNECTION_SETUP_REQUEST_INTERFACE_SINCE_VERSION) {
ei_connection_setup_request_interface(setup, "ei_connection_setup", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_connection", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_callback", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_seat", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_device", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_pointer", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_keyboard", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_touchscreen", VERSION_V(1));
}
ei_connection_setup_request_done(setup);
return 0;
}
static int
handle_msg_version(struct ei_connection_setup *setup, uint32_t version)
{
uint32_t min_version = min(version, setup->proto_object.version);
setup->proto_object.version = min_version;
/* Now send all the bits we need to send */
ei_connection_setup_initialize(setup, version);
return 0;
}
static void
connected(struct ei_connection *connection, void *user_data)
{
struct ei *ei = ei_connection_get_context(connection);
/* If we get here, the server didn't immediately disconnect us */
if (ei->state == EI_STATE_DISCONNECTED)
return;
ei_connected(ei);
}
static int
handle_msg_connection(struct ei_connection_setup *setup, uint32_t id, uint32_t version)
{
struct ei *ei = ei_connection_setup_get_context(setup);
assert(setup == ei->connection_setup);
/* we're done with our connection setup, drop it */
ei_connection_setup_unref(steal(&ei->connection_setup));
ei->connection = ei_connection_new(ei, id, version);
ei->state = EI_STATE_CONNECTING;
/* Send a sync on the connection - EIS should immediately send a
* disconnect event where applicable, so if we get through to our
* sync callback, we didn't immediately get disconnected */
ei_connection_sync(ei->connection, connected, NULL);
return 0;
}
static const struct ei_connection_setup_interface interface = {
/* no events */
.version = handle_msg_version,
.connection = handle_msg_connection,
};
const struct ei_connection_setup_interface *
@ -77,11 +152,12 @@ ei_connection_setup_get_interface(struct ei_connection_setup *connection_setup)
}
struct ei_connection_setup *
ei_connection_setup_new(struct ei *ei, uint32_t id, uint32_t version)
ei_connection_setup_new(struct ei *ei, 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.id = ei_get_new_id(ei);
assert(connection_setup->proto_object.id == 0); /* Special object */
connection_setup->proto_object.implementation = connection_setup;
connection_setup->proto_object.interface = &ei_connection_setup_proto_interface;
connection_setup->proto_object.version = version;

View file

@ -52,4 +52,4 @@ 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);
ei_connection_setup_new(struct ei *ei, uint32_t version);

View file

@ -60,6 +60,18 @@ static
OBJECT_IMPLEMENT_PARENT(ei_connection, ei);
OBJECT_IMPLEMENT_GETTER_AS_REF(ei_connection, proto_object, const struct brei_object*);
uint32_t
ei_connection_get_version(struct ei_connection *connection)
{
return connection->proto_object.version;
}
uint32_t
ei_connection_get_id(struct ei_connection *connection)
{
return connection->proto_object.id;
}
struct ei*
ei_connection_get_context(struct ei_connection *connection)
{
@ -74,17 +86,14 @@ ei_connection_get_interface(struct ei_connection *connection) {
}
struct ei_connection *
ei_connection_new(struct ei *ei)
ei_connection_new(struct ei *ei, uint32_t id, uint32_t version)
{
struct ei_connection *connection = ei_connection_create(&ei->object);
connection->proto_object.id = ei_get_new_id(ei);
/* This is a special object and must have id 0 */
assert(connection->proto_object.id == 0);
connection->proto_object.id = id;
connection->proto_object.implementation = connection;
connection->proto_object.interface = &ei_connection_proto_interface;
connection->proto_object.version = VERSION_V(1);
connection->proto_object.version = version;
ei_register_object(ei, &connection->proto_object);
list_init(&connection->pending_callbacks);

View file

@ -41,13 +41,15 @@ struct ei_connection {
};
OBJECT_DECLARE_GETTER(ei_connection, context, struct ei*);
OBJECT_DECLARE_GETTER(ei_connection, version, uint32_t);
OBJECT_DECLARE_GETTER(ei_connection, id, uint32_t);
OBJECT_DECLARE_GETTER(ei_connection, proto_object, const struct brei_object*);
OBJECT_DECLARE_GETTER(ei_connection, interface, const struct ei_connection_interface *);
OBJECT_DECLARE_REF(ei_connection);
OBJECT_DECLARE_UNREF(ei_connection);
struct ei_connection *
ei_connection_new(struct ei *ei);
ei_connection_new(struct ei *ei, uint32_t id, uint32_t version);
/**
* Called when the ei_callback.done event is received after

View file

@ -63,6 +63,7 @@ struct ei {
struct object object;
struct ei_connection *connection;
struct ei_connection_setup *connection_setup;
struct list proto_objects; /* brei_object list */
uint32_t next_object_id;
@ -117,6 +118,12 @@ ei_send_message(struct ei *ei, const struct brei_object *object,
void
ei_add_seat(struct ei_seat *seat);
void
ei_connected(struct ei *ei);
void
ei_queue_connect_event(struct ei *ei);
void
ei_queue_device_removed_event(struct ei_device *device);

View file

@ -62,6 +62,7 @@ ei_destroy(struct ei *ei)
if (ei->backend_interface.destroy)
ei->backend_interface.destroy(ei, ei->backend);
ei->backend = NULL;
ei_connection_setup_unref(ei->connection_setup);
ei_connection_unref(ei->connection);
sink_unref(ei->sink);
free(ei->name);
@ -98,7 +99,7 @@ ei_create_context(bool is_sender, void *user_data)
list_init(&ei->seats);
list_init(&ei->proto_objects);
ei->connection = ei_connection_new(ei);
ei->connection_setup = ei_connection_setup_new(ei, VERSION_V(1));
ei->next_object_id = 1;
ei_log_set_handler(ei, NULL);
@ -259,8 +260,8 @@ insert_event(struct ei *ei, struct ei_event *event)
}
static void
queue_connect_event(struct ei *ei)
void
ei_queue_connect_event(struct ei *ei)
{
struct ei_event *e = ei_event_new(ei);
e->type = EI_EVENT_CONNECT;
@ -580,9 +581,13 @@ static int
handle_msg_seat(struct ei_connection *connection, uint32_t seat_id, uint32_t version)
{
struct ei *ei = ei_connection_get_context(connection);
struct ei_seat *seat = ei_seat_new(ei, seat_id, version);
/* We might get the seat event before our callback finished, so make sure
* we know we're connected
*/
ei_connected(ei);
/* seats list owns the ref */
list_append(&ei->seats, &seat->link);
@ -629,6 +634,15 @@ ei_peek_event(struct ei *ei)
return ei_event_ref(e);
}
void
ei_connected(struct ei *ei)
{
if (ei->state == EI_STATE_CONNECTING) {
ei->state = EI_STATE_CONNECTED;
ei_queue_connect_event(ei);
}
}
static int handle_msg_disconnected(struct ei_connection *connection, uint32_t reason, const char *explanation)
{
struct ei *ei = ei_connection_get_context(connection);
@ -648,80 +662,15 @@ static int handle_msg_disconnected(struct ei_connection *connection, uint32_t re
} \
} while(0)
static void
connected(struct ei_connection *connection, void *user_data)
{
struct ei *ei = ei_connection_get_context(connection);
/* 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);
if (version >= EI_CONNECTION_SETUP_REQUEST_INTERFACE_SINCE_VERSION) {
ei_connection_setup_request_interface(setup, "ei_connection", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_callback", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_seat", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_device", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_pointer", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_keyboard", VERSION_V(1));
ei_connection_setup_request_interface(setup, "ei_touchscreen", VERSION_V(1));
}
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 const struct ei_connection_interface intf_state_backend = {
.connection_setup = handle_msg_connection_setup,
/* Everything triggers -EPROTO */
};
static const struct ei_connection_interface intf_state_connecting = {
.connection_setup = handle_msg_connection_setup,
.disconnected = handle_msg_disconnected,
};
static const struct ei_connection_interface intf_state_connected = {
.connection_setup = NULL, /* EPROTO */
static const struct ei_connection_interface interface = {
.disconnected = handle_msg_disconnected,
.seat = handle_msg_seat,
};
static const struct ei_connection_interface *interfaces[] = {
[EI_STATE_NEW] = NULL,
[EI_STATE_BACKEND] = &intf_state_backend,
[EI_STATE_CONNECTING] = &intf_state_connecting,
[EI_STATE_CONNECTED] = &intf_state_connected,
[EI_STATE_DISCONNECTING] = NULL,
[EI_STATE_DISCONNECTED] = NULL,
};
const struct ei_connection_interface *
ei_get_interface(struct ei *ei)
{
assert(ei->state < ARRAY_LENGTH(interfaces));
return interfaces[ei->state];
return &interface;
}
static int
@ -803,8 +752,9 @@ ei_set_socket(struct ei *ei, int fd)
ei->source = source_ref(source);
ei->state = EI_STATE_BACKEND;
/* The server SHOULD have already sent the connection setup, let's
* process that. If not ready, it'll happen in the next dispatch.
/* The server SHOULD have already sent the connection setup
* version, let's process that. If not ready, it'll happen
* in the next dispatch.
*
* FIXME: this will block if O_NONBLOCK is missing
*/

View file

@ -163,14 +163,6 @@ eis_client_send_message(struct eis_client *client, const struct brei_object *obj
return rc < 0 ? rc : 0;
}
static int
client_send_connection_setup(struct eis_client *client, struct eis_connection_setup *setup)
{
return eis_connection_event_connection_setup(client->connection,
eis_connection_setup_get_id(setup),
eis_connection_setup_get_version(setup));
}
static int
client_send_disconnect(struct eis_client *client, const char *reason)
{
@ -382,9 +374,6 @@ eis_client_new(struct eis *eis, int fd)
.ei_keyboard = VERSION_V(1),
.ei_touchscreen = VERSION_V(1),
};
client->connection = eis_connection_new(client);
struct source *s = source_new(fd, client_dispatch, client);
int rc = sink_add_source(eis->sink, s);
@ -405,11 +394,7 @@ eis_client_new(struct eis *eis, int fd)
source_unref(s);
/* 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->interface_versions);
client_send_connection_setup(client, setup);
client->setup = setup;
client->setup = eis_connection_setup_new(client, &client->interface_versions);
return client;
}

View file

@ -86,6 +86,10 @@ client_msg_done(struct eis_connection_setup *setup)
rc = 0;
}
client->connection = eis_connection_new(client);
eis_connection_setup_event_connection(setup, eis_connection_get_id(client->connection),
eis_connection_get_version(client->connection));
eis_connection_setup_unref(setup);
return rc;
@ -175,21 +179,23 @@ eis_connection_setup_get_interface(struct eis_connection_setup *setup) {
}
struct eis_connection_setup *
eis_connection_setup_new(struct eis_client *client, uint32_t new_id,
eis_connection_setup_new(struct eis_client *client,
const struct eis_client_interface_versions *versions)
{
struct eis_connection_setup *setup = eis_connection_setup_create(&client->object);
setup->proto_object.id = new_id;
setup->proto_object.id = 0;
setup->proto_object.implementation = setup;
setup->proto_object.interface = &eis_connection_setup_proto_interface;
setup->proto_object.version = versions->ei_connection_setup;
/* This object is always v1 until the client tells us otherwise */
setup->proto_object.version = VERSION_V(1);
list_init(&setup->proto_object.link);
setup->version = VERSION_V(1); /* our ei-connection-setup version */
setup->server_versions = *versions;
eis_client_register_object(client, &setup->proto_object);
eis_connection_setup_event_version(setup, versions->ei_connection_setup);
return setup; /* ref owned by caller */
}

View file

@ -55,5 +55,5 @@ 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,
eis_connection_setup_new(struct eis_client *client,
const struct eis_client_interface_versions *versions);

View file

@ -53,6 +53,18 @@ OBJECT_IMPLEMENT_CREATE(eis_connection);
static
OBJECT_IMPLEMENT_PARENT(eis_connection, eis_client);
uint32_t
eis_connection_get_version(struct eis_connection *connection)
{
return connection->proto_object.version;
}
uint32_t
eis_connection_get_id(struct eis_connection *connection)
{
return connection->proto_object.id;
}
struct eis_client*
eis_connection_get_client(struct eis_connection *connection)
{
@ -80,7 +92,7 @@ eis_connection_new(struct eis_client *client)
connection->proto_object.id = eis_client_get_new_id(client);
connection->proto_object.implementation = connection;
connection->proto_object.interface = &eis_connection_proto_interface;
connection->proto_object.version = VERSION_V(1);
connection->proto_object.version = client->interface_versions.ei_connection;
eis_client_register_object(client, &connection->proto_object);
return connection; /* ref owned by caller */

View file

@ -38,6 +38,8 @@ struct eis_connection {
};
OBJECT_DECLARE_GETTER(eis_connection, context, struct eis *);
OBJECT_DECLARE_GETTER(eis_connection, id, uint32_t);
OBJECT_DECLARE_GETTER(eis_connection, version, uint32_t);
OBJECT_DECLARE_GETTER(eis_connection, client, struct eis_client *);
OBJECT_DECLARE_GETTER(eis_connection, proto_object, const struct brei_object *);
OBJECT_DECLARE_GETTER(eis_connection, interface, const struct eis_connection_interface *);