blob: ed57b87df6ff8d59a92eb64fb3c2a043f5e8c11c [file] [log] [blame]
Artem Senichevefd5d742018-10-24 16:14:04 +03001/**
2 * @brief D-Bus signal watcher.
3 *
4 * This file is part of HostLogger project.
5 *
6 * Copyright (c) 2018 YADRO
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
Artem Senichevefd5d742018-10-24 16:14:04 +030021#include "dbus_watch.hpp"
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080022
23#include "config.hpp"
24
25#include <chrono>
Artem Senichevefd5d742018-10-24 16:14:04 +030026#include <set>
27#include <string>
Artem Senichevefd5d742018-10-24 16:14:04 +030028
29// D-Bus path to the host state object
30#define DBUS_HOST_OBJECT_PATH "/xyz/openbmc_project/state/host0"
31
32// Macro to normalize SDBus status code:
33// positive code is not an error in the systemd dbus implementation.
34#define DBUS_RC_TO_ERR(c) (c = (c <= 0 ? -c : 0))
35
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080036DbusWatcher::DbusWatcher(LogManager& logManager, sdbusplus::bus::bus& bus) :
37 logManager_(logManager), bus_(bus)
Artem Senichevefd5d742018-10-24 16:14:04 +030038{
39}
40
Artem Senichevefd5d742018-10-24 16:14:04 +030041int DbusWatcher::initialize()
42{
43 int rc;
44
45 // Add IO callback for host's log stream socket
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080046 rc = sd_event_add_io(bus_.get_event(), NULL, logManager_.getHostLogFd(),
Artem Senichevefd5d742018-10-24 16:14:04 +030047 EPOLLIN, &DbusWatcher::ioCallback, this);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080048 if (DBUS_RC_TO_ERR(rc))
49 {
50 fprintf(stderr, "Unable to add IO handler: %i %s\n", rc, strerror(rc));
Artem Senichevefd5d742018-10-24 16:14:04 +030051 return rc;
52 }
53
54 // Add flush handler
55 if (loggerConfig.flushPeriod == 0)
56 registerEventHandler();
57 else
58 rc = registerTimerHandler();
59
60 return rc;
61}
62
Artem Senichevefd5d742018-10-24 16:14:04 +030063void DbusWatcher::registerEventHandler()
64{
65 conds_["xyz.openbmc_project.State.Host"] = {
66 .property = "RequestedHostTransition",
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080067 .values = {"xyz.openbmc_project.State.Host.Transition.On"}};
Artem Senichevefd5d742018-10-24 16:14:04 +030068 conds_["xyz.openbmc_project.State.OperatingSystem.Status"] = {
69 .property = "OperatingSystemState",
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080070 .values = {"xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
71 "BootComplete",
72 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
73 "Inactive"}};
74 for (auto& cond : conds_)
75 {
76 cond.second.match = std::make_unique<sdbusplus::bus::match_t>(
77 bus_,
78 sdbusplus::bus::match::rules::propertiesChanged(
79 DBUS_HOST_OBJECT_PATH, cond.first),
80 [this](auto& msg) { this->hostStateHandler(msg); });
Artem Senichevefd5d742018-10-24 16:14:04 +030081 }
82}
83
Artem Senichevefd5d742018-10-24 16:14:04 +030084int DbusWatcher::registerTimerHandler()
85{
86 int rc;
87 sd_event_source* ev = NULL;
88
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080089 rc = sd_event_add_time(bus_.get_event(), &ev, CLOCK_MONOTONIC, UINT64_MAX,
90 0, &DbusWatcher::timerCallback, this);
91 if (DBUS_RC_TO_ERR(rc))
92 {
93 fprintf(stderr, "Unable to add timer handler: %i %s\n", rc,
94 strerror(rc));
Artem Senichevefd5d742018-10-24 16:14:04 +030095 return rc;
96 }
97
98 rc = sd_event_source_set_enabled(ev, SD_EVENT_ON);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -080099 if (DBUS_RC_TO_ERR(rc))
100 {
101 fprintf(stderr, "Unable to enable timer handler: %i %s\n", rc,
102 strerror(rc));
Artem Senichevefd5d742018-10-24 16:14:04 +0300103 return rc;
104 }
105
106 return setupTimer(ev);
107}
108
Artem Senichevefd5d742018-10-24 16:14:04 +0300109int DbusWatcher::setupTimer(sd_event_source* event)
110{
111 // Get the current time and add the delta (flush period)
112 using namespace std::chrono;
113 auto now = steady_clock::now().time_since_epoch();
114 hours timeOut(loggerConfig.flushPeriod);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800115 auto expireTime =
116 duration_cast<microseconds>(now) + duration_cast<microseconds>(timeOut);
Artem Senichevefd5d742018-10-24 16:14:04 +0300117
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800118 // Set the time
Artem Senichevefd5d742018-10-24 16:14:04 +0300119 int rc = sd_event_source_set_time(event, expireTime.count());
120 if (DBUS_RC_TO_ERR(rc))
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800121 fprintf(stderr, "Unable to set timer handler: %i %s\n", rc,
122 strerror(rc));
Artem Senichevefd5d742018-10-24 16:14:04 +0300123
124 return rc;
125}
126
Artem Senichevefd5d742018-10-24 16:14:04 +0300127void DbusWatcher::hostStateHandler(sdbusplus::message::message& msg)
128{
Patrick Williamsea316582020-05-13 17:56:03 -0500129 std::map<std::string, std::variant<std::string>> properties;
Artem Senichevefd5d742018-10-24 16:14:04 +0300130 std::string interface;
131
132 msg.read(interface, properties);
133
134 bool needFlush = false;
135 const auto itc = conds_.find(interface);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800136 if (itc != conds_.end())
137 {
Artem Senichevefd5d742018-10-24 16:14:04 +0300138 const auto itp = properties.find(itc->second.property);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800139 if (itp != properties.end())
140 {
Patrick Williamsea316582020-05-13 17:56:03 -0500141 const auto& propVal = std::get<std::string>(itp->second);
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800142 needFlush =
143 itc->second.values.find(propVal) != itc->second.values.end();
Artem Senichevefd5d742018-10-24 16:14:04 +0300144 }
145 }
146
147 if (needFlush)
148 logManager_.flush();
149}
150
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800151int DbusWatcher::ioCallback(sd_event_source* /*event*/, int /*fd*/,
152 uint32_t /*revents*/, void* data)
Artem Senichevefd5d742018-10-24 16:14:04 +0300153{
154 DbusWatcher* instance = static_cast<DbusWatcher*>(data);
155 instance->logManager_.handleHostLog();
156 return 0;
157}
158
Patrick Venture4d5a5dc2018-11-14 08:51:13 -0800159int DbusWatcher::timerCallback(sd_event_source* event, uint64_t /*usec*/,
160 void* data)
Artem Senichevefd5d742018-10-24 16:14:04 +0300161{
162 DbusWatcher* instance = static_cast<DbusWatcher*>(data);
163 instance->logManager_.flush();
164 return instance->setupTimer(event);
165}