1 /**
2  * Copyright © 2016 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <iostream>
17 #include <exception>
18 #include "manager.hpp"
19 
20 namespace phosphor
21 {
22 namespace inventory
23 {
24 namespace manager
25 {
26 namespace details
27 {
28 
29 /** @brief Fowrarding signal callback.
30  *
31  *  Extracts per-signal specific context and forwards the call to the manager
32  *  instance.
33  */
34 auto _signal(sd_bus_message *m, void *data, sd_bus_error *e) noexcept
35 {
36     try {
37         auto msg = sdbusplus::message::message(m);
38         auto &args = *static_cast<Manager::SigArg*>(data);
39         sd_bus_message_ref(m);
40         auto &mgr = *std::get<0>(args);
41         mgr.signal(msg, *std::get<1>(args));
42     }
43     catch (const std::exception &e) {
44         std::cerr << e.what() << std::endl;
45     }
46 
47     return 0;
48 }
49 
50 } // namespace details
51 
52 Manager::Manager(
53         sdbusplus::bus::bus &&bus,
54         const char *busname,
55         const char *root,
56         const char *iface) :
57     details::ServerObject<details::ManagerIface>(bus, root),
58     _shutdown(false),
59     _root(root),
60     _bus(std::move(bus)),
61     _manager(sdbusplus::server::manager::manager(_bus, root))
62 {
63     for (auto &x: _events) {
64         // Create a callback context for each event.
65         _sigargs.emplace_back(
66                 std::make_unique<SigArg>(
67                     std::make_tuple(
68                         this,
69                         &x)));
70         // Register our callback and the context for
71         // each event.
72         _matches.emplace_back(
73                 sdbusplus::server::match::match(
74                     _bus,
75                     std::get<0>(x),
76                     details::_signal,
77                     _sigargs.back().get()));
78     }
79 
80     _bus.request_name(busname);
81 }
82 
83 void Manager::shutdown() noexcept
84 {
85     _shutdown = true;
86 }
87 
88 void Manager::run() noexcept
89 {
90     while(!_shutdown) {
91         try {
92             _bus.process_discard();
93             _bus.wait(5000000);
94         }
95         catch (const std::exception &e) {
96             std::cerr << e.what() << std::endl;
97         }
98     }
99 }
100 
101 void Manager::notify(std::string path, Object object)
102 {
103     try {
104         if(object.cbegin() == object.cend())
105             throw std::runtime_error(
106                     "No interfaces in " + path);
107 
108         path.insert(0, _root);
109 
110         auto obj = _refs.find(path);
111         if(obj != _refs.end())
112             throw std::runtime_error(
113                     obj->first + " already exists");
114 
115         // Create an interface holder for each interface
116         // provided by the client and group them into
117         // a container.
118         InterfaceComposite ref;
119 
120         for (auto &x: object) {
121             auto maker = _makers.find(x.first.c_str());
122 
123             if(maker == _makers.end())
124                 throw std::runtime_error(
125                         "Unimplemented interface: " + x.first);
126 
127             ref.emplace(
128                     std::make_pair(
129                         x.first,
130                         (maker->second)(_bus, path.c_str())));
131         }
132 
133         // Hang on to a reference to the object (interfaces)
134         // so it stays on the bus, and so we can make calls
135         // to it if needed.
136         _refs.emplace(
137                 std::make_pair(
138                     path, std::move(ref)));
139     }
140     catch (const std::exception &e) {
141         std::cerr << e.what() << std::endl;
142     }
143 }
144 
145 void Manager::signal(sdbusplus::message::message &msg, auto &args)
146 {
147     auto &filter = *std::get<1>(args);
148     auto &actions = std::get<2>(args);
149 
150     if(filter(msg, *this)) {
151         for (auto &action: actions)
152             (*action)(*this);
153     }
154 }
155 
156 void Manager::destroyObject(const char *path)
157 {
158     std::string p{path};
159     _refs.erase(_root + p);
160 }
161 
162 } // namespace manager
163 } // namespace inventory
164 } // namespace phosphor
165 
166 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
167