Merge lp:~thomas-voss/trust-store/watch-service-name-owner-changes into lp:trust-store/15.04
- watch-service-name-owner-changes
- Merge into 15.04
Status: | Needs review |
---|---|
Proposed branch: | lp:~thomas-voss/trust-store/watch-service-name-owner-changes |
Merge into: | lp:trust-store/15.04 |
Diff against target: |
846 lines (+368/-186) 10 files modified
src/CMakeLists.txt (+3/-0) src/core/trust/daemon.cpp (+18/-92) src/core/trust/dbus/agent_registry.h (+54/-5) src/core/trust/remote/dbus.cpp (+21/-9) src/core/trust/remote/dbus.h (+8/-2) src/core/trust/runtime.cpp (+105/-0) src/core/trust/runtime.h (+88/-0) tests/CMakeLists.txt (+3/-0) tests/dbus_test.cpp (+4/-6) tests/remote_agent_test.cpp (+64/-72) |
To merge this branch: | bzr merge lp:~thomas-voss/trust-store/watch-service-name-owner-changes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+281483@code.launchpad.net |
This proposal supersedes a proposal from 2016-01-03.
Commit message
core::trust:
asynchronously if a new name owner is detected.
Description of the change
core::trust:
asynchronously if a new name owner is detected.
- 138. By Thomas Voß
-
Make core::trust:
:Runtime a proper class and do not expose its internals anymore. - 139. By Thomas Voß
-
Address a few minor niggles regarding object lifetimes and noexcept(true) guarantees.
- 140. By Thomas Voß
-
Wait a little longer to account for slow builders.
- 141. By Thomas Voß
-
Link correct bug report.
Unmerged revisions
- 141. By Thomas Voß
-
Link correct bug report.
- 140. By Thomas Voß
-
Wait a little longer to account for slow builders.
- 139. By Thomas Voß
-
Address a few minor niggles regarding object lifetimes and noexcept(true) guarantees.
- 138. By Thomas Voß
-
Make core::trust:
:Runtime a proper class and do not expose its internals anymore. - 137. By Thomas Voß
-
core::trust:
:dbus:: Agent:: Skeleton now watches for name owner changes, announcing itself
asynchronously if a new name owner is detected.
Preview Diff
1 | === modified file 'src/CMakeLists.txt' |
2 | --- src/CMakeLists.txt 2015-08-31 13:16:20 +0000 |
3 | +++ src/CMakeLists.txt 2016-01-04 15:02:54 +0000 |
4 | @@ -149,6 +149,9 @@ |
5 | trust-stored |
6 | |
7 | core/trust/daemon.cpp |
8 | + |
9 | + core/trust/runtime.h |
10 | + core/trust/runtime.cpp |
11 | ) |
12 | |
13 | add_executable( |
14 | |
15 | === modified file 'src/core/trust/daemon.cpp' |
16 | --- src/core/trust/daemon.cpp 2015-08-31 14:00:41 +0000 |
17 | +++ src/core/trust/daemon.cpp 2016-01-04 15:02:54 +0000 |
18 | @@ -22,6 +22,7 @@ |
19 | #include <core/trust/cached_agent.h> |
20 | #include <core/trust/expose.h> |
21 | #include <core/trust/i18n.h> |
22 | +#include <core/trust/runtime.h> |
23 | #include <core/trust/store.h> |
24 | #include <core/trust/white_listing_agent.h> |
25 | |
26 | @@ -49,67 +50,6 @@ |
27 | |
28 | namespace |
29 | { |
30 | - struct Runtime |
31 | - { |
32 | - // Do not execute in parallel, serialize |
33 | - // accesses. |
34 | - static constexpr std::size_t concurrency_hint{2}; |
35 | - |
36 | - // Our evil singleton pattern. Not bad though, we control the |
37 | - // entire executable and rely on automatic cleanup of static |
38 | - // instances. |
39 | - static Runtime& instance() |
40 | - { |
41 | - static Runtime runtime; |
42 | - return runtime; |
43 | - } |
44 | - |
45 | - ~Runtime() |
46 | - { |
47 | - io_service.stop(); |
48 | - |
49 | - if (worker1.joinable()) |
50 | - worker1.join(); |
51 | - |
52 | - if (worker2.joinable()) |
53 | - worker2.join(); |
54 | - } |
55 | - |
56 | - // We trap sig term to ensure a clean shutdown. |
57 | - std::shared_ptr<core::posix::SignalTrap> signal_trap |
58 | - { |
59 | - core::posix::trap_signals_for_all_subsequent_threads( |
60 | - { |
61 | - core::posix::Signal::sig_term, |
62 | - core::posix::Signal::sig_int |
63 | - }) |
64 | - }; |
65 | - |
66 | - // Our io_service instance exposed to remote agents. |
67 | - boost::asio::io_service io_service |
68 | - { |
69 | - concurrency_hint |
70 | - }; |
71 | - |
72 | - // We keep the io_service alive and introduce some artificial |
73 | - // work. |
74 | - boost::asio::io_service::work keep_alive |
75 | - { |
76 | - io_service |
77 | - }; |
78 | - |
79 | - // We immediate execute the io_service instance |
80 | - std::thread worker1 |
81 | - { |
82 | - std::thread{[this]() { io_service.run(); }} |
83 | - }; |
84 | - |
85 | - std::thread worker2 |
86 | - { |
87 | - std::thread{[this]() { io_service.run(); }} |
88 | - }; |
89 | - }; |
90 | - |
91 | core::trust::Daemon::Dictionary fill_dictionary_from_unrecognized_options(const Options::parsed_options& parsed_options) |
92 | { |
93 | auto unrecognized = Options::collect_unrecognized( |
94 | @@ -170,7 +110,7 @@ |
95 | "Could not create bus for name: " + bus_name |
96 | }; |
97 | |
98 | - bus->install_executor(core::dbus::asio::make_executor(bus, Runtime::instance().io_service)); |
99 | + bus->install_executor(core::trust::Runtime::instance().make_executor_for_bus(bus)); |
100 | |
101 | return bus; |
102 | } |
103 | @@ -256,7 +196,7 @@ |
104 | core::trust::remote::posix::Skeleton::Configuration config |
105 | { |
106 | agent, |
107 | - Runtime::instance().io_service, |
108 | + core::trust::Runtime::instance().service(), |
109 | boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")}, |
110 | core::trust::remote::helpers::proc_stat_start_time_resolver(), |
111 | core::trust::remote::helpers::aa_get_task_con_app_id_resolver(), |
112 | @@ -289,16 +229,19 @@ |
113 | core::trust::remote::dbus::default_agent_registry_path |
114 | }); |
115 | |
116 | + core::dbus::DBus daemon{bus}; |
117 | + |
118 | core::trust::remote::dbus::Agent::Skeleton::Configuration config |
119 | { |
120 | agent, |
121 | object, |
122 | + daemon.make_service_watcher(dbus_service_name), |
123 | service, |
124 | bus, |
125 | core::trust::remote::helpers::aa_get_task_con_app_id_resolver() |
126 | }; |
127 | |
128 | - return std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(config); |
129 | + return std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(std::move(config)); |
130 | } |
131 | } |
132 | }; |
133 | @@ -390,16 +333,6 @@ |
134 | // Executes the daemon with the given configuration. |
135 | core::posix::exit::Status core::trust::Daemon::Skeleton::main(const core::trust::Daemon::Skeleton::Configuration& configuration) |
136 | { |
137 | - Runtime::instance().signal_trap->signal_raised().connect([](core::posix::Signal) |
138 | - { |
139 | - Runtime::instance().signal_trap->stop(); |
140 | - }); |
141 | - |
142 | - std::thread worker |
143 | - { |
144 | - [configuration]() { configuration.bus->run(); } |
145 | - }; |
146 | - |
147 | // Expose the local store to the bus, keeping it exposed for the |
148 | // lifetime of the returned token. |
149 | auto token = core::trust::expose_store_to_bus_with_name( |
150 | @@ -407,12 +340,7 @@ |
151 | configuration.bus, |
152 | configuration.service_name); |
153 | |
154 | - Runtime::instance().signal_trap->run(); |
155 | - |
156 | - configuration.bus->stop(); |
157 | - |
158 | - if (worker.joinable()) |
159 | - worker.join(); |
160 | + core::trust::Runtime::instance().run(); |
161 | |
162 | return core::posix::exit::Status::success; |
163 | } |
164 | @@ -432,7 +360,7 @@ |
165 | |
166 | core::trust::remote::posix::Stub::Configuration config |
167 | { |
168 | - Runtime::instance().io_service, |
169 | + core::trust::Runtime::instance().service(), |
170 | boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")}, |
171 | core::trust::remote::helpers::proc_stat_start_time_resolver(), |
172 | core::trust::remote::posix::Stub::get_sock_opt_credentials_resolver(), |
173 | @@ -522,13 +450,18 @@ |
174 | // A user can feed a request to the stub. |
175 | struct Shell : public std::enable_shared_from_this<Shell> |
176 | { |
177 | - Shell(const std::shared_ptr<core::trust::Agent>& agent) |
178 | + Shell(const std::shared_ptr<core::trust::Agent>& agent, boost::asio::io_service& ios) |
179 | : agent{agent}, |
180 | - stdin{Runtime::instance().io_service, STDIN_FILENO}, |
181 | + stdin{ios, STDIN_FILENO}, |
182 | app_id_resolver{core::trust::remote::helpers::aa_get_task_con_app_id_resolver()} |
183 | { |
184 | } |
185 | |
186 | + ~Shell() |
187 | + { |
188 | + stop(); |
189 | + } |
190 | + |
191 | // Prints out the initial prompt and initiates a read operation on stdin. |
192 | void start() |
193 | { |
194 | @@ -605,20 +538,13 @@ |
195 | core::posix::exit::Status core::trust::Daemon::Stub::main(const core::trust::Daemon::Stub::Configuration& configuration) |
196 | { |
197 | // We setup our minimal shell here. |
198 | - auto shell = std::make_shared<Shell>(configuration.remote.agent); |
199 | - |
200 | - Runtime::instance().signal_trap->signal_raised().connect([](core::posix::Signal) |
201 | - { |
202 | - Runtime::instance().signal_trap->stop(); |
203 | - }); |
204 | + auto shell = std::make_shared<Shell>(configuration.remote.agent, core::trust::Runtime::instance().service()); |
205 | |
206 | // We start up our shell |
207 | shell->start(); |
208 | |
209 | // Wait until signal arrives. |
210 | - Runtime::instance().signal_trap->run(); |
211 | - |
212 | - shell->stop(); |
213 | + core::trust::Runtime::instance().run(); |
214 | |
215 | return core::posix::exit::Status::success; |
216 | } |
217 | |
218 | === modified file 'src/core/trust/dbus/agent_registry.h' |
219 | --- src/core/trust/dbus/agent_registry.h 2014-08-04 07:10:52 +0000 |
220 | +++ src/core/trust/dbus/agent_registry.h 2016-01-04 15:02:54 +0000 |
221 | @@ -114,8 +114,10 @@ |
222 | }; |
223 | |
224 | // A DBus stub implementation of core::trust::AgentRegistry. |
225 | - struct Stub : public core::trust::Agent::Registry |
226 | + class Stub : public std::enable_shared_from_this<Stub>, |
227 | + public core::trust::Agent::Registry |
228 | { |
229 | + public: |
230 | // Functor for generating unique object paths. |
231 | typedef std::function<core::dbus::types::ObjectPath(const core::trust::Uid&)> ObjectPathGenerator; |
232 | |
233 | @@ -139,12 +141,12 @@ |
234 | core::dbus::Service::Ptr service; |
235 | // The underlying bus instance. |
236 | core::dbus::Bus::Ptr bus; |
237 | - }; |
238 | + }; |
239 | |
240 | - // Initializes stub access to the Stub. |
241 | - Stub(const Configuration& configuration) |
242 | - : configuration(configuration) |
243 | + // create returns a new shared Stub instance for configuration. |
244 | + static std::shared_ptr<Stub> create(const Configuration& configuration) |
245 | { |
246 | + return std::shared_ptr<Stub>(new Stub(configuration)); |
247 | } |
248 | |
249 | // Calls into the remote implementation to register the given agent implementation. |
250 | @@ -179,6 +181,46 @@ |
251 | locking_agent_registry.register_agent_for_user(uid, skeleton); |
252 | } |
253 | |
254 | + // Calls into the remote implementation to register the given agent implementation. |
255 | + // Throws std::runtime_error and std::logic_error in case of issues. |
256 | + void register_agent_for_user_async(const core::trust::Uid& uid, const std::shared_ptr<core::trust::Agent>& impl, const std::function<void()>& then) |
257 | + { |
258 | + // We sample a path for the given uid |
259 | + auto path = configuration.object_path_generator(uid); |
260 | + // And construct the skeleton instance. |
261 | + auto skeleton = std::shared_ptr<core::trust::dbus::Agent::Skeleton> |
262 | + { |
263 | + new core::trust::dbus::Agent::Skeleton |
264 | + { |
265 | + core::trust::dbus::Agent::Skeleton::Configuration |
266 | + { |
267 | + configuration.service->add_object_for_path(path), |
268 | + configuration.bus, |
269 | + std::bind(&core::trust::Agent::authenticate_request_with_parameters, impl, std::placeholders::_1) |
270 | + } |
271 | + } |
272 | + }; |
273 | + |
274 | + auto sp = shared_from_this(); |
275 | + |
276 | + // And announce the agent. |
277 | + configuration.object->invoke_method_asynchronously_with_callback< |
278 | + Methods::RegisterAgentForUser, void |
279 | + >([this, sp, then, uid, skeleton](const core::dbus::Result<void>& result) |
280 | + { |
281 | + if (result.is_error()) |
282 | + { |
283 | + std::cerr << "Failed to register agent for user: " << result.error().print() << std::endl; |
284 | + } |
285 | + else |
286 | + { |
287 | + // All good, update our own state prior to invoking the supplied callback. |
288 | + locking_agent_registry.register_agent_for_user(uid, skeleton); |
289 | + then(); |
290 | + } |
291 | + }, uid, path); |
292 | + } |
293 | + |
294 | // Calls into the remote implementation to unregister any agent registered for the given uid. |
295 | // Throws std::runtime_error and std::logic_error in case of issues. |
296 | void unregister_agent_for_user(const core::trust::Uid& uid) override |
297 | @@ -195,6 +237,13 @@ |
298 | }; |
299 | } |
300 | |
301 | + private: |
302 | + // Initializes stub access to the Stub. |
303 | + Stub(const Configuration& configuration) |
304 | + : configuration(configuration) |
305 | + { |
306 | + } |
307 | + |
308 | // We just store all creation-time arguments. |
309 | Configuration configuration; |
310 | // Our local registry of agents |
311 | |
312 | === modified file 'src/core/trust/remote/dbus.cpp' |
313 | --- src/core/trust/remote/dbus.cpp 2014-07-29 17:00:35 +0000 |
314 | +++ src/core/trust/remote/dbus.cpp 2016-01-04 15:02:54 +0000 |
315 | @@ -19,6 +19,7 @@ |
316 | #include <core/trust/remote/dbus.h> |
317 | |
318 | #include <core/trust/dbus_agent.h> |
319 | +#include <core/trust/runtime.h> |
320 | |
321 | core::trust::remote::dbus::Agent::Stub::Stub(const core::trust::remote::dbus::Agent::Stub::Configuration& configuration) |
322 | : agent_registry_skeleton |
323 | @@ -43,20 +44,31 @@ |
324 | return agent->authenticate_request_with_parameters(parameters); |
325 | } |
326 | |
327 | -core::trust::remote::dbus::Agent::Skeleton::Skeleton(const core::trust::remote::dbus::Agent::Skeleton::Configuration& configuration) |
328 | +core::trust::remote::dbus::Agent::Skeleton::Skeleton(core::trust::remote::dbus::Agent::Skeleton::Configuration configuration) |
329 | : core::trust::remote::Agent::Skeleton{configuration.impl}, |
330 | + config(std::move(configuration)), |
331 | agent_registry_stub |
332 | { |
333 | - core::trust::dbus::AgentRegistry::Stub::Configuration |
334 | - { |
335 | - configuration.agent_registry_object, |
336 | - core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(), |
337 | - configuration.service, |
338 | - configuration.bus |
339 | - } |
340 | + core::trust::dbus::AgentRegistry::Stub::create( |
341 | + core::trust::dbus::AgentRegistry::Stub::Configuration |
342 | + { |
343 | + config.agent_registry_object, |
344 | + core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(), |
345 | + config.service, |
346 | + config.bus |
347 | + }) |
348 | } |
349 | { |
350 | - agent_registry_stub.register_agent_for_user(core::trust::Uid{::getuid()}, configuration.impl); |
351 | + static const auto printing_cb = []() { std::cout << "Successfully registered agent for user." << std::endl; }; |
352 | + |
353 | + agent_registry_stub->register_agent_for_user_async(core::trust::Uid{::getuid()}, config.impl, printing_cb); |
354 | + |
355 | + // We don't have to track the lifetime of "this" as config.agent_registry_watcher is owned |
356 | + // by "this". |
357 | + config.agent_registry_watcher->service_registered().connect([this]() |
358 | + { |
359 | + agent_registry_stub->register_agent_for_user_async(core::trust::Uid{::getuid()}, config.impl, printing_cb); |
360 | + }); |
361 | } |
362 | |
363 | core::trust::Request::Answer core::trust::remote::dbus::Agent::Skeleton::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters) |
364 | |
365 | === modified file 'src/core/trust/remote/dbus.h' |
366 | --- src/core/trust/remote/dbus.h 2014-08-04 07:57:05 +0000 |
367 | +++ src/core/trust/remote/dbus.h 2016-01-04 15:02:54 +0000 |
368 | @@ -25,6 +25,8 @@ |
369 | #include <core/trust/dbus/agent.h> |
370 | #include <core/trust/dbus/agent_registry.h> |
371 | |
372 | +#include <core/dbus/service_watcher.h> |
373 | + |
374 | #include <unistd.h> |
375 | #include <sys/types.h> |
376 | |
377 | @@ -86,6 +88,8 @@ |
378 | std::shared_ptr<Agent> impl; |
379 | // The remote object implementing core.trust.dbus.AgentRegistry. |
380 | core::dbus::Object::Ptr agent_registry_object; |
381 | + // The watcher monitoring the remote object implementing core.trust.dbus.AgentRegistry. |
382 | + std::unique_ptr<core::dbus::ServiceWatcher> agent_registry_watcher; |
383 | // The service that objects implementing core.trust.dbus.Agent should be added to. |
384 | core::dbus::Service::Ptr service; |
385 | // The underlying bus instance. |
386 | @@ -95,13 +99,15 @@ |
387 | }; |
388 | |
389 | // Constructs a new Skeleton instance, installing impl for handling actual requests. |
390 | - Skeleton(const Configuration& configuration); |
391 | + Skeleton(Configuration configuration); |
392 | |
393 | // From core::trust::Agent, dispatches to the actual implementation. |
394 | core::trust::Request::Answer authenticate_request_with_parameters(const RequestParameters& parameters); |
395 | |
396 | + // Store all creation-time parameters. |
397 | + Configuration config; |
398 | // Stub for accessing the remote agent registry. |
399 | - core::trust::dbus::AgentRegistry::Stub agent_registry_stub; |
400 | + std::shared_ptr<core::trust::dbus::AgentRegistry::Stub> agent_registry_stub; |
401 | }; |
402 | }; |
403 | } |
404 | |
405 | === added file 'src/core/trust/runtime.cpp' |
406 | --- src/core/trust/runtime.cpp 1970-01-01 00:00:00 +0000 |
407 | +++ src/core/trust/runtime.cpp 2016-01-04 15:02:54 +0000 |
408 | @@ -0,0 +1,105 @@ |
409 | +/* |
410 | + * Copyright © 2016 Canonical Ltd. |
411 | + * |
412 | + * This program is free software: you can redistribute it and/or modify it |
413 | + * under the terms of the GNU Lesser General Public License version 3, |
414 | + * as published by the Free Software Foundation. |
415 | + * |
416 | + * This program is distributed in the hope that it will be useful, |
417 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
418 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
419 | + * GNU Lesser General Public License for more details. |
420 | + * |
421 | + * You should have received a copy of the GNU Lesser General Public License |
422 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
423 | + * |
424 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
425 | + */ |
426 | + |
427 | +#include <core/trust/runtime.h> |
428 | + |
429 | +#include <core/dbus/asio/executor.h> |
430 | + |
431 | +#include <iostream> |
432 | +#include <stdexcept> |
433 | + |
434 | +namespace |
435 | +{ |
436 | +void execute_and_never_throw(boost::asio::io_service& ios) noexcept(true) |
437 | +{ |
438 | + while (true) |
439 | + { |
440 | + try |
441 | + { |
442 | + ios.run(); |
443 | + break; |
444 | + } |
445 | + catch (const std::exception& e) |
446 | + { |
447 | + std::cerr << __PRETTY_FUNCTION__ << ": " << e.what() << std::endl; |
448 | + } |
449 | + catch (...) |
450 | + { |
451 | + std::cerr << __PRETTY_FUNCTION__ << ": unknown exception" << std::endl; |
452 | + } |
453 | + } |
454 | +} |
455 | +} |
456 | + |
457 | +core::trust::Runtime& core::trust::Runtime::instance() |
458 | +{ |
459 | + static Runtime runtime; |
460 | + return runtime; |
461 | +} |
462 | + |
463 | +core::trust::Runtime::Runtime() |
464 | + : signal_trap{core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term, core::posix::Signal::sig_int})}, |
465 | + keep_alive{io_service} |
466 | +{ |
467 | + for (std::size_t i = 0; i < Runtime::concurrency_hint; i++) |
468 | + { |
469 | + pool.emplace_back(execute_and_never_throw, std::ref(io_service)); |
470 | + } |
471 | + |
472 | + signal_trap->signal_raised().connect([this](const core::posix::Signal&) |
473 | + { |
474 | + stop(); |
475 | + }); |
476 | +} |
477 | + |
478 | +core::trust::Runtime::~Runtime() |
479 | +{ |
480 | + try |
481 | + { |
482 | + io_service.stop(); |
483 | + |
484 | + for (auto& worker : pool) |
485 | + if (worker.joinable()) |
486 | + worker.join(); |
487 | + } |
488 | + catch (...) |
489 | + { |
490 | + // Empty on purpose. We just have to |
491 | + // fulfill the noexcept(true) guarantee. |
492 | + } |
493 | +} |
494 | + |
495 | +void core::trust::Runtime::run() |
496 | +{ |
497 | + signal_trap->run(); |
498 | +} |
499 | + |
500 | +void core::trust::Runtime::stop() |
501 | +{ |
502 | + signal_trap->stop(); |
503 | +} |
504 | + |
505 | +boost::asio::io_service& core::trust::Runtime::service() |
506 | +{ |
507 | + return io_service; |
508 | +} |
509 | + |
510 | +core::dbus::Executor::Ptr core::trust::Runtime::make_executor_for_bus(const core::dbus::Bus::Ptr& bus) |
511 | +{ |
512 | + return core::dbus::asio::make_executor(bus, io_service); |
513 | +} |
514 | |
515 | === added file 'src/core/trust/runtime.h' |
516 | --- src/core/trust/runtime.h 1970-01-01 00:00:00 +0000 |
517 | +++ src/core/trust/runtime.h 2016-01-04 15:02:54 +0000 |
518 | @@ -0,0 +1,88 @@ |
519 | +/* |
520 | + * Copyright © 2016 Canonical Ltd. |
521 | + * |
522 | + * This program is free software: you can redistribute it and/or modify it |
523 | + * under the terms of the GNU Lesser General Public License version 3, |
524 | + * as published by the Free Software Foundation. |
525 | + * |
526 | + * This program is distributed in the hope that it will be useful, |
527 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
528 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
529 | + * GNU Lesser General Public License for more details. |
530 | + * |
531 | + * You should have received a copy of the GNU Lesser General Public License |
532 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
533 | + * |
534 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
535 | + */ |
536 | + |
537 | +#ifndef CORE_TRUST_RUNTIME_H_ |
538 | +#define CORE_TRUST_RUNTIME_H_ |
539 | + |
540 | +#include <core/posix/signal.h> |
541 | + |
542 | +#include <core/dbus/bus.h> |
543 | +#include <core/dbus/executor.h> |
544 | + |
545 | +#include <boost/asio.hpp> |
546 | + |
547 | +#include <memory> |
548 | +#include <thread> |
549 | +#include <vector> |
550 | + |
551 | +namespace core |
552 | +{ |
553 | +namespace trust |
554 | +{ |
555 | +// A Runtime maintains a pool of workers enabling |
556 | +// implementations to dispatch invocations and have their |
557 | +// ready handlers automatically executed. |
558 | +class Runtime |
559 | +{ |
560 | +public: |
561 | + // Do not execute in parallel, serialize |
562 | + // accesses. |
563 | + static constexpr std::size_t concurrency_hint{2}; |
564 | + |
565 | + // Our evil singleton pattern. Not bad though, we control the |
566 | + // entire executable and rely on automatic cleanup of static |
567 | + // instances. |
568 | + static Runtime& instance(); |
569 | + |
570 | + // Gracefully shuts down operations. |
571 | + ~Runtime() noexcept(true); |
572 | + |
573 | + // run blocks until either stop is called or a |
574 | + // signal requesting graceful shutdown is received. |
575 | + void run(); |
576 | + |
577 | + // requests the runtime to shut down, does not block. |
578 | + void stop(); |
579 | + |
580 | + // Returns a mutable reference to the underlying boost::asio::io_service |
581 | + // powering the runtime's reactor. |
582 | + boost::asio::io_service& service(); |
583 | + |
584 | + // Creates an executor for a bus instance hooking into this Runtime instance. |
585 | + core::dbus::Executor::Ptr make_executor_for_bus(const core::dbus::Bus::Ptr& bus); |
586 | + |
587 | +private: |
588 | + Runtime(); |
589 | + |
590 | + // We trap sig term to ensure a clean shutdown. |
591 | + std::shared_ptr<core::posix::SignalTrap> signal_trap; |
592 | + |
593 | + // Our io_service instance exposed to remote agents. |
594 | + boost::asio::io_service io_service; |
595 | + |
596 | + // We keep the io_service alive and introduce some artificial |
597 | + // work. |
598 | + boost::asio::io_service::work keep_alive; |
599 | + |
600 | + // We execute the io_service on a pool of worker threads. |
601 | + std::vector<std::thread> pool; |
602 | +}; |
603 | +} |
604 | +} |
605 | + |
606 | +#endif // CORE_TRUST_RUNTIME_H_ |
607 | |
608 | === modified file 'tests/CMakeLists.txt' |
609 | --- tests/CMakeLists.txt 2014-11-14 12:17:24 +0000 |
610 | +++ tests/CMakeLists.txt 2016-01-04 15:02:54 +0000 |
611 | @@ -46,6 +46,9 @@ |
612 | add_executable( |
613 | remote_agent_test |
614 | remote_agent_test.cpp |
615 | + |
616 | + ${CMAKE_SOURCE_DIR}/src/core/trust/runtime.h |
617 | + ${CMAKE_SOURCE_DIR}/src/core/trust/runtime.cpp |
618 | ) |
619 | |
620 | add_executable( |
621 | |
622 | === modified file 'tests/dbus_test.cpp' |
623 | --- tests/dbus_test.cpp 2014-08-04 08:32:57 +0000 |
624 | +++ tests/dbus_test.cpp 2016-01-04 15:02:54 +0000 |
625 | @@ -370,21 +370,19 @@ |
626 | InvokeWithoutArgs(&state, &State::notify), |
627 | Return(core::trust::Request::Answer::denied))); |
628 | |
629 | - core::trust::dbus::AgentRegistry::Stub stub |
630 | - { |
631 | + auto stub = core::trust::dbus::AgentRegistry::Stub::create( |
632 | core::trust::dbus::AgentRegistry::Stub::Configuration |
633 | { |
634 | agent_registry_object, |
635 | core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(), |
636 | service, |
637 | bus |
638 | - } |
639 | - }; |
640 | + }); |
641 | |
642 | std::thread t{[bus]() { bus->run(); }}; |
643 | |
644 | // We register for the current user id. |
645 | - stub.register_agent_for_user(core::trust::Uid{::getuid()}, agent); |
646 | + stub->register_agent_for_user(core::trust::Uid{::getuid()}, agent); |
647 | |
648 | // Tell the other side that we are good to go. |
649 | agent_registered.try_signal_ready_for(std::chrono::milliseconds{500}); |
650 | @@ -393,7 +391,7 @@ |
651 | state.wait(); |
652 | |
653 | // And unregister again. |
654 | - stub.unregister_agent_for_user(core::trust::Uid{::getuid()}); |
655 | + stub->unregister_agent_for_user(core::trust::Uid{::getuid()}); |
656 | |
657 | bus->stop(); |
658 | |
659 | |
660 | === modified file 'tests/remote_agent_test.cpp' |
661 | --- tests/remote_agent_test.cpp 2015-08-14 09:53:12 +0000 |
662 | +++ tests/remote_agent_test.cpp 2016-01-04 15:02:54 +0000 |
663 | @@ -30,6 +30,8 @@ |
664 | #include <core/dbus/asio/executor.h> |
665 | #include <core/dbus/fixture.h> |
666 | |
667 | +#include <core/trust/runtime.h> |
668 | + |
669 | #include <gmock/gmock.h> |
670 | #include <gtest/gtest.h> |
671 | |
672 | @@ -792,6 +794,12 @@ |
673 | { |
674 | struct DBus : public core::dbus::testing::Fixture |
675 | { |
676 | + core::dbus::Bus::Ptr session_bus_with_executor() |
677 | + { |
678 | + auto sb = session_bus(); |
679 | + sb->install_executor(core::trust::Runtime::instance().make_executor_for_bus(sb)); |
680 | + return sb; |
681 | + } |
682 | }; |
683 | |
684 | std::string service_name |
685 | @@ -804,10 +812,6 @@ |
686 | { |
687 | using namespace ::testing; |
688 | |
689 | - core::testing::CrossProcessSync |
690 | - stub_ready, // signals stub --| I'm ready |--> skeleton |
691 | - skeleton_ready; // signals skeleton --| I'm ready |--> stub |
692 | - |
693 | auto app = core::posix::fork([]() |
694 | { |
695 | while(true) std::this_thread::sleep_for(std::chrono::milliseconds{500}); |
696 | @@ -825,7 +829,50 @@ |
697 | const core::trust::Uid app_uid{::getuid()}; |
698 | const core::trust::Pid app_pid{app.pid()}; |
699 | |
700 | - auto stub = core::posix::fork([this, app_uid, app_pid, answer, &stub_ready, &skeleton_ready]() |
701 | + auto skeleton = core::posix::fork([this, answer]() |
702 | + { |
703 | + auto bus = session_bus_with_executor(); |
704 | + |
705 | + // We have to rely on a MockAgent to break the dependency on a running Mir instance. |
706 | + auto mock_agent = std::make_shared<::testing::NiceMock<MockAgent>>(); |
707 | + |
708 | + ON_CALL(*mock_agent, authenticate_request_with_parameters(_)) |
709 | + .WillByDefault(Return(answer)); |
710 | + |
711 | + std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name; |
712 | + |
713 | + auto service = core::dbus::Service::use_service(bus, dbus_service_name); |
714 | + auto object = service->object_for_path(core::dbus::types::ObjectPath |
715 | + { |
716 | + core::trust::remote::dbus::default_agent_registry_path |
717 | + }); |
718 | + |
719 | + core::dbus::DBus daemon{bus}; |
720 | + |
721 | + core::trust::remote::dbus::Agent::Skeleton::Configuration config |
722 | + { |
723 | + mock_agent, |
724 | + object, |
725 | + daemon.make_service_watcher(dbus_service_name), |
726 | + service, |
727 | + bus, |
728 | + core::trust::remote::helpers::aa_get_task_con_app_id_resolver() |
729 | + }; |
730 | + |
731 | + auto skeleton = std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(std::move(config)); |
732 | + |
733 | + core::trust::Runtime::instance().run(); |
734 | + return core::posix::exit::Status::success; |
735 | + }, core::posix::StandardStream::empty); |
736 | + |
737 | + |
738 | + // stubf models a trusted helper, with the following simplified |
739 | + // mode of operation: |
740 | + // (1.) Helper claims its unique name on the bus. |
741 | + // (2.) Helper installs an AgentRegistry::Skeleton. |
742 | + // (3.) Helper learns about per-user trust::Agent instances on the bus. |
743 | + // (4.) Helper issues requests for authentication. |
744 | + auto stubf = [this, app_uid, app_pid, answer]() |
745 | { |
746 | core::trust::Agent::RequestParameters ref_params |
747 | { |
748 | @@ -836,10 +883,7 @@ |
749 | "just an example description" |
750 | }; |
751 | |
752 | - auto bus = session_bus(); |
753 | - bus->install_executor(core::dbus::asio::make_executor(bus)); |
754 | - |
755 | - std::thread worker{[bus]() { bus->run(); }}; |
756 | + auto bus = session_bus_with_executor(); |
757 | |
758 | std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name; |
759 | |
760 | @@ -857,76 +901,24 @@ |
761 | |
762 | auto stub = std::make_shared<core::trust::remote::dbus::Agent::Stub>(config); |
763 | |
764 | - stub_ready.try_signal_ready_for(std::chrono::milliseconds{1000}); |
765 | - skeleton_ready.wait_for_signal_ready_for(std::chrono::milliseconds{1000}); |
766 | + std::this_thread::sleep_for(std::chrono::seconds(10)); |
767 | |
768 | for (unsigned int i = 0; i < 100; i++) |
769 | EXPECT_EQ(answer, stub->authenticate_request_with_parameters(ref_params)); |
770 | |
771 | - bus->stop(); |
772 | - |
773 | - if (worker.joinable()) |
774 | - worker.join(); |
775 | - |
776 | return Test::HasFailure() ? |
777 | core::posix::exit::Status::failure : |
778 | core::posix::exit::Status::success; |
779 | - }, core::posix::StandardStream::empty); |
780 | - |
781 | - auto skeleton = core::posix::fork([this, answer, &stub_ready, &skeleton_ready]() |
782 | - { |
783 | - auto trap = core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term}); |
784 | - |
785 | - trap->signal_raised().connect([trap](core::posix::Signal) |
786 | - { |
787 | - trap->stop(); |
788 | - }); |
789 | - |
790 | - auto bus = session_bus(); |
791 | - bus->install_executor(core::dbus::asio::make_executor(bus)); |
792 | - |
793 | - std::thread worker{[bus]() { bus->run(); }}; |
794 | - |
795 | - // We have to rely on a MockAgent to break the dependency on a running Mir instance. |
796 | - auto mock_agent = std::make_shared<::testing::NiceMock<MockAgent>>(); |
797 | - |
798 | - ON_CALL(*mock_agent, authenticate_request_with_parameters(_)) |
799 | - .WillByDefault(Return(answer)); |
800 | - |
801 | - std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name; |
802 | - |
803 | - stub_ready.wait_for_signal_ready_for(std::chrono::milliseconds{1000}); |
804 | - |
805 | - auto service = core::dbus::Service::use_service(bus, dbus_service_name); |
806 | - auto object = service->object_for_path(core::dbus::types::ObjectPath |
807 | - { |
808 | - core::trust::remote::dbus::default_agent_registry_path |
809 | - }); |
810 | - |
811 | - core::trust::remote::dbus::Agent::Skeleton::Configuration config |
812 | - { |
813 | - mock_agent, |
814 | - object, |
815 | - service, |
816 | - bus, |
817 | - core::trust::remote::helpers::aa_get_task_con_app_id_resolver() |
818 | - }; |
819 | - |
820 | - auto skeleton = std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(config); |
821 | - |
822 | - skeleton_ready.try_signal_ready_for(std::chrono::milliseconds{1000}); |
823 | - |
824 | - trap->run(); |
825 | - |
826 | - bus->stop(); |
827 | - |
828 | - if (worker.joinable()) |
829 | - worker.join(); |
830 | - |
831 | - return core::posix::exit::Status::success; |
832 | - }, core::posix::StandardStream::empty); |
833 | - |
834 | - EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced))); |
835 | + }; |
836 | + |
837 | + std::this_thread::sleep_for(std::chrono::seconds(2)); |
838 | + auto stub = core::posix::fork(stubf, core::posix::StandardStream::empty); |
839 | + EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced))); |
840 | + |
841 | + std::this_thread::sleep_for(std::chrono::seconds(2)); |
842 | + stub = core::posix::fork(stubf, core::posix::StandardStream::empty); |
843 | + EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced))); |
844 | + |
845 | skeleton.send_signal_or_throw(core::posix::Signal::sig_term); |
846 | EXPECT_TRUE(ProcessExitedSuccessfully(skeleton.wait_for(core::posix::wait::Flags::untraced))); |
847 |