blob: b9e8ace10f6f42ed430d6ac90b7ab12845a415f1 [file] [log] [blame]
/**
* Copyright © 2016 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <exception>
#include "manager.hpp"
namespace phosphor
{
namespace inventory
{
namespace manager
{
namespace details
{
/** @brief Fowrarding signal callback.
*
* Extracts per-signal specific context and forwards the call to the manager
* instance.
*/
auto _signal(sd_bus_message *m, void *data, sd_bus_error *e) noexcept
{
try {
auto msg = sdbusplus::message::message(m);
auto &args = *static_cast<Manager::SigArg*>(data);
sd_bus_message_ref(m);
auto &mgr = *std::get<0>(args);
mgr.signal(
msg,
static_cast<const details::DbusSignal &>(
*std::get<1>(args)),
*std::get<2>(args));
}
catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
} // namespace details
Manager::Manager(
sdbusplus::bus::bus &&bus,
const char *busname,
const char *root,
const char *iface) :
details::ServerObject<details::ManagerIface>(bus, root),
_shutdown(false),
_root(root),
_bus(std::move(bus)),
_manager(sdbusplus::server::manager::manager(_bus, root))
{
for (auto &group: _events)
{
for (auto pEvent: std::get<0>(group))
{
if (pEvent->type !=
details::Event::Type::DBUS_SIGNAL)
continue;
// Create a callback context for this event group.
auto dbusEvent = static_cast<details::DbusSignal *>(
pEvent.get());
// Go ahead and store an iterator pointing at
// the event data to avoid lookups later since
// additional signal callbacks aren't added
// after the manager is constructed.
_sigargs.emplace_back(
std::make_unique<SigArg>(
std::make_tuple(
this,
dbusEvent,
&group)));
// Register our callback and the context for
// each signal event.
_matches.emplace_back(
sdbusplus::server::match::match(
_bus,
std::get<0>(*dbusEvent),
details::_signal,
_sigargs.back().get()));
}
}
_bus.request_name(busname);
}
void Manager::shutdown() noexcept
{
_shutdown = true;
}
void Manager::run() noexcept
{
while(!_shutdown) {
try {
_bus.process_discard();
_bus.wait(5000000);
}
catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
}
void Manager::notify(std::string path, Object object)
{
try {
if(object.cbegin() == object.cend())
throw std::runtime_error(
"No interfaces in " + path);
path.insert(0, _root);
auto obj = _refs.find(path);
if(obj != _refs.end())
throw std::runtime_error(
obj->first + " already exists");
// Create an interface holder for each interface
// provided by the client and group them into
// a container.
InterfaceComposite ref;
for (auto &x: object) {
auto maker = _makers.find(x.first.c_str());
if(maker == _makers.end())
throw std::runtime_error(
"Unimplemented interface: " + x.first);
ref.emplace(
std::make_pair(
x.first,
(maker->second)(_bus, path.c_str())));
}
// Hang on to a reference to the object (interfaces)
// so it stays on the bus, and so we can make calls
// to it if needed.
_refs.emplace(
std::make_pair(
path, std::move(ref)));
}
catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
void Manager::signal(
sdbusplus::message::message &msg,
const details::DbusSignal &event,
const EventInfo &info)
{
auto &filter = *std::get<1>(event);
auto &actions = std::get<1>(info);
if(filter(msg, *this)) {
for (auto &action: actions)
(*action)(*this);
}
}
void Manager::destroyObject(const char *path)
{
std::string p{path};
_refs.erase(_root + p);
}
} // namespace manager
} // namespace inventory
} // namespace phosphor
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4