diff --git a/proto/protocol.xml b/proto/protocol.xml
index 58bf630..e3c21f8 100644
--- a/proto/protocol.xml
+++ b/proto/protocol.xml
@@ -101,11 +101,13 @@
In summary, a typical client connection does:
- connect to the socket
- - read ei_handshake.version for object id 0
- - send ei_handshake.interface for "ei_connection"
- - send ei_handshake.interface for all other supported interfaces
+ - read ei_handshake.handshake_version for object id 0
+ - send ei_handshake.handshake_version for object id 0
+ - send ei_handshake.interface_version for all other supported interfaces
- optionally: send ei_handshake.name and ei_handshake.context_type
- send ei_handshake.finish
+ - send ei_handshake.finish
+ - optionally: receive ei_handshake.interface_version for named interfaces
- receive the ei_connection.connection event and create that object
- receive ei_connection.seat (if any seats are available)
- ....
@@ -149,6 +151,24 @@
+
+
+ Notifies the EIS implementation that this client supports the
+ given version of the ei_handshake interface. The version number
+ must be less than or equal to the version in the
+ handshake_version event sent by the EIS implementation when
+ the connection was established.
+
+ Immediately after sending this request, the client must assume the negotiated
+ version number for the ei_handshake interface and the EIS implementation
+ may send events and process requests matching that version.
+
+ This request must be sent exactly once and it must be the first request
+ the client sends.
+
+
+
+
Notify the EIS implementation that configuration is complete.
@@ -218,12 +238,8 @@
failing to do so will result in the EIS implementation disconnecting
the client on ei_handshake.finish.
- If the "ei_handshake" version is given, the interface of this
- object is upgraded to the given version. Otherwise, the
- ei_handshake version defaults to 1.
-
- A client must not provide a "ei_handshake" version higher
- than the EIS implementation sent immediately after connection.
+ This request must not be sent for the "ei_handshake" interface, use
+ the handshake_version request instead.
Note that an EIS implementation may consider some interfaces to
be required and immediately ei_connection.disconnect a client
@@ -237,33 +253,32 @@
+
+
+ This event is sent exactly once and immediately after connection
+ to the EIS implementation.
+
+ In response, the client must send the handshake_version request
+ with any version up to including the version provided in this event.
+ See the handshake_version request for details on what happens next.
+
+
+
Notifies the client that the EIS implementation supports
the given named interface with the given maximum version number.
- This event is sent immediately after connection to the EIS implementation
- for the "ei_handshake" interface. In response, the client may
- send the interface_version request for the "ei_handshake" interface
- with any version up to including the version provided in that event.
- Once the request has been sent, the client must assume the negotiated
- version number for the ei_handshake interface and the server
- may send events and process requests matching that version.
-
- A client should not issue any requests until negotiating the version for
- the "ei_handshake" interface.
-
- Note that the EIS implementation assumes that the supported
- client version of the "ei_handshake" interface is 1 unless and
- until the client announces a higher version of this interface in the
- ei_handshake.interface_version request.
-
This event must be sent by the EIS implementation for any
- interfaces that supports client-created objects (e.g. "ei_callback").
+ interfaces that supports client-created objects (e.g. "ei_callback")
+ before the ei_handshake.connection event.
The client must not assume those interfaces are supported unless
and until those versions have been received.
+ This request must not be sent for the "ei_handshake" interface, use
+ the handshake_version event instead.
+
This event may be sent by the EIS implementation for any
other supported interface (but not necessarily all supported
interfaces) before the ei_handshake.connection event.
diff --git a/src/libei-handshake.c b/src/libei-handshake.c
index 46b6bff..833d7d1 100644
--- a/src/libei-handshake.c
+++ b/src/libei-handshake.c
@@ -72,6 +72,9 @@ static int
ei_handshake_initialize(struct ei_handshake *setup, uint32_t version)
{
struct ei *ei = ei_handshake_get_context(setup);
+ struct ei_interface_versions *v = &ei->interface_versions;
+
+ ei_handshake_request_handshake_version(setup, v->ei_handshake);
if (version >= EI_HANDSHAKE_REQUEST_CONTEXT_TYPE_SINCE_VERSION)
ei_handshake_request_context_type(setup,
@@ -83,8 +86,6 @@ ei_handshake_initialize(struct ei_handshake *setup, uint32_t version)
ei_handshake_request_name(setup, ei->name);
if (version >= EI_HANDSHAKE_REQUEST_INTERFACE_VERSION_SINCE_VERSION) {
- struct ei_interface_versions *v = &ei->interface_versions;
- ei_handshake_request_interface_version(setup, "ei_handshake", v->ei_handshake);
ei_handshake_request_interface_version(setup, "ei_connection", v->ei_connection);
ei_handshake_request_interface_version(setup, "ei_callback", v->ei_callback);
ei_handshake_request_interface_version(setup, "ei_pingpong", v->ei_pingpong);
@@ -100,6 +101,24 @@ ei_handshake_initialize(struct ei_handshake *setup, uint32_t version)
return 0;
}
+static struct brei_result *
+handle_msg_handshake_version(struct ei_handshake *setup, uint32_t version)
+{
+ struct ei *ei = ei_handshake_get_context(setup);
+ struct ei_interface_versions *v = &ei->interface_versions;
+
+ uint32_t min_version = min(version, ei->interface_versions.ei_handshake);
+ v->ei_handshake = min_version;
+
+ /* Now upgrade our protocol object to the server version (if applicable) */
+ setup->proto_object.version = min_version;
+
+ /* Now send all the bits we need to send */
+ ei_handshake_initialize(setup, min_version);
+
+ return NULL;
+}
+
static struct brei_result *
handle_msg_interface_version(struct ei_handshake *setup, const char *name, uint32_t version)
{
@@ -107,14 +126,7 @@ handle_msg_interface_version(struct ei_handshake *setup, const char *name, uint3
struct ei_interface_versions *v = &ei->interface_versions;
if (streq(name, "ei_handshake")) {
- uint32_t min_version = min(version, ei->interface_versions.ei_handshake);
- v->ei_handshake = min_version;
-
- /* Now upgrade our protocol object to the server version (if applicable) */
- setup->proto_object.version = min_version;
-
- /* Now send all the bits we need to send */
- ei_handshake_initialize(setup, min_version);
+ /* EIS shouldn't send this anyway, let's ignore this */
}
#define VERSION_UPDATE(iface_) if (streq(name, #iface_)) v->iface_ = min(version, v->iface_);
else VERSION_UPDATE(ei_connection)
@@ -164,6 +176,7 @@ handle_msg_connection(struct ei_handshake *setup, uint32_t serial, uint32_t id,
}
static const struct ei_handshake_interface interface = {
+ .handshake_version = handle_msg_handshake_version,
.interface_version = handle_msg_interface_version,
.connection = handle_msg_connection,
};
diff --git a/src/libeis-handshake.c b/src/libeis-handshake.c
index 4021c2f..d6ee91a 100644
--- a/src/libeis-handshake.c
+++ b/src/libeis-handshake.c
@@ -82,13 +82,37 @@ pong(struct eis_connection *connection, void *user_data)
eis_queue_connect_event(client);
}
+static struct brei_result*
+client_msg_handshake_version(struct eis_handshake *setup, uint32_t version)
+{
+ struct eis_client *client = eis_handshake_get_client(setup);
+ struct eis *eis = eis_client_get_context(client);
+
+ log_debug(eis, "client %#x supports handshake version %u", client->id, version);
+
+ if (version == 0)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_VALUE, "Invalid handshake version %u", version);
+
+ if (setup->client_versions.ei_handshake != 0)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "Duplicate handshake version");
+ if (version > setup->server_versions.ei_handshake)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "Invalid handshake version %ud", version);
+
+ setup->client_versions.ei_handshake = min(setup->server_versions.ei_handshake, version);
+
+ return 0;
+}
+
static struct brei_result *
client_msg_finish(struct eis_handshake *setup)
{
struct eis_client *client = eis_handshake_get_client(setup);
/* Required interfaces - immediate disconnection if missing */
- if (setup->client_versions.ei_connection == 0 ||
+ if (setup->client_versions.ei_handshake == 0 ||
+ setup->client_versions.ei_connection == 0 ||
setup->client_versions.ei_callback == 0 ||
setup->client_versions.ei_pingpong == 0)
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
@@ -126,6 +150,10 @@ client_msg_finish(struct eis_handshake *setup)
static struct brei_result *
client_msg_name(struct eis_handshake *setup, const char *name)
{
+ if (setup->client_versions.ei_handshake == 0)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "Missing handshake versions");
+
if (setup->name)
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL, "Duplicate client name");
@@ -137,6 +165,10 @@ client_msg_name(struct eis_handshake *setup, const char *name)
static struct brei_result *
client_msg_context_type(struct eis_handshake *setup, uint32_t type)
{
+ if (setup->client_versions.ei_handshake == 0)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "Missing handshake versions");
+
switch(type) {
case EIS_HANDSHAKE_CONTEXT_TYPE_SENDER:
setup->is_sender = true;
@@ -152,6 +184,14 @@ client_msg_context_type(struct eis_handshake *setup, uint32_t type)
static struct brei_result *
client_msg_interface_version(struct eis_handshake *setup, const char *name, uint32_t version)
{
+ if (setup->client_versions.ei_handshake == 0)
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "Missing handshake versions");
+
+ if (streq(name, "ei_handshake"))
+ return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
+ "ei_handshake may not be used in interface_version");
+
struct eis_client *client = eis_handshake_get_client(setup);
struct eis *eis = eis_client_get_context(client);
struct v {
@@ -167,7 +207,7 @@ client_msg_interface_version(struct eis_handshake *setup, const char *name, uint
VERSION_ENTRY(ei_callback),
VERSION_ENTRY(ei_pingpong),
VERSION_ENTRY(ei_connection),
- VERSION_ENTRY(ei_handshake),
+ /* ei_handshake is not handled here */
VERSION_ENTRY(ei_seat),
VERSION_ENTRY(ei_device),
VERSION_ENTRY(ei_pointer),
@@ -199,6 +239,7 @@ client_msg_interface_version(struct eis_handshake *setup, const char *name, uint
}
static const struct eis_handshake_interface interface = {
+ .handshake_version = client_msg_handshake_version,
.finish = client_msg_finish,
.context_type = client_msg_context_type,
.name = client_msg_name,
@@ -227,7 +268,7 @@ eis_handshake_new(struct eis_client *client,
setup->server_versions = *versions;
eis_client_register_object(client, &setup->proto_object);
- eis_handshake_event_interface_version(setup, "ei_handshake", versions->ei_handshake);
+ eis_handshake_event_handshake_version(setup, versions->ei_handshake);
return setup; /* ref owned by caller */
}
diff --git a/test/test_protocol.py b/test/test_protocol.py
index 6c39860..15e7979 100644
--- a/test/test_protocol.py
+++ b/test/test_protocol.py
@@ -158,6 +158,7 @@ class Ei:
def init_default_sender_connection(self) -> None:
setup = self.handshake
+ self.send(setup.HandshakeVersion(VERSION_V(1)))
self.send(setup.ContextType(EiHandshake.EiContextType.SENDER))
self.send(setup.Name("test client"))
self.send(
@@ -359,8 +360,7 @@ class TestEiProtocol:
ei.wait_for(lambda: bool(setup.calllog))
call = setup.calllog[0]
- assert call.name == "InterfaceVersion"
- assert call.args["name"] == "ei_handshake"
+ assert call.name == "HandshakeVersion"
assert call.args["version"] == VERSION_V(1)
eis.terminate()
@@ -406,6 +406,7 @@ class TestEiProtocol:
except ValueError:
pass
+ ei.send(ei.handshake.HandshakeVersion(VERSION_V(1)))
ei.send(ei.handshake.ContextType(invalid_type))
try:
@@ -503,6 +504,7 @@ class TestEiProtocol:
setup = ei.handshake
# Establish our connection
+ ei.send(setup.HandshakeVersion(VERSION_V(1)))
ei.send(setup.ContextType(EiHandshake.EiContextType.SENDER))
ei.send(setup.Name("test client"))
for interface in ["ei_connection", "ei_callback", "ei_pingpong"]:
@@ -563,6 +565,7 @@ class TestEiProtocol:
setup = ei.handshake
# Establish our connection
+ ei.send(setup.HandshakeVersion(VERSION_V(1)))
ei.send(setup.ContextType(EiHandshake.EiContextType.SENDER))
ei.send(setup.Name("test client"))
for interface in ["ei_connection", "ei_callback", "ei_pingpong"]:
@@ -735,6 +738,7 @@ class TestEiProtocol:
ei.dispatch()
setup = ei.handshake
+ ei.send(setup.HandshakeVersion(VERSION_V(1)))
ei.send(setup.ContextType(EiHandshake.EiContextType.SENDER))
ei.send(setup.Name("test client"))