Merge lp:~thomas-voss/trust-store/watch-service-name-owner-changes into lp:trust-store/15.04

Proposed by Thomas Voß
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
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::dbus::Agent::Skeleton now watches for name owner changes, announcing itself
asynchronously if a new name owner is detected.

Description of the change

core::trust::dbus::Agent::Skeleton now watches for name owner changes, announcing itself
asynchronously if a new name owner is detected.

To post a comment you must log in.
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2015-08-31 13:16:20 +0000
+++ src/CMakeLists.txt 2016-01-04 15:02:54 +0000
@@ -149,6 +149,9 @@
149 trust-stored149 trust-stored
150150
151 core/trust/daemon.cpp151 core/trust/daemon.cpp
152
153 core/trust/runtime.h
154 core/trust/runtime.cpp
152)155)
153156
154add_executable(157add_executable(
155158
=== modified file 'src/core/trust/daemon.cpp'
--- src/core/trust/daemon.cpp 2015-08-31 14:00:41 +0000
+++ src/core/trust/daemon.cpp 2016-01-04 15:02:54 +0000
@@ -22,6 +22,7 @@
22#include <core/trust/cached_agent.h>22#include <core/trust/cached_agent.h>
23#include <core/trust/expose.h>23#include <core/trust/expose.h>
24#include <core/trust/i18n.h>24#include <core/trust/i18n.h>
25#include <core/trust/runtime.h>
25#include <core/trust/store.h>26#include <core/trust/store.h>
26#include <core/trust/white_listing_agent.h>27#include <core/trust/white_listing_agent.h>
2728
@@ -49,67 +50,6 @@
4950
50namespace51namespace
51{52{
52 struct Runtime
53 {
54 // Do not execute in parallel, serialize
55 // accesses.
56 static constexpr std::size_t concurrency_hint{2};
57
58 // Our evil singleton pattern. Not bad though, we control the
59 // entire executable and rely on automatic cleanup of static
60 // instances.
61 static Runtime& instance()
62 {
63 static Runtime runtime;
64 return runtime;
65 }
66
67 ~Runtime()
68 {
69 io_service.stop();
70
71 if (worker1.joinable())
72 worker1.join();
73
74 if (worker2.joinable())
75 worker2.join();
76 }
77
78 // We trap sig term to ensure a clean shutdown.
79 std::shared_ptr<core::posix::SignalTrap> signal_trap
80 {
81 core::posix::trap_signals_for_all_subsequent_threads(
82 {
83 core::posix::Signal::sig_term,
84 core::posix::Signal::sig_int
85 })
86 };
87
88 // Our io_service instance exposed to remote agents.
89 boost::asio::io_service io_service
90 {
91 concurrency_hint
92 };
93
94 // We keep the io_service alive and introduce some artificial
95 // work.
96 boost::asio::io_service::work keep_alive
97 {
98 io_service
99 };
100
101 // We immediate execute the io_service instance
102 std::thread worker1
103 {
104 std::thread{[this]() { io_service.run(); }}
105 };
106
107 std::thread worker2
108 {
109 std::thread{[this]() { io_service.run(); }}
110 };
111 };
112
113 core::trust::Daemon::Dictionary fill_dictionary_from_unrecognized_options(const Options::parsed_options& parsed_options)53 core::trust::Daemon::Dictionary fill_dictionary_from_unrecognized_options(const Options::parsed_options& parsed_options)
114 {54 {
115 auto unrecognized = Options::collect_unrecognized(55 auto unrecognized = Options::collect_unrecognized(
@@ -170,7 +110,7 @@
170 "Could not create bus for name: " + bus_name110 "Could not create bus for name: " + bus_name
171 };111 };
172112
173 bus->install_executor(core::dbus::asio::make_executor(bus, Runtime::instance().io_service));113 bus->install_executor(core::trust::Runtime::instance().make_executor_for_bus(bus));
174114
175 return bus;115 return bus;
176 }116 }
@@ -256,7 +196,7 @@
256 core::trust::remote::posix::Skeleton::Configuration config196 core::trust::remote::posix::Skeleton::Configuration config
257 {197 {
258 agent,198 agent,
259 Runtime::instance().io_service,199 core::trust::Runtime::instance().service(),
260 boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")},200 boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")},
261 core::trust::remote::helpers::proc_stat_start_time_resolver(),201 core::trust::remote::helpers::proc_stat_start_time_resolver(),
262 core::trust::remote::helpers::aa_get_task_con_app_id_resolver(),202 core::trust::remote::helpers::aa_get_task_con_app_id_resolver(),
@@ -289,16 +229,19 @@
289 core::trust::remote::dbus::default_agent_registry_path229 core::trust::remote::dbus::default_agent_registry_path
290 });230 });
291231
232 core::dbus::DBus daemon{bus};
233
292 core::trust::remote::dbus::Agent::Skeleton::Configuration config234 core::trust::remote::dbus::Agent::Skeleton::Configuration config
293 {235 {
294 agent,236 agent,
295 object,237 object,
238 daemon.make_service_watcher(dbus_service_name),
296 service,239 service,
297 bus,240 bus,
298 core::trust::remote::helpers::aa_get_task_con_app_id_resolver()241 core::trust::remote::helpers::aa_get_task_con_app_id_resolver()
299 };242 };
300243
301 return std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(config);244 return std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(std::move(config));
302 }245 }
303 }246 }
304 };247 };
@@ -390,16 +333,6 @@
390// Executes the daemon with the given configuration.333// Executes the daemon with the given configuration.
391core::posix::exit::Status core::trust::Daemon::Skeleton::main(const core::trust::Daemon::Skeleton::Configuration& configuration)334core::posix::exit::Status core::trust::Daemon::Skeleton::main(const core::trust::Daemon::Skeleton::Configuration& configuration)
392{335{
393 Runtime::instance().signal_trap->signal_raised().connect([](core::posix::Signal)
394 {
395 Runtime::instance().signal_trap->stop();
396 });
397
398 std::thread worker
399 {
400 [configuration]() { configuration.bus->run(); }
401 };
402
403 // Expose the local store to the bus, keeping it exposed for the336 // Expose the local store to the bus, keeping it exposed for the
404 // lifetime of the returned token.337 // lifetime of the returned token.
405 auto token = core::trust::expose_store_to_bus_with_name(338 auto token = core::trust::expose_store_to_bus_with_name(
@@ -407,12 +340,7 @@
407 configuration.bus,340 configuration.bus,
408 configuration.service_name);341 configuration.service_name);
409342
410 Runtime::instance().signal_trap->run();343 core::trust::Runtime::instance().run();
411
412 configuration.bus->stop();
413
414 if (worker.joinable())
415 worker.join();
416344
417 return core::posix::exit::Status::success;345 return core::posix::exit::Status::success;
418}346}
@@ -432,7 +360,7 @@
432360
433 core::trust::remote::posix::Stub::Configuration config361 core::trust::remote::posix::Stub::Configuration config
434 {362 {
435 Runtime::instance().io_service,363 core::trust::Runtime::instance().service(),
436 boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")},364 boost::asio::local::stream_protocol::endpoint{dict.at("endpoint")},
437 core::trust::remote::helpers::proc_stat_start_time_resolver(),365 core::trust::remote::helpers::proc_stat_start_time_resolver(),
438 core::trust::remote::posix::Stub::get_sock_opt_credentials_resolver(),366 core::trust::remote::posix::Stub::get_sock_opt_credentials_resolver(),
@@ -522,13 +450,18 @@
522// A user can feed a request to the stub.450// A user can feed a request to the stub.
523struct Shell : public std::enable_shared_from_this<Shell>451struct Shell : public std::enable_shared_from_this<Shell>
524{452{
525 Shell(const std::shared_ptr<core::trust::Agent>& agent)453 Shell(const std::shared_ptr<core::trust::Agent>& agent, boost::asio::io_service& ios)
526 : agent{agent},454 : agent{agent},
527 stdin{Runtime::instance().io_service, STDIN_FILENO},455 stdin{ios, STDIN_FILENO},
528 app_id_resolver{core::trust::remote::helpers::aa_get_task_con_app_id_resolver()}456 app_id_resolver{core::trust::remote::helpers::aa_get_task_con_app_id_resolver()}
529 {457 {
530 }458 }
531459
460 ~Shell()
461 {
462 stop();
463 }
464
532 // Prints out the initial prompt and initiates a read operation on stdin.465 // Prints out the initial prompt and initiates a read operation on stdin.
533 void start()466 void start()
534 {467 {
@@ -605,20 +538,13 @@
605core::posix::exit::Status core::trust::Daemon::Stub::main(const core::trust::Daemon::Stub::Configuration& configuration)538core::posix::exit::Status core::trust::Daemon::Stub::main(const core::trust::Daemon::Stub::Configuration& configuration)
606{539{
607 // We setup our minimal shell here.540 // We setup our minimal shell here.
608 auto shell = std::make_shared<Shell>(configuration.remote.agent);541 auto shell = std::make_shared<Shell>(configuration.remote.agent, core::trust::Runtime::instance().service());
609
610 Runtime::instance().signal_trap->signal_raised().connect([](core::posix::Signal)
611 {
612 Runtime::instance().signal_trap->stop();
613 });
614542
615 // We start up our shell543 // We start up our shell
616 shell->start();544 shell->start();
617545
618 // Wait until signal arrives.546 // Wait until signal arrives.
619 Runtime::instance().signal_trap->run();547 core::trust::Runtime::instance().run();
620
621 shell->stop();
622548
623 return core::posix::exit::Status::success;549 return core::posix::exit::Status::success;
624}550}
625551
=== modified file 'src/core/trust/dbus/agent_registry.h'
--- src/core/trust/dbus/agent_registry.h 2014-08-04 07:10:52 +0000
+++ src/core/trust/dbus/agent_registry.h 2016-01-04 15:02:54 +0000
@@ -114,8 +114,10 @@
114 };114 };
115115
116 // A DBus stub implementation of core::trust::AgentRegistry.116 // A DBus stub implementation of core::trust::AgentRegistry.
117 struct Stub : public core::trust::Agent::Registry117 class Stub : public std::enable_shared_from_this<Stub>,
118 public core::trust::Agent::Registry
118 {119 {
120 public:
119 // Functor for generating unique object paths.121 // Functor for generating unique object paths.
120 typedef std::function<core::dbus::types::ObjectPath(const core::trust::Uid&)> ObjectPathGenerator;122 typedef std::function<core::dbus::types::ObjectPath(const core::trust::Uid&)> ObjectPathGenerator;
121123
@@ -139,12 +141,12 @@
139 core::dbus::Service::Ptr service;141 core::dbus::Service::Ptr service;
140 // The underlying bus instance.142 // The underlying bus instance.
141 core::dbus::Bus::Ptr bus;143 core::dbus::Bus::Ptr bus;
142 };144 };
143145
144 // Initializes stub access to the Stub.146 // create returns a new shared Stub instance for configuration.
145 Stub(const Configuration& configuration)147 static std::shared_ptr<Stub> create(const Configuration& configuration)
146 : configuration(configuration)
147 {148 {
149 return std::shared_ptr<Stub>(new Stub(configuration));
148 }150 }
149151
150 // Calls into the remote implementation to register the given agent implementation.152 // Calls into the remote implementation to register the given agent implementation.
@@ -179,6 +181,46 @@
179 locking_agent_registry.register_agent_for_user(uid, skeleton);181 locking_agent_registry.register_agent_for_user(uid, skeleton);
180 }182 }
181183
184 // Calls into the remote implementation to register the given agent implementation.
185 // Throws std::runtime_error and std::logic_error in case of issues.
186 void register_agent_for_user_async(const core::trust::Uid& uid, const std::shared_ptr<core::trust::Agent>& impl, const std::function<void()>& then)
187 {
188 // We sample a path for the given uid
189 auto path = configuration.object_path_generator(uid);
190 // And construct the skeleton instance.
191 auto skeleton = std::shared_ptr<core::trust::dbus::Agent::Skeleton>
192 {
193 new core::trust::dbus::Agent::Skeleton
194 {
195 core::trust::dbus::Agent::Skeleton::Configuration
196 {
197 configuration.service->add_object_for_path(path),
198 configuration.bus,
199 std::bind(&core::trust::Agent::authenticate_request_with_parameters, impl, std::placeholders::_1)
200 }
201 }
202 };
203
204 auto sp = shared_from_this();
205
206 // And announce the agent.
207 configuration.object->invoke_method_asynchronously_with_callback<
208 Methods::RegisterAgentForUser, void
209 >([this, sp, then, uid, skeleton](const core::dbus::Result<void>& result)
210 {
211 if (result.is_error())
212 {
213 std::cerr << "Failed to register agent for user: " << result.error().print() << std::endl;
214 }
215 else
216 {
217 // All good, update our own state prior to invoking the supplied callback.
218 locking_agent_registry.register_agent_for_user(uid, skeleton);
219 then();
220 }
221 }, uid, path);
222 }
223
182 // Calls into the remote implementation to unregister any agent registered for the given uid.224 // Calls into the remote implementation to unregister any agent registered for the given uid.
183 // Throws std::runtime_error and std::logic_error in case of issues.225 // Throws std::runtime_error and std::logic_error in case of issues.
184 void unregister_agent_for_user(const core::trust::Uid& uid) override226 void unregister_agent_for_user(const core::trust::Uid& uid) override
@@ -195,6 +237,13 @@
195 };237 };
196 }238 }
197239
240 private:
241 // Initializes stub access to the Stub.
242 Stub(const Configuration& configuration)
243 : configuration(configuration)
244 {
245 }
246
198 // We just store all creation-time arguments.247 // We just store all creation-time arguments.
199 Configuration configuration;248 Configuration configuration;
200 // Our local registry of agents249 // Our local registry of agents
201250
=== modified file 'src/core/trust/remote/dbus.cpp'
--- src/core/trust/remote/dbus.cpp 2014-07-29 17:00:35 +0000
+++ src/core/trust/remote/dbus.cpp 2016-01-04 15:02:54 +0000
@@ -19,6 +19,7 @@
19#include <core/trust/remote/dbus.h>19#include <core/trust/remote/dbus.h>
2020
21#include <core/trust/dbus_agent.h>21#include <core/trust/dbus_agent.h>
22#include <core/trust/runtime.h>
2223
23core::trust::remote::dbus::Agent::Stub::Stub(const core::trust::remote::dbus::Agent::Stub::Configuration& configuration)24core::trust::remote::dbus::Agent::Stub::Stub(const core::trust::remote::dbus::Agent::Stub::Configuration& configuration)
24 : agent_registry_skeleton25 : agent_registry_skeleton
@@ -43,20 +44,31 @@
43 return agent->authenticate_request_with_parameters(parameters);44 return agent->authenticate_request_with_parameters(parameters);
44}45}
4546
46core::trust::remote::dbus::Agent::Skeleton::Skeleton(const core::trust::remote::dbus::Agent::Skeleton::Configuration& configuration)47core::trust::remote::dbus::Agent::Skeleton::Skeleton(core::trust::remote::dbus::Agent::Skeleton::Configuration configuration)
47 : core::trust::remote::Agent::Skeleton{configuration.impl},48 : core::trust::remote::Agent::Skeleton{configuration.impl},
49 config(std::move(configuration)),
48 agent_registry_stub50 agent_registry_stub
49 {51 {
50 core::trust::dbus::AgentRegistry::Stub::Configuration52 core::trust::dbus::AgentRegistry::Stub::create(
51 {53 core::trust::dbus::AgentRegistry::Stub::Configuration
52 configuration.agent_registry_object,54 {
53 core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(),55 config.agent_registry_object,
54 configuration.service,56 core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(),
55 configuration.bus57 config.service,
56 }58 config.bus
59 })
57 }60 }
58{61{
59 agent_registry_stub.register_agent_for_user(core::trust::Uid{::getuid()}, configuration.impl);62 static const auto printing_cb = []() { std::cout << "Successfully registered agent for user." << std::endl; };
63
64 agent_registry_stub->register_agent_for_user_async(core::trust::Uid{::getuid()}, config.impl, printing_cb);
65
66 // We don't have to track the lifetime of "this" as config.agent_registry_watcher is owned
67 // by "this".
68 config.agent_registry_watcher->service_registered().connect([this]()
69 {
70 agent_registry_stub->register_agent_for_user_async(core::trust::Uid{::getuid()}, config.impl, printing_cb);
71 });
60}72}
6173
62core::trust::Request::Answer core::trust::remote::dbus::Agent::Skeleton::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters)74core::trust::Request::Answer core::trust::remote::dbus::Agent::Skeleton::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters)
6375
=== modified file 'src/core/trust/remote/dbus.h'
--- src/core/trust/remote/dbus.h 2014-08-04 07:57:05 +0000
+++ src/core/trust/remote/dbus.h 2016-01-04 15:02:54 +0000
@@ -25,6 +25,8 @@
25#include <core/trust/dbus/agent.h>25#include <core/trust/dbus/agent.h>
26#include <core/trust/dbus/agent_registry.h>26#include <core/trust/dbus/agent_registry.h>
2727
28#include <core/dbus/service_watcher.h>
29
28#include <unistd.h>30#include <unistd.h>
29#include <sys/types.h>31#include <sys/types.h>
3032
@@ -86,6 +88,8 @@
86 std::shared_ptr<Agent> impl;88 std::shared_ptr<Agent> impl;
87 // The remote object implementing core.trust.dbus.AgentRegistry.89 // The remote object implementing core.trust.dbus.AgentRegistry.
88 core::dbus::Object::Ptr agent_registry_object;90 core::dbus::Object::Ptr agent_registry_object;
91 // The watcher monitoring the remote object implementing core.trust.dbus.AgentRegistry.
92 std::unique_ptr<core::dbus::ServiceWatcher> agent_registry_watcher;
89 // The service that objects implementing core.trust.dbus.Agent should be added to.93 // The service that objects implementing core.trust.dbus.Agent should be added to.
90 core::dbus::Service::Ptr service;94 core::dbus::Service::Ptr service;
91 // The underlying bus instance.95 // The underlying bus instance.
@@ -95,13 +99,15 @@
95 };99 };
96100
97 // Constructs a new Skeleton instance, installing impl for handling actual requests.101 // Constructs a new Skeleton instance, installing impl for handling actual requests.
98 Skeleton(const Configuration& configuration);102 Skeleton(Configuration configuration);
99103
100 // From core::trust::Agent, dispatches to the actual implementation.104 // From core::trust::Agent, dispatches to the actual implementation.
101 core::trust::Request::Answer authenticate_request_with_parameters(const RequestParameters& parameters);105 core::trust::Request::Answer authenticate_request_with_parameters(const RequestParameters& parameters);
102106
107 // Store all creation-time parameters.
108 Configuration config;
103 // Stub for accessing the remote agent registry.109 // Stub for accessing the remote agent registry.
104 core::trust::dbus::AgentRegistry::Stub agent_registry_stub;110 std::shared_ptr<core::trust::dbus::AgentRegistry::Stub> agent_registry_stub;
105 };111 };
106};112};
107}113}
108114
=== added file 'src/core/trust/runtime.cpp'
--- src/core/trust/runtime.cpp 1970-01-01 00:00:00 +0000
+++ src/core/trust/runtime.cpp 2016-01-04 15:02:54 +0000
@@ -0,0 +1,105 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#include <core/trust/runtime.h>
20
21#include <core/dbus/asio/executor.h>
22
23#include <iostream>
24#include <stdexcept>
25
26namespace
27{
28void execute_and_never_throw(boost::asio::io_service& ios) noexcept(true)
29{
30 while (true)
31 {
32 try
33 {
34 ios.run();
35 break;
36 }
37 catch (const std::exception& e)
38 {
39 std::cerr << __PRETTY_FUNCTION__ << ": " << e.what() << std::endl;
40 }
41 catch (...)
42 {
43 std::cerr << __PRETTY_FUNCTION__ << ": unknown exception" << std::endl;
44 }
45 }
46}
47}
48
49core::trust::Runtime& core::trust::Runtime::instance()
50{
51 static Runtime runtime;
52 return runtime;
53}
54
55core::trust::Runtime::Runtime()
56 : signal_trap{core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term, core::posix::Signal::sig_int})},
57 keep_alive{io_service}
58{
59 for (std::size_t i = 0; i < Runtime::concurrency_hint; i++)
60 {
61 pool.emplace_back(execute_and_never_throw, std::ref(io_service));
62 }
63
64 signal_trap->signal_raised().connect([this](const core::posix::Signal&)
65 {
66 stop();
67 });
68}
69
70core::trust::Runtime::~Runtime()
71{
72 try
73 {
74 io_service.stop();
75
76 for (auto& worker : pool)
77 if (worker.joinable())
78 worker.join();
79 }
80 catch (...)
81 {
82 // Empty on purpose. We just have to
83 // fulfill the noexcept(true) guarantee.
84 }
85}
86
87void core::trust::Runtime::run()
88{
89 signal_trap->run();
90}
91
92void core::trust::Runtime::stop()
93{
94 signal_trap->stop();
95}
96
97boost::asio::io_service& core::trust::Runtime::service()
98{
99 return io_service;
100}
101
102core::dbus::Executor::Ptr core::trust::Runtime::make_executor_for_bus(const core::dbus::Bus::Ptr& bus)
103{
104 return core::dbus::asio::make_executor(bus, io_service);
105}
0106
=== added file 'src/core/trust/runtime.h'
--- src/core/trust/runtime.h 1970-01-01 00:00:00 +0000
+++ src/core/trust/runtime.h 2016-01-04 15:02:54 +0000
@@ -0,0 +1,88 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#ifndef CORE_TRUST_RUNTIME_H_
20#define CORE_TRUST_RUNTIME_H_
21
22#include <core/posix/signal.h>
23
24#include <core/dbus/bus.h>
25#include <core/dbus/executor.h>
26
27#include <boost/asio.hpp>
28
29#include <memory>
30#include <thread>
31#include <vector>
32
33namespace core
34{
35namespace trust
36{
37// A Runtime maintains a pool of workers enabling
38// implementations to dispatch invocations and have their
39// ready handlers automatically executed.
40class Runtime
41{
42public:
43 // Do not execute in parallel, serialize
44 // accesses.
45 static constexpr std::size_t concurrency_hint{2};
46
47 // Our evil singleton pattern. Not bad though, we control the
48 // entire executable and rely on automatic cleanup of static
49 // instances.
50 static Runtime& instance();
51
52 // Gracefully shuts down operations.
53 ~Runtime() noexcept(true);
54
55 // run blocks until either stop is called or a
56 // signal requesting graceful shutdown is received.
57 void run();
58
59 // requests the runtime to shut down, does not block.
60 void stop();
61
62 // Returns a mutable reference to the underlying boost::asio::io_service
63 // powering the runtime's reactor.
64 boost::asio::io_service& service();
65
66 // Creates an executor for a bus instance hooking into this Runtime instance.
67 core::dbus::Executor::Ptr make_executor_for_bus(const core::dbus::Bus::Ptr& bus);
68
69private:
70 Runtime();
71
72 // We trap sig term to ensure a clean shutdown.
73 std::shared_ptr<core::posix::SignalTrap> signal_trap;
74
75 // Our io_service instance exposed to remote agents.
76 boost::asio::io_service io_service;
77
78 // We keep the io_service alive and introduce some artificial
79 // work.
80 boost::asio::io_service::work keep_alive;
81
82 // We execute the io_service on a pool of worker threads.
83 std::vector<std::thread> pool;
84};
85}
86}
87
88#endif // CORE_TRUST_RUNTIME_H_
089
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2014-11-14 12:17:24 +0000
+++ tests/CMakeLists.txt 2016-01-04 15:02:54 +0000
@@ -46,6 +46,9 @@
46add_executable(46add_executable(
47 remote_agent_test47 remote_agent_test
48 remote_agent_test.cpp48 remote_agent_test.cpp
49
50 ${CMAKE_SOURCE_DIR}/src/core/trust/runtime.h
51 ${CMAKE_SOURCE_DIR}/src/core/trust/runtime.cpp
49)52)
5053
51add_executable(54add_executable(
5255
=== modified file 'tests/dbus_test.cpp'
--- tests/dbus_test.cpp 2014-08-04 08:32:57 +0000
+++ tests/dbus_test.cpp 2016-01-04 15:02:54 +0000
@@ -370,21 +370,19 @@
370 InvokeWithoutArgs(&state, &State::notify),370 InvokeWithoutArgs(&state, &State::notify),
371 Return(core::trust::Request::Answer::denied)));371 Return(core::trust::Request::Answer::denied)));
372372
373 core::trust::dbus::AgentRegistry::Stub stub373 auto stub = core::trust::dbus::AgentRegistry::Stub::create(
374 {
375 core::trust::dbus::AgentRegistry::Stub::Configuration374 core::trust::dbus::AgentRegistry::Stub::Configuration
376 {375 {
377 agent_registry_object,376 agent_registry_object,
378 core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(),377 core::trust::dbus::AgentRegistry::Stub::counting_object_path_generator(),
379 service,378 service,
380 bus379 bus
381 }380 });
382 };
383381
384 std::thread t{[bus]() { bus->run(); }};382 std::thread t{[bus]() { bus->run(); }};
385383
386 // We register for the current user id.384 // We register for the current user id.
387 stub.register_agent_for_user(core::trust::Uid{::getuid()}, agent);385 stub->register_agent_for_user(core::trust::Uid{::getuid()}, agent);
388386
389 // Tell the other side that we are good to go.387 // Tell the other side that we are good to go.
390 agent_registered.try_signal_ready_for(std::chrono::milliseconds{500});388 agent_registered.try_signal_ready_for(std::chrono::milliseconds{500});
@@ -393,7 +391,7 @@
393 state.wait();391 state.wait();
394392
395 // And unregister again.393 // And unregister again.
396 stub.unregister_agent_for_user(core::trust::Uid{::getuid()});394 stub->unregister_agent_for_user(core::trust::Uid{::getuid()});
397395
398 bus->stop();396 bus->stop();
399397
400398
=== modified file 'tests/remote_agent_test.cpp'
--- tests/remote_agent_test.cpp 2015-08-14 09:53:12 +0000
+++ tests/remote_agent_test.cpp 2016-01-04 15:02:54 +0000
@@ -30,6 +30,8 @@
30#include <core/dbus/asio/executor.h>30#include <core/dbus/asio/executor.h>
31#include <core/dbus/fixture.h>31#include <core/dbus/fixture.h>
3232
33#include <core/trust/runtime.h>
34
33#include <gmock/gmock.h>35#include <gmock/gmock.h>
34#include <gtest/gtest.h>36#include <gtest/gtest.h>
3537
@@ -792,6 +794,12 @@
792{794{
793struct DBus : public core::dbus::testing::Fixture795struct DBus : public core::dbus::testing::Fixture
794{796{
797 core::dbus::Bus::Ptr session_bus_with_executor()
798 {
799 auto sb = session_bus();
800 sb->install_executor(core::trust::Runtime::instance().make_executor_for_bus(sb));
801 return sb;
802 }
795};803};
796804
797std::string service_name805std::string service_name
@@ -804,10 +812,6 @@
804{812{
805 using namespace ::testing;813 using namespace ::testing;
806814
807 core::testing::CrossProcessSync
808 stub_ready, // signals stub --| I'm ready |--> skeleton
809 skeleton_ready; // signals skeleton --| I'm ready |--> stub
810
811 auto app = core::posix::fork([]()815 auto app = core::posix::fork([]()
812 {816 {
813 while(true) std::this_thread::sleep_for(std::chrono::milliseconds{500});817 while(true) std::this_thread::sleep_for(std::chrono::milliseconds{500});
@@ -825,7 +829,50 @@
825 const core::trust::Uid app_uid{::getuid()};829 const core::trust::Uid app_uid{::getuid()};
826 const core::trust::Pid app_pid{app.pid()};830 const core::trust::Pid app_pid{app.pid()};
827831
828 auto stub = core::posix::fork([this, app_uid, app_pid, answer, &stub_ready, &skeleton_ready]()832 auto skeleton = core::posix::fork([this, answer]()
833 {
834 auto bus = session_bus_with_executor();
835
836 // We have to rely on a MockAgent to break the dependency on a running Mir instance.
837 auto mock_agent = std::make_shared<::testing::NiceMock<MockAgent>>();
838
839 ON_CALL(*mock_agent, authenticate_request_with_parameters(_))
840 .WillByDefault(Return(answer));
841
842 std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name;
843
844 auto service = core::dbus::Service::use_service(bus, dbus_service_name);
845 auto object = service->object_for_path(core::dbus::types::ObjectPath
846 {
847 core::trust::remote::dbus::default_agent_registry_path
848 });
849
850 core::dbus::DBus daemon{bus};
851
852 core::trust::remote::dbus::Agent::Skeleton::Configuration config
853 {
854 mock_agent,
855 object,
856 daemon.make_service_watcher(dbus_service_name),
857 service,
858 bus,
859 core::trust::remote::helpers::aa_get_task_con_app_id_resolver()
860 };
861
862 auto skeleton = std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(std::move(config));
863
864 core::trust::Runtime::instance().run();
865 return core::posix::exit::Status::success;
866 }, core::posix::StandardStream::empty);
867
868
869 // stubf models a trusted helper, with the following simplified
870 // mode of operation:
871 // (1.) Helper claims its unique name on the bus.
872 // (2.) Helper installs an AgentRegistry::Skeleton.
873 // (3.) Helper learns about per-user trust::Agent instances on the bus.
874 // (4.) Helper issues requests for authentication.
875 auto stubf = [this, app_uid, app_pid, answer]()
829 {876 {
830 core::trust::Agent::RequestParameters ref_params877 core::trust::Agent::RequestParameters ref_params
831 {878 {
@@ -836,10 +883,7 @@
836 "just an example description"883 "just an example description"
837 };884 };
838885
839 auto bus = session_bus();886 auto bus = session_bus_with_executor();
840 bus->install_executor(core::dbus::asio::make_executor(bus));
841
842 std::thread worker{[bus]() { bus->run(); }};
843887
844 std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name;888 std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name;
845889
@@ -857,76 +901,24 @@
857901
858 auto stub = std::make_shared<core::trust::remote::dbus::Agent::Stub>(config);902 auto stub = std::make_shared<core::trust::remote::dbus::Agent::Stub>(config);
859903
860 stub_ready.try_signal_ready_for(std::chrono::milliseconds{1000});904 std::this_thread::sleep_for(std::chrono::seconds(10));
861 skeleton_ready.wait_for_signal_ready_for(std::chrono::milliseconds{1000});
862905
863 for (unsigned int i = 0; i < 100; i++)906 for (unsigned int i = 0; i < 100; i++)
864 EXPECT_EQ(answer, stub->authenticate_request_with_parameters(ref_params));907 EXPECT_EQ(answer, stub->authenticate_request_with_parameters(ref_params));
865908
866 bus->stop();
867
868 if (worker.joinable())
869 worker.join();
870
871 return Test::HasFailure() ?909 return Test::HasFailure() ?
872 core::posix::exit::Status::failure :910 core::posix::exit::Status::failure :
873 core::posix::exit::Status::success;911 core::posix::exit::Status::success;
874 }, core::posix::StandardStream::empty);912 };
875913
876 auto skeleton = core::posix::fork([this, answer, &stub_ready, &skeleton_ready]()914 std::this_thread::sleep_for(std::chrono::seconds(2));
877 {915 auto stub = core::posix::fork(stubf, core::posix::StandardStream::empty);
878 auto trap = core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term});916 EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced)));
879917
880 trap->signal_raised().connect([trap](core::posix::Signal)918 std::this_thread::sleep_for(std::chrono::seconds(2));
881 {919 stub = core::posix::fork(stubf, core::posix::StandardStream::empty);
882 trap->stop();920 EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced)));
883 });921
884
885 auto bus = session_bus();
886 bus->install_executor(core::dbus::asio::make_executor(bus));
887
888 std::thread worker{[bus]() { bus->run(); }};
889
890 // We have to rely on a MockAgent to break the dependency on a running Mir instance.
891 auto mock_agent = std::make_shared<::testing::NiceMock<MockAgent>>();
892
893 ON_CALL(*mock_agent, authenticate_request_with_parameters(_))
894 .WillByDefault(Return(answer));
895
896 std::string dbus_service_name = core::trust::remote::dbus::default_service_name_prefix + std::string{"."} + service_name;
897
898 stub_ready.wait_for_signal_ready_for(std::chrono::milliseconds{1000});
899
900 auto service = core::dbus::Service::use_service(bus, dbus_service_name);
901 auto object = service->object_for_path(core::dbus::types::ObjectPath
902 {
903 core::trust::remote::dbus::default_agent_registry_path
904 });
905
906 core::trust::remote::dbus::Agent::Skeleton::Configuration config
907 {
908 mock_agent,
909 object,
910 service,
911 bus,
912 core::trust::remote::helpers::aa_get_task_con_app_id_resolver()
913 };
914
915 auto skeleton = std::make_shared<core::trust::remote::dbus::Agent::Skeleton>(config);
916
917 skeleton_ready.try_signal_ready_for(std::chrono::milliseconds{1000});
918
919 trap->run();
920
921 bus->stop();
922
923 if (worker.joinable())
924 worker.join();
925
926 return core::posix::exit::Status::success;
927 }, core::posix::StandardStream::empty);
928
929 EXPECT_TRUE(ProcessExitedSuccessfully(stub.wait_for(core::posix::wait::Flags::untraced)));
930 skeleton.send_signal_or_throw(core::posix::Signal::sig_term);922 skeleton.send_signal_or_throw(core::posix::Signal::sig_term);
931 EXPECT_TRUE(ProcessExitedSuccessfully(skeleton.wait_for(core::posix::wait::Flags::untraced)));923 EXPECT_TRUE(ProcessExitedSuccessfully(skeleton.wait_for(core::posix::wait::Flags::untraced)));
932924

Subscribers

People subscribed via source and target branches