Merge lp:~alan-griffiths/mir/fix-1486496 into lp:mir
- fix-1486496
- Merge into development-branch
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 |
Related bugs: |
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2873
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2874
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2875
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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_
Otherwise sensible.
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_
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.
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2877
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2878
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
The hang in mir_performance test is because this...
Get:3 http://
... 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+
Preview Diff
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; |
FAILED: Continuous integration, rev:2872 jenkins. qa.ubuntu. com/job/ mir-ci/ 4645/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/3629 s-jenkins. ubuntu- ci:8080/ job/mir- clang-ts- vivid-amd64- build/50/ console jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/2540 jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/3579/ console jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 794/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 3579 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 3579/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/6348/ console s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 22753
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/4645/ rebuild
http://