Mir

Merge lp:~alan-griffiths/mir/fix-1486496 into lp:mir

Proposed by Alan Griffiths
Status: Superseded
Proposed branch: lp:~alan-griffiths/mir/fix-1486496
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/simplify-connect-code
Diff against target: 283 lines (+136/-7)
9 files modified
src/client/mir_connection.cpp (+1/-1)
src/client/rpc/mir_basic_rpc_channel.cpp (+24/-2)
src/client/rpc/mir_basic_rpc_channel.h (+1/-0)
src/include/common/mir/frontend/client_constants.h (+3/-1)
src/include/common/mir/protobuf/protocol_version.h (+48/-0)
src/server/frontend/socket_connection.cpp (+8/-1)
tests/acceptance-tests/test_client_library.cpp (+48/-0)
tests/integration-tests/test_error_reporting.cpp (+1/-1)
tests/unit-tests/frontend/test_socket_connection.cpp (+2/-1)
To merge this branch: bzr merge lp:~alan-griffiths/mir/fix-1486496
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Alan Griffiths Abstain
Chris Halse Rogers Needs Fixing
Review via email: mp+268747@code.launchpad.net

Commit message

client, frontend: Introduce meaningful versioning into the protobuf protocol and check it.

Description of the change

client, frontend: Introduce meaningful versioning into the protobuf protocol and check it.

Because the server simply disconnects on a connection failure the client doesn't receive any reason for the failure. However, reporting a connection failure is better than hanging.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

126 +// Client libraries older than last ABI break may make calls we can't understand

This seems to be an extremely conservative choice, which will likely prevent many clients which would otherwise work fine from connecting. We remove protocol extremely rarely; the last protocol we removed had been deprecated for 2 years.

I don't think it's unreasonable to manually populate the oldest_compatible_protocol_version().

Otherwise sensible.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> 126 +// Client libraries older than last ABI break may make calls we can't
> understand
>
> This seems to be an extremely conservative choice, which will likely prevent
> many clients which would otherwise work fine from connecting. We remove
> protocol extremely rarely; the last protocol we removed had been deprecated
> for 2 years.

If you investigate the linked bug you'll find that this choice is actually correct as things stand on trunk.

I don't think it is *yet* worth spending the effort to ensure current libmirclient can interwork with old libmirserver versions. (There is no likelihood of Mir servers based on different libmirservers being installed side-by-side on a user system.)

> I don't think it's unreasonable to manually populate the
> oldest_compatible_protocol_version().

I think being conservative is a good default.

Next time we bump the major API version number we can consider if we can be less conservative. I hope after all the "opaquification" and deprecation that landed in 0.14 that this will be a very long time.

> Otherwise sensible.

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Oops!

review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

After attempting to reproduce locally and chatting with kdub on IRC it looks like the CI failure (hang in glmark) is related to lp:1441553.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

The hang in mir_performance test is because this...

Get:3 http://ports.ubuntu.com/ubuntu-ports/ vivid/universe glmark2-es2-mir armhf 2014.03-0ubuntu3 [298 kB]

... is the libmirclient.so.8 based version from vivid. *Not* the libmirclient.so.9 based rebuild from the "Stable Phone Overlay PPA".

(That is version 2014.03+git20150611.fa71af2d-0ubuntu1.1~overlay1)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/client/mir_connection.cpp'
2--- src/client/mir_connection.cpp 2015-08-21 11:36:32 +0000
3+++ src/client/mir_connection.cpp 2015-08-25 15:45:40 +0000
4@@ -165,7 +165,7 @@
5 {
6 std::lock_guard<decltype(mutex)> lock(mutex);
7
8- if (connect_result && connect_result->has_error())
9+ if (error_message.empty() && connect_result)
10 {
11 return connect_result->error().c_str();
12 }
13
14=== modified file 'src/client/rpc/mir_basic_rpc_channel.cpp'
15--- src/client/rpc/mir_basic_rpc_channel.cpp 2015-07-29 01:39:52 +0000
16+++ src/client/rpc/mir_basic_rpc_channel.cpp 2015-08-25 15:45:40 +0000
17@@ -23,12 +23,33 @@
18 #include "mir_protobuf_wire.pb.h"
19 #include "mir/frontend/client_constants.h"
20 #include "mir/variable_length_array.h"
21+#include "mir/protobuf/protocol_version.h"
22+#include "mir/log.h"
23
24 #include <sstream>
25
26 namespace mclr = mir::client::rpc;
27 namespace mclrd = mir::client::rpc::detail;
28
29+namespace
30+{
31+int get_protocol_version()
32+{
33+ auto protocol_version = mir::protobuf::current_protocol_version();
34+
35+ if (auto const protocol_version_override = getenv("MIR_CLIENT_TEST_OVERRRIDE_PROTOCOL_VERSION"))
36+ {
37+ int const new_protcol_version = strtol(protocol_version_override, nullptr, 0);
38+ mir::log(mir::logging::Severity::warning, MIR_LOG_COMPONENT,
39+ "Overriding protocol version 0x%x with 0x%x", protocol_version, new_protcol_version);
40+
41+ protocol_version = new_protcol_version;
42+ }
43+
44+ return protocol_version;
45+}
46+}
47+
48 mclrd::PendingCallCache::PendingCallCache(
49 std::shared_ptr<RpcReport> const& rpc_report)
50 : rpc_report{rpc_report}
51@@ -99,7 +120,8 @@
52
53
54 mclr::MirBasicRpcChannel::MirBasicRpcChannel() :
55- next_message_id(0)
56+ next_message_id(0),
57+ protocol_version{get_protocol_version()}
58 {
59 }
60
61@@ -120,7 +142,7 @@
62 invoke.set_id(next_id());
63 invoke.set_method_name(method_name);
64 invoke.set_parameters(buffer.data(), buffer.size());
65- invoke.set_protocol_version(1);
66+ invoke.set_protocol_version(protocol_version);
67 invoke.set_side_channel_fds(num_side_channel_fds);
68
69 return invoke;
70
71=== modified file 'src/client/rpc/mir_basic_rpc_channel.h'
72--- src/client/rpc/mir_basic_rpc_channel.h 2015-07-29 01:39:52 +0000
73+++ src/client/rpc/mir_basic_rpc_channel.h 2015-08-25 15:45:40 +0000
74@@ -118,6 +118,7 @@
75
76 private:
77 std::atomic<int> next_message_id;
78+ int const protocol_version;
79 };
80
81 }
82
83=== modified file 'src/include/common/mir/frontend/client_constants.h'
84--- src/include/common/mir/frontend/client_constants.h 2015-02-22 07:46:25 +0000
85+++ src/include/common/mir/frontend/client_constants.h 2015-08-25 15:45:40 +0000
86@@ -27,7 +27,9 @@
87 /// Number of buffers the client library will keep.
88
89 /// mir::client::ClientBufferDepository and mir::frontend::ClientBufferTracker need to use the same value
90-unsigned int const client_buffer_cache_size = 3;
91+// TODO this ought to be 3 - but is 4 as a workaround for issues with overallocation (lp:1441553)
92+// (this should become moot with "new Buffer Semantics")
93+unsigned int const client_buffer_cache_size = 4;
94
95 /// Buffers need to be big enough to support messages
96 unsigned int const serialization_buffer_size = 2048;
97
98=== added file 'src/include/common/mir/protobuf/protocol_version.h'
99--- src/include/common/mir/protobuf/protocol_version.h 1970-01-01 00:00:00 +0000
100+++ src/include/common/mir/protobuf/protocol_version.h 2015-08-25 15:45:40 +0000
101@@ -0,0 +1,48 @@
102+/*
103+ * Copyright © 2015 Canonical Ltd.
104+ *
105+ * This program is free software: you can redistribute it and/or modify it
106+ * under the terms of the GNU Lesser General Public License version 3,
107+ * as published by the Free Software Foundation.
108+ *
109+ * This program is distributed in the hope that it will be useful,
110+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
112+ * GNU Lesser General Public License for more details.
113+ *
114+ * You should have received a copy of the GNU Lesser General Public License
115+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
116+ *
117+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
118+ */
119+
120+#ifndef MIR_PROTOBUF_PROTOCOL_VERSION_H
121+#define MIR_PROTOBUF_PROTOCOL_VERSION_H
122+
123+#include "mir_toolkit/version.h"
124+
125+namespace mir
126+{
127+namespace protobuf
128+{
129+inline constexpr int protocol_version(int major, int minor)
130+{
131+ return (major << 10) + minor;
132+}
133+
134+// For the present we use the client API protocol_version as a proxy for the protocol
135+// protocol_version as the protocol is typically updated to support API changes.
136+inline constexpr int current_protocol_version()
137+{
138+ return protocol_version(MIR_CLIENT_MAJOR_VERSION, MIR_CLIENT_MINOR_VERSION);
139+}
140+
141+// Client libraries older than last ABI break may make calls we can't understand
142+inline constexpr int oldest_compatible_protocol_version()
143+{
144+ return protocol_version(MIR_CLIENT_MAJOR_VERSION, 0);
145+}
146+}
147+}
148+
149+#endif //MIR_PROTOBUF_PROTOCOL_VERSION_H
150
151=== modified file 'src/server/frontend/socket_connection.cpp'
152--- src/server/frontend/socket_connection.cpp 2015-02-22 07:46:25 +0000
153+++ src/server/frontend/socket_connection.cpp 2015-08-25 15:45:40 +0000
154@@ -21,6 +21,7 @@
155 #include "message_receiver.h"
156 #include "mir/frontend/message_processor.h"
157 #include "mir/frontend/session_credentials.h"
158+#include "mir/protobuf/protocol_version.h"
159
160 #include "mir_protobuf_wire.pb.h"
161
162@@ -90,6 +91,10 @@
163 void mfd::SocketConnection::on_new_message(const boost::system::error_code& error)
164 try
165 {
166+ // No support for newer client libraries
167+ static auto const forward_compatibility_limit = mir::protobuf::current_protocol_version();
168+ static auto const backward_compatibility_limit = mir::protobuf::oldest_compatible_protocol_version();
169+
170 if (error)
171 {
172 BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
173@@ -98,7 +103,9 @@
174 mir::protobuf::wire::Invocation invocation;
175 invocation.ParseFromArray(body.data(), body.size());
176
177- if (!invocation.has_protocol_version() || invocation.protocol_version() != 1)
178+ if (!invocation.has_protocol_version() ||
179+ invocation.protocol_version() > forward_compatibility_limit ||
180+ invocation.protocol_version() < backward_compatibility_limit)
181 BOOST_THROW_EXCEPTION(std::runtime_error("Unsupported protocol version"));
182
183 std::vector<mir::Fd> fds;
184
185=== modified file 'tests/acceptance-tests/test_client_library.cpp'
186--- tests/acceptance-tests/test_client_library.cpp 2015-07-27 07:24:50 +0000
187+++ tests/acceptance-tests/test_client_library.cpp 2015-08-25 15:45:40 +0000
188@@ -136,6 +136,8 @@
189
190 mtf::UsingStubClientPlatform using_stub_client_platform;
191 };
192+
193+auto const* const protocol_version_override = "MIR_CLIENT_TEST_OVERRRIDE_PROTOCOL_VERSION";
194 }
195
196 using namespace testing;
197@@ -164,6 +166,52 @@
198 mir_connection_release(connection);
199 }
200
201+TEST_F(ClientLibrary, connects_when_protobuf_protocol_oldest_supported)
202+{
203+ std::ostringstream buffer;
204+ buffer << ((MIR_CLIENT_MAJOR_VERSION) << 10);
205+
206+ add_to_environment(protocol_version_override, buffer.str().c_str());
207+
208+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
209+
210+ EXPECT_THAT(connection, NotNull());
211+ EXPECT_TRUE(mir_connection_is_valid(connection));
212+ EXPECT_THAT(mir_connection_get_error_message(connection), StrEq(""));
213+
214+ mir_connection_release(connection);
215+}
216+
217+TEST_F(ClientLibrary, reports_error_when_protobuf_protocol_obsolete)
218+{
219+ std::ostringstream buffer;
220+ buffer << ((MIR_CLIENT_MAJOR_VERSION-1) << 10);
221+ add_to_environment(protocol_version_override, buffer.str().c_str());
222+
223+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
224+
225+ EXPECT_THAT(connection, NotNull());
226+ EXPECT_FALSE(mir_connection_is_valid(connection));
227+ EXPECT_THAT(mir_connection_get_error_message(connection), StrEq("Connect failed"));
228+
229+ mir_connection_release(connection);
230+}
231+
232+TEST_F(ClientLibrary, reports_error_when_protobuf_protocol_too_new)
233+{
234+ std::ostringstream buffer;
235+ buffer << ((MIR_CLIENT_MAJOR_VERSION) << 10) + MIR_CLIENT_MINOR_VERSION+1;
236+ add_to_environment(protocol_version_override, buffer.str().c_str());
237+
238+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
239+
240+ EXPECT_THAT(connection, NotNull());
241+ EXPECT_FALSE(mir_connection_is_valid(connection));
242+ EXPECT_THAT(mir_connection_get_error_message(connection), StrEq("Connect failed"));
243+
244+ mir_connection_release(connection);
245+}
246+
247 TEST_F(ClientLibrary, creates_surface)
248 {
249 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
250
251=== modified file 'tests/integration-tests/test_error_reporting.cpp'
252--- tests/integration-tests/test_error_reporting.cpp 2015-07-29 01:18:29 +0000
253+++ tests/integration-tests/test_error_reporting.cpp 2015-08-25 15:45:40 +0000
254@@ -100,7 +100,7 @@
255
256 ASSERT_TRUE(connection != NULL);
257 EXPECT_FALSE(mir_connection_is_valid(connection));
258- EXPECT_THAT(mir_connection_get_error_message(connection), testing::HasSubstr(test_exception_text));
259+ EXPECT_THAT(mir_connection_get_error_message(connection), testing::HasSubstr("Connect failed"));
260
261 mir_connection_release(connection);
262 }
263
264=== modified file 'tests/unit-tests/frontend/test_socket_connection.cpp'
265--- tests/unit-tests/frontend/test_socket_connection.cpp 2015-06-25 03:00:08 +0000
266+++ tests/unit-tests/frontend/test_socket_connection.cpp 2015-08-25 15:45:40 +0000
267@@ -22,6 +22,7 @@
268 #include "mir/frontend/message_processor.h"
269 #include "mir/frontend/session_credentials.h"
270 #include "mir/fd.h"
271+#include "mir/protobuf/protocol_version.h"
272
273 #include "mir/test/fake_shared.h"
274
275@@ -145,7 +146,7 @@
276 invocation.set_id(1);
277 invocation.set_method_name("");
278 invocation.set_parameters(buffer, 0);
279- invocation.set_protocol_version(1);
280+ invocation.set_protocol_version(mir::protobuf::current_protocol_version());
281 invocation.set_side_channel_fds(2);
282 auto const body_size = invocation.ByteSize();
283 buffer[0] = body_size / 0x100;

Subscribers

People subscribed via source and target branches