149aefb31SBrad Bishop /**
249aefb31SBrad Bishop  * Copyright © 2016 IBM Corporation
349aefb31SBrad Bishop  *
449aefb31SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
549aefb31SBrad Bishop  * you may not use this file except in compliance with the License.
649aefb31SBrad Bishop  * You may obtain a copy of the License at
749aefb31SBrad Bishop  *
849aefb31SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
949aefb31SBrad Bishop  *
1049aefb31SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
1149aefb31SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
1249aefb31SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349aefb31SBrad Bishop  * See the License for the specific language governing permissions and
1449aefb31SBrad Bishop  * limitations under the License.
1549aefb31SBrad Bishop  */
1649aefb31SBrad Bishop #include <iostream>
1749aefb31SBrad Bishop #include <exception>
18*24424983SBrad Bishop #include <chrono>
1949aefb31SBrad Bishop #include "manager.hpp"
2049aefb31SBrad Bishop 
21*24424983SBrad Bishop using namespace std::literals::chrono_literals;
22*24424983SBrad Bishop 
2349aefb31SBrad Bishop namespace phosphor
2449aefb31SBrad Bishop {
2549aefb31SBrad Bishop namespace inventory
2649aefb31SBrad Bishop {
2749aefb31SBrad Bishop namespace manager
2849aefb31SBrad Bishop {
2949aefb31SBrad Bishop namespace details
3049aefb31SBrad Bishop {
3149aefb31SBrad Bishop 
3249aefb31SBrad Bishop /** @brief Fowrarding signal callback.
3349aefb31SBrad Bishop  *
3449aefb31SBrad Bishop  *  Extracts per-signal specific context and forwards the call to the manager
3549aefb31SBrad Bishop  *  instance.
3649aefb31SBrad Bishop  */
3749aefb31SBrad Bishop auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
3849aefb31SBrad Bishop {
397b33777bSBrad Bishop     try
407b33777bSBrad Bishop     {
4149aefb31SBrad Bishop         auto msg = sdbusplus::message::message(m);
4249aefb31SBrad Bishop         auto& args = *static_cast<Manager::SigArg*>(data);
4349aefb31SBrad Bishop         sd_bus_message_ref(m);
4449aefb31SBrad Bishop         auto& mgr = *std::get<0>(args);
4568c80839SBrad Bishop         mgr.signal(
4668c80839SBrad Bishop             msg,
4768c80839SBrad Bishop             static_cast<const details::DbusSignal&>(
4868c80839SBrad Bishop                 *std::get<1>(args)),
4968c80839SBrad Bishop             *std::get<2>(args));
5049aefb31SBrad Bishop     }
517b33777bSBrad Bishop     catch (const std::exception& e)
527b33777bSBrad Bishop     {
5349aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
5449aefb31SBrad Bishop     }
5549aefb31SBrad Bishop 
5649aefb31SBrad Bishop     return 0;
5749aefb31SBrad Bishop }
5849aefb31SBrad Bishop 
5949aefb31SBrad Bishop } // namespace details
6049aefb31SBrad Bishop 
6149aefb31SBrad Bishop Manager::Manager(
6249aefb31SBrad Bishop     sdbusplus::bus::bus&& bus,
6349aefb31SBrad Bishop     const char* busname,
6449aefb31SBrad Bishop     const char* root,
6549aefb31SBrad Bishop     const char* iface) :
66451f8d93SBrad Bishop     details::ServerObject<details::ManagerIface>(bus, root),
6749aefb31SBrad Bishop     _shutdown(false),
6849aefb31SBrad Bishop     _root(root),
6949aefb31SBrad Bishop     _bus(std::move(bus)),
7049aefb31SBrad Bishop     _manager(sdbusplus::server::manager::manager(_bus, root))
7149aefb31SBrad Bishop {
7268c80839SBrad Bishop     for (auto& group : _events)
7368c80839SBrad Bishop     {
7468c80839SBrad Bishop         for (auto pEvent : std::get<0>(group))
7568c80839SBrad Bishop         {
764f20a3e3SBrad Bishop             if (pEvent->type !=
774f20a3e3SBrad Bishop                 details::Event::Type::DBUS_SIGNAL)
787b33777bSBrad Bishop             {
794f20a3e3SBrad Bishop                 continue;
807b33777bSBrad Bishop             }
814f20a3e3SBrad Bishop 
8268c80839SBrad Bishop             // Create a callback context for this event group.
8368c80839SBrad Bishop             auto dbusEvent = static_cast<details::DbusSignal*>(
8468c80839SBrad Bishop                                  pEvent.get());
8568c80839SBrad Bishop 
8668c80839SBrad Bishop             // Go ahead and store an iterator pointing at
8768c80839SBrad Bishop             // the event data to avoid lookups later since
8868c80839SBrad Bishop             // additional signal callbacks aren't added
8968c80839SBrad Bishop             // after the manager is constructed.
9049aefb31SBrad Bishop             _sigargs.emplace_back(
9149aefb31SBrad Bishop                 std::make_unique<SigArg>(
9249aefb31SBrad Bishop                     this,
9368c80839SBrad Bishop                     dbusEvent,
941ab880a1SBrad Bishop                     &group));
9568c80839SBrad Bishop 
9649aefb31SBrad Bishop             // Register our callback and the context for
9768c80839SBrad Bishop             // each signal event.
9849aefb31SBrad Bishop             _matches.emplace_back(
9949aefb31SBrad Bishop                 _bus,
10068c80839SBrad Bishop                 std::get<0>(*dbusEvent),
10149aefb31SBrad Bishop                 details::_signal,
1021ab880a1SBrad Bishop                 _sigargs.back().get());
10349aefb31SBrad Bishop         }
10468c80839SBrad Bishop     }
10549aefb31SBrad Bishop 
10649aefb31SBrad Bishop     _bus.request_name(busname);
10749aefb31SBrad Bishop }
10849aefb31SBrad Bishop 
10949aefb31SBrad Bishop void Manager::shutdown() noexcept
11049aefb31SBrad Bishop {
11149aefb31SBrad Bishop     _shutdown = true;
11249aefb31SBrad Bishop }
11349aefb31SBrad Bishop 
11449aefb31SBrad Bishop void Manager::run() noexcept
11549aefb31SBrad Bishop {
1167b33777bSBrad Bishop     while (!_shutdown)
1177b33777bSBrad Bishop     {
1187b33777bSBrad Bishop         try
1197b33777bSBrad Bishop         {
12049aefb31SBrad Bishop             _bus.process_discard();
121*24424983SBrad Bishop             _bus.wait((5000000us).count());
12249aefb31SBrad Bishop         }
1237b33777bSBrad Bishop         catch (const std::exception& e)
1247b33777bSBrad Bishop         {
12549aefb31SBrad Bishop             std::cerr << e.what() << std::endl;
12649aefb31SBrad Bishop         }
12749aefb31SBrad Bishop     }
12849aefb31SBrad Bishop }
12949aefb31SBrad Bishop 
13049aefb31SBrad Bishop void Manager::notify(std::string path, Object object)
13149aefb31SBrad Bishop {
1327b33777bSBrad Bishop     try
1337b33777bSBrad Bishop     {
13449aefb31SBrad Bishop         if (object.cbegin() == object.cend())
13549aefb31SBrad Bishop             throw std::runtime_error(
13649aefb31SBrad Bishop                 "No interfaces in " + path);
13749aefb31SBrad Bishop 
13849aefb31SBrad Bishop         path.insert(0, _root);
13949aefb31SBrad Bishop 
14049aefb31SBrad Bishop         auto obj = _refs.find(path);
14149aefb31SBrad Bishop         if (obj != _refs.end())
14249aefb31SBrad Bishop             throw std::runtime_error(
14349aefb31SBrad Bishop                 obj->first + " already exists");
14449aefb31SBrad Bishop 
14549aefb31SBrad Bishop         // Create an interface holder for each interface
14649aefb31SBrad Bishop         // provided by the client and group them into
14749aefb31SBrad Bishop         // a container.
14849aefb31SBrad Bishop         InterfaceComposite ref;
14949aefb31SBrad Bishop 
1507b33777bSBrad Bishop         for (auto& x : object)
1517b33777bSBrad Bishop         {
1525fbaa7feSBrad Bishop             auto maker = _makers.find(x.first.c_str());
15349aefb31SBrad Bishop 
1545fbaa7feSBrad Bishop             if (maker == _makers.end())
15549aefb31SBrad Bishop                 throw std::runtime_error(
15649aefb31SBrad Bishop                     "Unimplemented interface: " + x.first);
15749aefb31SBrad Bishop 
1581ab880a1SBrad Bishop             ref.emplace(x.first,
1591ab880a1SBrad Bishop                         (maker->second)(_bus, path.c_str()));
16049aefb31SBrad Bishop         }
16149aefb31SBrad Bishop 
16249aefb31SBrad Bishop         // Hang on to a reference to the object (interfaces)
16349aefb31SBrad Bishop         // so it stays on the bus, and so we can make calls
16449aefb31SBrad Bishop         // to it if needed.
16549aefb31SBrad Bishop         _refs.emplace(
1661ab880a1SBrad Bishop             path, std::move(ref));
16749aefb31SBrad Bishop     }
1687b33777bSBrad Bishop     catch (const std::exception& e)
1697b33777bSBrad Bishop     {
17049aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
17149aefb31SBrad Bishop     }
17249aefb31SBrad Bishop }
17349aefb31SBrad Bishop 
17468c80839SBrad Bishop void Manager::signal(
17568c80839SBrad Bishop     sdbusplus::message::message& msg,
17668c80839SBrad Bishop     const details::DbusSignal& event,
17768c80839SBrad Bishop     const EventInfo& info)
17849aefb31SBrad Bishop {
17968c80839SBrad Bishop     auto& filter = *std::get<1>(event);
18068c80839SBrad Bishop     auto& actions = std::get<1>(info);
1813d57f507SBrad Bishop 
1827b33777bSBrad Bishop     if (filter(msg, *this))
1837b33777bSBrad Bishop     {
1849007432aSBrad Bishop         for (auto& action : actions)
1857b33777bSBrad Bishop         {
1869007432aSBrad Bishop             (*action)(*this);
1873d57f507SBrad Bishop         }
18849aefb31SBrad Bishop     }
1897b33777bSBrad Bishop }
19049aefb31SBrad Bishop 
191656a7d00SBrad Bishop void Manager::destroyObject(const char* path)
192656a7d00SBrad Bishop {
193656a7d00SBrad Bishop     std::string p{path};
194656a7d00SBrad Bishop     _refs.erase(_root + p);
195656a7d00SBrad Bishop }
196656a7d00SBrad Bishop 
197b83a21eaSBrad Bishop details::holder::Base& Manager::getInterfaceHolder(
198b83a21eaSBrad Bishop     const char* path, const char* interface)
199b83a21eaSBrad Bishop {
200b83a21eaSBrad Bishop     return const_cast<const Manager*>(
201b83a21eaSBrad Bishop                this)->getInterfaceHolder(path, interface);
202b83a21eaSBrad Bishop }
203b83a21eaSBrad Bishop 
204b83a21eaSBrad Bishop details::holder::Base& Manager::getInterfaceHolder(
205b83a21eaSBrad Bishop     const char* path, const char* interface) const
206b83a21eaSBrad Bishop {
207b83a21eaSBrad Bishop     std::string p{path};
208b83a21eaSBrad Bishop     auto oit = _refs.find(_root + p);
209b83a21eaSBrad Bishop     if (oit == _refs.end())
210b83a21eaSBrad Bishop         throw std::runtime_error(
211b83a21eaSBrad Bishop             _root + p + " was not found");
212b83a21eaSBrad Bishop 
213b83a21eaSBrad Bishop     auto& obj = oit->second;
214b83a21eaSBrad Bishop     auto iit = obj.find(interface);
215b83a21eaSBrad Bishop     if (iit == obj.end())
216b83a21eaSBrad Bishop         throw std::runtime_error(
217b83a21eaSBrad Bishop             "interface was not found");
218b83a21eaSBrad Bishop 
219b83a21eaSBrad Bishop     return *iit->second;
220b83a21eaSBrad Bishop }
221b83a21eaSBrad Bishop 
22249aefb31SBrad Bishop } // namespace manager
22349aefb31SBrad Bishop } // namespace inventory
22449aefb31SBrad Bishop } // namespace phosphor
22549aefb31SBrad Bishop 
22649aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
227