blob: ca5118edf53e57d41433b625bc01eb004306e024 [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
21#include "config.hpp"
22#include "dbus_watch.hpp"
23#include <set>
24#include <string>
25#include <chrono>
26
27// D-Bus path to the host state object
28#define DBUS_HOST_OBJECT_PATH "/xyz/openbmc_project/state/host0"
29
30// Macro to normalize SDBus status code:
31// positive code is not an error in the systemd dbus implementation.
32#define DBUS_RC_TO_ERR(c) (c = (c <= 0 ? -c : 0))
33
34
35DbusWatcher::DbusWatcher(LogManager& logManager, sdbusplus::bus::bus& bus)
36: logManager_(logManager),
37 bus_(bus)
38{
39}
40
41
42int DbusWatcher::initialize()
43{
44 int rc;
45
46 // Add IO callback for host's log stream socket
47 rc = sd_event_add_io(bus_.get_event(), NULL,
48 logManager_.getHostLogFd(),
49 EPOLLIN, &DbusWatcher::ioCallback, this);
50 if (DBUS_RC_TO_ERR(rc)) {
51 fprintf(stderr, "Unable to add IO handler: %i %s\n",
52 rc, strerror(rc));
53 return rc;
54 }
55
56 // Add flush handler
57 if (loggerConfig.flushPeriod == 0)
58 registerEventHandler();
59 else
60 rc = registerTimerHandler();
61
62 return rc;
63}
64
65
66void DbusWatcher::registerEventHandler()
67{
68 conds_["xyz.openbmc_project.State.Host"] = {
69 .property = "RequestedHostTransition",
70 .values = {
71 "xyz.openbmc_project.State.Host.Transition.On"
72 }
73 };
74 conds_["xyz.openbmc_project.State.OperatingSystem.Status"] = {
75 .property = "OperatingSystemState",
76 .values = {
77 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.BootComplete",
78 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"
79 }
80 };
81 for (auto& cond: conds_) {
82 cond.second.match = std::make_unique<sdbusplus::bus::match_t>(bus_,
83 sdbusplus::bus::match::rules::propertiesChanged(
84 DBUS_HOST_OBJECT_PATH, cond.first),
85 [this](auto& msg){ this->hostStateHandler(msg); });
86 }
87}
88
89
90int DbusWatcher::registerTimerHandler()
91{
92 int rc;
93 sd_event_source* ev = NULL;
94
95 rc = sd_event_add_time(bus_.get_event(), &ev, CLOCK_MONOTONIC,
96 UINT64_MAX, 0, &DbusWatcher::timerCallback, this);
97 if (DBUS_RC_TO_ERR(rc)) {
98 fprintf(stderr, "Unable to add timer handler: %i %s\n", rc, strerror(rc));
99 return rc;
100 }
101
102 rc = sd_event_source_set_enabled(ev, SD_EVENT_ON);
103 if (DBUS_RC_TO_ERR(rc)) {
104 fprintf(stderr, "Unable to enable timer handler: %i %s\n", rc, strerror(rc));
105 return rc;
106 }
107
108 return setupTimer(ev);
109}
110
111
112int DbusWatcher::setupTimer(sd_event_source* event)
113{
114 // Get the current time and add the delta (flush period)
115 using namespace std::chrono;
116 auto now = steady_clock::now().time_since_epoch();
117 hours timeOut(loggerConfig.flushPeriod);
118 auto expireTime = duration_cast<microseconds>(now) +
119 duration_cast<microseconds>(timeOut);
120
121 //Set the time
122 int rc = sd_event_source_set_time(event, expireTime.count());
123 if (DBUS_RC_TO_ERR(rc))
124 fprintf(stderr, "Unable to set timer handler: %i %s\n", rc, strerror(rc));
125
126 return rc;
127}
128
129
130void DbusWatcher::hostStateHandler(sdbusplus::message::message& msg)
131{
132 std::map<std::string, sdbusplus::message::variant<std::string>> properties;
133 std::string interface;
134
135 msg.read(interface, properties);
136
137 bool needFlush = false;
138 const auto itc = conds_.find(interface);
139 if (itc != conds_.end()) {
140 const auto itp = properties.find(itc->second.property);
141 if (itp != properties.end()) {
William A. Kennington III432bdd62018-11-06 15:32:13 -0800142 const auto& propVal = sdbusplus::message::variant_ns::get<std::string>(itp->second);
Artem Senichevefd5d742018-10-24 16:14:04 +0300143 needFlush = itc->second.values.find(propVal) != itc->second.values.end();
144 }
145 }
146
147 if (needFlush)
148 logManager_.flush();
149}
150
151
152int DbusWatcher::ioCallback(sd_event_source* /*event*/, int /*fd*/, uint32_t /*revents*/, void* data)
153{
154 DbusWatcher* instance = static_cast<DbusWatcher*>(data);
155 instance->logManager_.handleHostLog();
156 return 0;
157}
158
159
160int DbusWatcher::timerCallback(sd_event_source* event, uint64_t /*usec*/, void* data)
161{
162 DbusWatcher* instance = static_cast<DbusWatcher*>(data);
163 instance->logManager_.flush();
164 return instance->setupTimer(event);
165}