summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interfaces/mount_point_state_machine.hpp9
-rw-r--r--src/state/activating_state.cpp3
-rw-r--r--src/state/active_state.hpp15
-rw-r--r--src/state/deactivating_state.hpp5
-rw-r--r--src/state/initial_state.hpp146
-rw-r--r--src/state/ready_state.hpp7
-rw-r--r--src/state_machine.hpp48
-rw-r--r--src/utils.hpp81
8 files changed, 186 insertions, 128 deletions
diff --git a/src/interfaces/mount_point_state_machine.hpp b/src/interfaces/mount_point_state_machine.hpp
index db521fb..e6b175c 100644
--- a/src/interfaces/mount_point_state_machine.hpp
+++ b/src/interfaces/mount_point_state_machine.hpp
@@ -3,6 +3,8 @@
#include "configuration.hpp"
#include "resources.hpp"
+#include <system_error>
+
struct BasicState;
namespace interfaces
@@ -20,6 +22,13 @@ struct MountPointStateMachine
virtual ~MountPointStateMachine() = default;
+ virtual void notify(const std::error_code& ec = {}) = 0;
+ virtual void notificationStart() = 0;
+ virtual void
+ notificationInitialize(std::shared_ptr<sdbusplus::asio::connection> con,
+ const std::string& svc, const std::string& iface,
+ const std::string& name) = 0;
+
virtual std::string_view getName() const = 0;
virtual Configuration::MountPoint& getConfig() = 0;
virtual std::optional<Target>& getTarget() = 0;
diff --git a/src/state/activating_state.cpp b/src/state/activating_state.cpp
index c22174f..7143545 100644
--- a/src/state/activating_state.cpp
+++ b/src/state/activating_state.cpp
@@ -54,7 +54,8 @@ std::unique_ptr<BasicState> ActivatingState::handleEvent([
[maybe_unused]] SubprocessStoppedEvent event)
{
LogMsg(Logger::Error, "Process ended prematurely");
- return std::make_unique<ReadyState>(machine);
+ return std::make_unique<ReadyState>(machine, std::errc::connection_refused,
+ "Process ended prematurely");
}
std::unique_ptr<BasicState> ActivatingState::activateProxyMode()
diff --git a/src/state/active_state.hpp b/src/state/active_state.hpp
index a204dc3..beb1da1 100644
--- a/src/state/active_state.hpp
+++ b/src/state/active_state.hpp
@@ -14,7 +14,10 @@ struct ActiveState : public BasicStateT<ActiveState>
std::unique_ptr<resource::Process> process,
std::unique_ptr<resource::Gadget> gadget) :
BasicStateT(machine),
- process(std::move(process)), gadget(std::move(gadget)){};
+ process(std::move(process)), gadget(std::move(gadget))
+ {
+ machine.notify();
+ };
virtual std::unique_ptr<BasicState> onEnter()
{
@@ -43,12 +46,9 @@ struct ActiveState : public BasicStateT<ActiveState>
Configuration::inactivityTimeout.count(),
"s) - Unmounting");
// unmount media & stop retriggering timer
- boost::asio::spawn(
- machine.getIoc(),
- [&machine = machine](
- [[maybe_unused]] boost::asio::yield_context yield) {
- machine.emitUnmountEvent();
- });
+ boost::asio::post(machine.getIoc(), [&machine = machine]() {
+ machine.emitUnmountEvent();
+ });
return;
}
else
@@ -80,6 +80,7 @@ struct ActiveState : public BasicStateT<ActiveState>
std::unique_ptr<BasicState> handleEvent([[maybe_unused]] UnmountEvent event)
{
+ machine.notificationStart();
return std::make_unique<DeactivatingState>(machine, std::move(process),
std::move(gadget));
}
diff --git a/src/state/deactivating_state.hpp b/src/state/deactivating_state.hpp
index 57f1072..472b6f1 100644
--- a/src/state/deactivating_state.hpp
+++ b/src/state/deactivating_state.hpp
@@ -64,14 +64,17 @@ struct DeactivatingState : public BasicStateT<DeactivatingState>
{
LogMsg(Logger::Info, machine.getName(),
" udev StateChange::removed");
+ return std::make_unique<ReadyState>(machine);
}
else
{
LogMsg(Logger::Error, machine.getName(), " udev StateChange::",
static_cast<std::underlying_type_t<StateChange>>(
udevStateChangeEvent->devState));
+ return std::make_unique<ReadyState>(
+ machine, std::errc::connection_refused,
+ "Not expected udev state");
}
- return std::make_unique<ReadyState>(machine);
}
return nullptr;
}
diff --git a/src/state/initial_state.hpp b/src/state/initial_state.hpp
index 324f456..f9255b0 100644
--- a/src/state/initial_state.hpp
+++ b/src/state/initial_state.hpp
@@ -1,7 +1,13 @@
#include "active_state.hpp"
#include "basic_state.hpp"
+#include "logger.hpp"
#include "ready_state.hpp"
+#include <sys/mount.h>
+
+#include <memory>
+#include <sdbusplus/asio/connection.hpp>
+#include <string>
#include <system_error>
struct InitialState : public BasicStateT<InitialState>
@@ -200,85 +206,18 @@ struct InitialState : public BasicStateT<InitialState>
auto iface = event.objServer->add_interface(path, name);
- const auto timerPeriod = std::chrono::milliseconds(100);
- const auto duration = std::chrono::seconds(
- machine.getConfig().timeout.value_or(
- Configuration::MountPoint::defaultTimeout) +
- 5);
- const auto waitCnt =
- std::chrono::duration_cast<std::chrono::milliseconds>(duration) /
- timerPeriod;
- LogMsg(Logger::Debug, "[App] waitCnt == ", waitCnt);
+ iface->register_signal<int32_t>("Completion");
+ machine.notificationInitialize(event.bus, path, name, "Completion");
// Common unmount
- iface->register_method(
- "Unmount", [&machine = machine, waitCnt,
- timerPeriod](boost::asio::yield_context yield) {
- LogMsg(Logger::Info, "[App]: Unmount called on ",
- machine.getName());
- machine.emitUnmountEvent();
-
- auto repeats = waitCnt;
- boost::asio::steady_timer timer(machine.getIoc());
- while (repeats > 0)
- {
- if (machine.getState().get_if<ReadyState>())
- {
- LogMsg(Logger::Debug, "[App] Unmount ok");
- return true;
- }
- boost::system::error_code ignored_ec;
- timer.expires_from_now(timerPeriod);
- timer.async_wait(yield[ignored_ec]);
- repeats--;
- }
- LogMsg(Logger::Error,
- "[App] timedout when waiting for ReadyState");
- throw sdbusplus::exception::SdBusError(EBUSY,
- "Resource is busy");
- return false;
- });
+ iface->register_method("Unmount", [&machine = machine]() {
+ LogMsg(Logger::Info, "[App]: Unmount called on ",
+ machine.getName());
- // Common mount
- const auto handleMount =
- [waitCnt, timerPeriod](
- boost::asio::yield_context yield,
- interfaces::MountPointStateMachine& machine,
- std::optional<interfaces::MountPointStateMachine::Target>
- target) {
- machine.emitMountEvent(std::move(target));
-
- auto repeats = waitCnt;
- boost::asio::steady_timer timer(machine.getIoc());
- while (repeats > 0)
- {
- if (auto s = machine.getState().get_if<ReadyState>())
- {
- if (s->error)
- {
- throw sdbusplus::exception::SdBusError(
- static_cast<int>(s->error->code),
- s->error->message.c_str());
- }
- LogMsg(Logger::Error, "[App] Mount failed");
- return false;
- }
- if (machine.getState().get_if<ActiveState>())
- {
- LogMsg(Logger::Info, "[App] Mount ok");
- return true;
- }
- boost::system::error_code ignored_ec;
- timer.expires_from_now(timerPeriod);
- timer.async_wait(yield[ignored_ec]);
- repeats--;
- }
- LogMsg(Logger::Error,
- "[App] timedout when waiting for ActiveState");
- throw sdbusplus::exception::SdBusError(EBUSY,
- "Resource is busy");
- return false;
- };
+ machine.emitUnmountEvent();
+
+ return true;
+ });
// Mount specialization
if (isLegacy)
@@ -287,9 +226,9 @@ struct InitialState : public BasicStateT<InitialState>
using optional_fd = std::variant<int, unix_fd>;
iface->register_method(
- "Mount", [&machine = machine, handleMount](
- boost::asio::yield_context yield,
- std::string imgUrl, bool rw, optional_fd fd) {
+ "Mount", [&machine = machine](boost::asio::yield_context yield,
+ std::string imgUrl, bool rw,
+ optional_fd fd) {
LogMsg(Logger::Info, "[App]: Mount called on ",
getObjectPath(machine), machine.getName());
@@ -333,48 +272,21 @@ struct InitialState : public BasicStateT<InitialState>
utils::secureCleanup(buf);
}
- try
- {
- auto ret =
- handleMount(yield, machine, std::move(target));
- if (machine.getTarget())
- {
- machine.getTarget()->credentials.reset();
- }
- LogMsg(Logger::Info, "[App]: mount completed ", ret);
- return ret;
- }
- catch (const std::exception& e)
- {
- LogMsg(Logger::Error, e.what());
- if (machine.getTarget())
- {
- machine.getTarget()->credentials.reset();
- }
- throw;
- return false;
- }
- catch (...)
- {
- if (machine.getTarget())
- {
- machine.getTarget()->credentials.reset();
- }
- throw;
- return false;
- }
+ machine.emitMountEvent(std::move(target));
+
+ return true;
});
}
- else
+ else // proxy
{
- iface->register_method(
- "Mount", [&machine = machine,
- handleMount](boost::asio::yield_context yield) {
- LogMsg(Logger::Info, "[App]: Mount called on ",
- getObjectPath(machine), machine.getName());
+ iface->register_method("Mount", [&machine = machine]() mutable {
+ LogMsg(Logger::Info, "[App]: Mount called on ",
+ getObjectPath(machine), machine.getName());
- return handleMount(yield, machine, std::nullopt);
- });
+ machine.emitMountEvent(std::nullopt);
+
+ return true;
+ });
}
iface->initialize();
diff --git a/src/state/ready_state.hpp b/src/state/ready_state.hpp
index bf1e160..e20e700 100644
--- a/src/state/ready_state.hpp
+++ b/src/state/ready_state.hpp
@@ -24,7 +24,10 @@ struct ReadyState : public BasicStateT<ReadyState>
};
ReadyState(interfaces::MountPointStateMachine& machine) :
- BasicStateT(machine){};
+ BasicStateT(machine)
+ {
+ machine.notify();
+ };
ReadyState(interfaces::MountPointStateMachine& machine, const std::errc& ec,
const std::string& message) :
@@ -33,6 +36,7 @@ struct ReadyState : public BasicStateT<ReadyState>
{
LogMsg(Logger::Error, machine.getName(),
" Errno = ", static_cast<int>(ec), " : ", message);
+ machine.notify(std::make_error_code(ec));
}
std::unique_ptr<BasicState> onEnter() override
@@ -47,6 +51,7 @@ struct ReadyState : public BasicStateT<ReadyState>
std::unique_ptr<BasicState> handleEvent(MountEvent event)
{
+ machine.notificationStart();
if (event.target)
{
machine.getTarget() = std::move(event.target);
diff --git a/src/state_machine.hpp b/src/state_machine.hpp
index 259802c..d5f3265 100644
--- a/src/state_machine.hpp
+++ b/src/state_machine.hpp
@@ -1,10 +1,13 @@
#pragma once
-
#include "interfaces/mount_point_state_machine.hpp"
#include "state/initial_state.hpp"
+#include "utils.hpp"
+#include <boost/asio/steady_timer.hpp>
+#include <functional>
#include <memory>
#include <sdbusplus/asio/object_server.hpp>
+#include <system_error>
struct MountPointStateMachine : public interfaces::MountPointStateMachine
{
@@ -106,9 +109,52 @@ struct MountPointStateMachine : public interfaces::MountPointStateMachine
}
}
+ virtual void
+ notificationInitialize(std::shared_ptr<sdbusplus::asio::connection> con,
+ const std::string& svc, const std::string& iface,
+ const std::string& name) override
+ {
+ auto signal = std::make_unique<utils::SignalSender>(std::move(con), svc,
+ iface, name);
+
+ auto timer = std::make_unique<boost::asio::steady_timer>(ioc);
+
+ completionNotification = std::make_unique<utils::NotificationWrapper>(
+ std::move(signal), std::move(timer));
+ }
+ void notificationStart()
+ {
+ auto notificationHandler = [this](const boost::system::error_code& ec) {
+ if (ec == boost::system::errc::operation_canceled)
+ {
+ return;
+ }
+
+ LogMsg(Logger::Error,
+ "[App] timedout when waiting for target state");
+
+ completionNotification->notify(
+ std::make_error_code(std::errc::device_or_resource_busy));
+ };
+
+ LogMsg(Logger::Debug, "Started notification");
+ completionNotification->start(
+ std::move(notificationHandler),
+ std::chrono::seconds(
+ config.timeout.value_or(
+ Configuration::MountPoint::defaultTimeout) +
+ 5));
+ }
+
+ virtual void notify(const std::error_code& ec = {}) override
+ {
+ completionNotification->notify(ec);
+ }
+
boost::asio::io_context& ioc;
std::string name;
Configuration::MountPoint config;
+ std::unique_ptr<utils::NotificationWrapper> completionNotification;
std::optional<Target> target;
std::unique_ptr<BasicState> state = std::make_unique<InitialState>(*this);
diff --git a/src/utils.hpp b/src/utils.hpp
index 587cc41..db9f325 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -1,14 +1,19 @@
#pragma once
+#include "logger.hpp"
+
#include <unistd.h>
#include <algorithm>
+#include <boost/asio/steady_timer.hpp>
#include <boost/process/async_pipe.hpp>
#include <boost/type_traits/has_dereference.hpp>
#include <filesystem>
#include <memory>
+#include <optional>
#include <sdbusplus/asio/object_server.hpp>
#include <string>
+#include <system_error>
#include <vector>
namespace fs = std::filesystem;
@@ -281,4 +286,80 @@ class VolatileFile
std::string filePath;
const std::size_t size;
};
+
+class SignalSender
+{
+ public:
+ SignalSender(std::shared_ptr<sdbusplus::asio::connection> con,
+ const std::string& obj, const std::string& iface,
+ const std::string& name) :
+ con(con),
+ interface(iface), object(obj), name(name){};
+
+ SignalSender() = delete;
+ SignalSender(const SignalSender&) = delete;
+
+ void send(std::optional<const std::error_code> status)
+ {
+ auto msgSignal =
+ con->new_signal(object.c_str(), interface.c_str(), name.c_str());
+
+ msgSignal.append(status.value_or(std::error_code{}).value());
+ LogMsg(Logger::Debug, "Sending signal: Object: ", object,
+ ", Interface: ", interface, ", Name: ", name,
+ "Status: ", status.value_or(std::error_code{}).value());
+ msgSignal.signal_send();
+ }
+
+ private:
+ std::shared_ptr<sdbusplus::asio::connection> con;
+ std::string interface;
+ std::string object;
+ std::string name;
+};
+
+class NotificationWrapper
+{
+ public:
+ NotificationWrapper(std::unique_ptr<SignalSender> signal,
+ std::unique_ptr<boost::asio::steady_timer> timer) :
+ signal(std::move(signal)),
+ timer(std::move(timer))
+ {
+ }
+
+ void start(std::function<void(const boost::system::error_code&)>&& handler,
+ const std::chrono::seconds& duration)
+ {
+ LogMsg(Logger::Debug, "Notification initiated");
+ started = true;
+ timer->expires_from_now(duration);
+ timer->async_wait([this, handler{std::move(handler)}](
+ const boost::system::error_code& ec) {
+ started = false;
+ handler(ec);
+ });
+ }
+
+ void notify(const std::error_code& ec)
+ {
+ if (started)
+ {
+ timer->cancel();
+ if (ec)
+ signal->send((ec));
+ else
+ signal->send(std::nullopt);
+ started = false;
+ return;
+ }
+ LogMsg(Logger::Debug, "Notification(ec) supressed (not started)");
+ }
+
+ private:
+ std::unique_ptr<SignalSender> signal;
+ std::unique_ptr<boost::asio::steady_timer> timer;
+ bool started{false};
+};
+
} // namespace utils