blob: ffde98ef48708694eab79af761e9f31d8b152ffe [file] [log] [blame]
Brad Bishop49aefb32016-10-19 11:54:14 -04001/**
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>
Brad Bishop24424982017-01-13 16:37:14 -050018#include <chrono>
Brad Bishop79ccaf72017-01-22 16:00:50 -050019#include <algorithm>
Saqib Khan101d8372017-02-20 15:36:11 -060020#include <phosphor-logging/log.hpp>
Brad Bishop49aefb32016-10-19 11:54:14 -040021#include "manager.hpp"
Brad Bishop79ccaf72017-01-22 16:00:50 -050022#include "errors.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040023
Brad Bishop24424982017-01-13 16:37:14 -050024using namespace std::literals::chrono_literals;
25
Brad Bishop49aefb32016-10-19 11:54:14 -040026namespace phosphor
27{
28namespace inventory
29{
30namespace manager
31{
Brad Bishop49aefb32016-10-19 11:54:14 -040032/** @brief Fowrarding signal callback.
33 *
34 * Extracts per-signal specific context and forwards the call to the manager
35 * instance.
36 */
Brad Bishop7b337772017-01-12 16:11:24 -050037auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
Brad Bishop49aefb32016-10-19 11:54:14 -040038{
Brad Bishop7b337772017-01-12 16:11:24 -050039 try
40 {
Brad Bishop49aefb32016-10-19 11:54:14 -040041 auto msg = sdbusplus::message::message(m);
Brad Bishop7b337772017-01-12 16:11:24 -050042 auto& args = *static_cast<Manager::SigArg*>(data);
Brad Bishop49aefb32016-10-19 11:54:14 -040043 sd_bus_message_ref(m);
Brad Bishop7b337772017-01-12 16:11:24 -050044 auto& mgr = *std::get<0>(args);
Brad Bishop48547a82017-01-19 15:12:50 -050045 mgr.handleEvent(
Brad Bishop7b337772017-01-12 16:11:24 -050046 msg,
Brad Bishop12f8a3c2017-02-09 00:02:00 -050047 static_cast<const DbusSignal&>(
Brad Bishop7b337772017-01-12 16:11:24 -050048 *std::get<1>(args)),
49 *std::get<2>(args));
Brad Bishop49aefb32016-10-19 11:54:14 -040050 }
Brad Bishop7b337772017-01-12 16:11:24 -050051 catch (const std::exception& e)
52 {
Brad Bishop49aefb32016-10-19 11:54:14 -040053 std::cerr << e.what() << std::endl;
54 }
55
56 return 0;
57}
58
Brad Bishop49aefb32016-10-19 11:54:14 -040059Manager::Manager(
Brad Bishop7b337772017-01-12 16:11:24 -050060 sdbusplus::bus::bus&& bus,
61 const char* busname,
62 const char* root,
63 const char* iface) :
Brad Bishop12f8a3c2017-02-09 00:02:00 -050064 ServerObject<ManagerIface>(bus, root),
Brad Bishop49aefb32016-10-19 11:54:14 -040065 _shutdown(false),
66 _root(root),
67 _bus(std::move(bus)),
Brad Bishop9b864832017-03-07 00:10:33 -050068 _manager(_bus, root)
Brad Bishop49aefb32016-10-19 11:54:14 -040069{
Brad Bishop7b337772017-01-12 16:11:24 -050070 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050071 {
Brad Bishop12f8a3c2017-02-09 00:02:00 -050072 for (auto pEvent : std::get<std::vector<EventBasePtr>>(
Brad Bishop48547a82017-01-19 15:12:50 -050073 group))
Brad Bishop68c80832016-11-29 16:41:32 -050074 {
75 if (pEvent->type !=
Brad Bishop12f8a3c2017-02-09 00:02:00 -050076 Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050077 {
Brad Bishop68c80832016-11-29 16:41:32 -050078 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050079 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050080
Brad Bishop68c80832016-11-29 16:41:32 -050081 // Create a callback context for this event group.
Brad Bishop12f8a3c2017-02-09 00:02:00 -050082 auto dbusEvent = static_cast<DbusSignal*>(
Brad Bishop7b337772017-01-12 16:11:24 -050083 pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050084
85 // Go ahead and store an iterator pointing at
86 // the event data to avoid lookups later since
87 // additional signal callbacks aren't added
88 // after the manager is constructed.
89 _sigargs.emplace_back(
Brad Bishop7b337772017-01-12 16:11:24 -050090 std::make_unique<SigArg>(
91 this,
92 dbusEvent,
93 &group));
Brad Bishop68c80832016-11-29 16:41:32 -050094
95 // Register our callback and the context for
96 // each signal event.
97 _matches.emplace_back(
Brad Bishop7b337772017-01-12 16:11:24 -050098 _bus,
Brad Bishop48547a82017-01-19 15:12:50 -050099 dbusEvent->signature,
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500100 _signal,
Brad Bishop7b337772017-01-12 16:11:24 -0500101 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -0500102 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400103 }
104
105 _bus.request_name(busname);
106}
107
108void Manager::shutdown() noexcept
109{
110 _shutdown = true;
111}
112
113void Manager::run() noexcept
114{
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500115 sdbusplus::message::message unusedMsg{nullptr};
116
117 // Run startup events.
118 for (auto& group : _events)
119 {
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500120 for (auto pEvent : std::get<std::vector<EventBasePtr>>(
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500121 group))
122 {
123 if (pEvent->type ==
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500124 Event::Type::STARTUP)
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500125 {
126 handleEvent(unusedMsg, *pEvent, group);
127 }
128 }
129 }
130
Brad Bishop7b337772017-01-12 16:11:24 -0500131 while (!_shutdown)
132 {
133 try
134 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400135 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500136 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400137 }
Brad Bishop7b337772017-01-12 16:11:24 -0500138 catch (const std::exception& e)
139 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400140 std::cerr << e.what() << std::endl;
141 }
142 }
143}
144
Brad Bishop79ccaf72017-01-22 16:00:50 -0500145void Manager::updateInterfaces(
146 const sdbusplus::message::object_path& path,
147 const Object& interfaces,
148 ObjectReferences::iterator pos,
149 bool newObject)
150{
151 auto& refaces = pos->second;
152 auto ifaceit = interfaces.cbegin();
153 auto opsit = _makers.cbegin();
154 auto refaceit = refaces.begin();
155 std::vector<std::string> signals;
156
157 while (ifaceit != interfaces.cend())
158 {
159 try
160 {
161 // Find the binding ops for this interface.
162 opsit = std::lower_bound(
163 opsit,
164 _makers.cend(),
165 ifaceit->first,
166 compareFirst(_makers.key_comp()));
167
168 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
169 {
170 // This interface is not supported.
171 throw InterfaceError(
172 "Encountered unsupported interface.",
173 ifaceit->first);
174 }
175
176 // Find the binding insertion point or the binding to update.
177 refaceit = std::lower_bound(
178 refaceit,
179 refaces.end(),
180 ifaceit->first,
181 compareFirst(refaces.key_comp()));
182
183 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
184 {
185 // Add the new interface.
186 auto& ctor = std::get<MakerType>(opsit->second);
187 refaceit = refaces.insert(
188 refaceit,
189 std::make_pair(
190 ifaceit->first,
191 ctor(
192 _bus,
193 path.str.c_str(),
194 ifaceit->second)));
195 signals.push_back(ifaceit->first);
196 }
197 else
198 {
199 // Set the new property values.
200 auto& assign = std::get<AssignerType>(opsit->second);
201 assign(ifaceit->second, refaceit->second);
202 }
203 }
204 catch (const InterfaceError& e)
205 {
206 // Reset the binding ops iterator since we are
207 // at the end.
208 opsit = _makers.cbegin();
209 e.log();
210 }
211
212 ++ifaceit;
213 }
214
215 if (newObject)
216 {
217 _bus.emit_object_added(path.str.c_str());
218 }
219 else if (!signals.empty())
220 {
221 // TODO: emit an interfaces added signal
222 }
223}
224
225void Manager::updateObjects(
226 const std::map<sdbusplus::message::object_path, Object>& objs)
227{
228 auto objit = objs.cbegin();
229 auto refit = _refs.begin();
230 std::string absPath;
231 bool newObj;
232
233 while (objit != objs.cend())
234 {
235 // Find the insertion point or the object to update.
236 refit = std::lower_bound(
237 refit,
238 _refs.end(),
239 objit->first,
240 compareFirst(RelPathCompare(_root)));
241
242 absPath.assign(_root);
243 absPath.append(objit->first);
244
245 newObj = false;
246 if (refit == _refs.end() || refit->first != absPath)
247 {
248 refit = _refs.insert(
249 refit,
250 std::make_pair(
251 absPath,
252 decltype(_refs)::mapped_type()));
253 newObj = true;
254 }
255
256 updateInterfaces(absPath, objit->second, refit, newObj);
257 ++objit;
258 }
259}
260
Brad Bishop03f4cd92017-02-03 15:17:21 -0500261void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400262{
Brad Bishopcda036f2017-02-15 10:06:48 -0500263 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400264}
265
Brad Bishop48547a82017-01-19 15:12:50 -0500266void Manager::handleEvent(
Brad Bishop7b337772017-01-12 16:11:24 -0500267 sdbusplus::message::message& msg,
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500268 const Event& event,
Brad Bishop7b337772017-01-12 16:11:24 -0500269 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400270{
Brad Bishop7b337772017-01-12 16:11:24 -0500271 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400272
Brad Bishop48547a82017-01-19 15:12:50 -0500273 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500274 {
Brad Bishop07934a62017-02-08 23:34:59 -0500275 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500276 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500277 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500278 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400279 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500280 for (auto& action : actions)
281 {
Brad Bishop07934a62017-02-08 23:34:59 -0500282 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500283 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400284}
285
Brad Bishop7b7e7122017-01-21 21:21:46 -0500286void Manager::destroyObjects(
287 const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400288{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500289 std::string p;
290
Brad Bishop7b7e7122017-01-21 21:21:46 -0500291 for (const auto& path : paths)
292 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500293 p.assign(_root);
294 p.append(path);
295 _bus.emit_object_removed(p.c_str());
296 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500297 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400298}
299
Brad Bishopeb68a682017-01-22 00:58:54 -0500300void Manager::createObjects(
301 const std::map<sdbusplus::message::object_path, Object>& objs)
302{
Brad Bishopcda036f2017-02-15 10:06:48 -0500303 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500304}
305
Brad Bishop150147a2017-02-08 23:57:46 -0500306any_ns::any& Manager::getInterfaceHolder(
Brad Bishop7b337772017-01-12 16:11:24 -0500307 const char* path, const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500308{
Brad Bishop150147a2017-02-08 23:57:46 -0500309 return const_cast<any_ns::any&>(
310 const_cast<const Manager*>(
311 this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500312}
313
Brad Bishop150147a2017-02-08 23:57:46 -0500314const any_ns::any& Manager::getInterfaceHolder(
Brad Bishop7b337772017-01-12 16:11:24 -0500315 const char* path, const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500316{
317 std::string p{path};
318 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500319 if (oit == _refs.end())
Brad Bishopb83a21e2016-11-30 13:43:37 -0500320 throw std::runtime_error(
Brad Bishop7b337772017-01-12 16:11:24 -0500321 _root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500322
Brad Bishop7b337772017-01-12 16:11:24 -0500323 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500324 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500325 if (iit == obj.end())
Brad Bishopb83a21e2016-11-30 13:43:37 -0500326 throw std::runtime_error(
Brad Bishop7b337772017-01-12 16:11:24 -0500327 "interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500328
Brad Bishop150147a2017-02-08 23:57:46 -0500329 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500330}
331
Brad Bishop49aefb32016-10-19 11:54:14 -0400332} // namespace manager
333} // namespace inventory
334} // namespace phosphor
335
336// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4