Initial commit

Signed-off-by: Artem Senichev <a.senichev@yadro.com>
diff --git a/src/dbus_watch.cpp b/src/dbus_watch.cpp
new file mode 100644
index 0000000..fa1bcb1
--- /dev/null
+++ b/src/dbus_watch.cpp
@@ -0,0 +1,165 @@
+/**
+ * @brief D-Bus signal watcher.
+ *
+ * This file is part of HostLogger project.
+ *
+ * Copyright (c) 2018 YADRO
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.hpp"
+#include "dbus_watch.hpp"
+#include <set>
+#include <string>
+#include <chrono>
+
+// D-Bus path to the host state object
+#define DBUS_HOST_OBJECT_PATH "/xyz/openbmc_project/state/host0"
+
+// Macro to normalize SDBus status code:
+// positive code is not an error in the systemd dbus implementation.
+#define DBUS_RC_TO_ERR(c) (c = (c <= 0 ? -c : 0))
+
+
+DbusWatcher::DbusWatcher(LogManager& logManager, sdbusplus::bus::bus& bus)
+: logManager_(logManager),
+  bus_(bus)
+{
+}
+
+
+int DbusWatcher::initialize()
+{
+    int rc;
+
+    // Add IO callback for host's log stream socket
+    rc = sd_event_add_io(bus_.get_event(), NULL,
+                         logManager_.getHostLogFd(),
+                         EPOLLIN, &DbusWatcher::ioCallback, this);
+    if (DBUS_RC_TO_ERR(rc)) {
+        fprintf(stderr, "Unable to add IO handler: %i %s\n",
+                        rc, strerror(rc));
+        return rc;
+    }
+
+    // Add flush handler
+    if (loggerConfig.flushPeriod == 0)
+        registerEventHandler();
+    else
+        rc = registerTimerHandler();
+
+    return rc;
+}
+
+
+void DbusWatcher::registerEventHandler()
+{
+    conds_["xyz.openbmc_project.State.Host"] = {
+        .property = "RequestedHostTransition",
+        .values = {
+            "xyz.openbmc_project.State.Host.Transition.On"
+        }
+    };
+    conds_["xyz.openbmc_project.State.OperatingSystem.Status"] = {
+        .property = "OperatingSystemState",
+        .values = {
+            "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.BootComplete",
+            "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"
+        }
+    };
+    for (auto& cond: conds_) {
+        cond.second.match = std::make_unique<sdbusplus::bus::match_t>(bus_,
+                            sdbusplus::bus::match::rules::propertiesChanged(
+                            DBUS_HOST_OBJECT_PATH, cond.first),
+                            [this](auto& msg){ this->hostStateHandler(msg); });
+    }
+}
+
+
+int DbusWatcher::registerTimerHandler()
+{
+    int rc;
+    sd_event_source* ev = NULL;
+
+    rc = sd_event_add_time(bus_.get_event(), &ev, CLOCK_MONOTONIC,
+                           UINT64_MAX, 0, &DbusWatcher::timerCallback, this);
+    if (DBUS_RC_TO_ERR(rc)) {
+        fprintf(stderr, "Unable to add timer handler: %i %s\n", rc, strerror(rc));
+        return rc;
+    }
+
+    rc = sd_event_source_set_enabled(ev, SD_EVENT_ON);
+    if (DBUS_RC_TO_ERR(rc)) {
+        fprintf(stderr, "Unable to enable timer handler: %i %s\n", rc, strerror(rc));
+        return rc;
+    }
+
+    return setupTimer(ev);
+}
+
+
+int DbusWatcher::setupTimer(sd_event_source* event)
+{
+    // Get the current time and add the delta (flush period)
+    using namespace std::chrono;
+    auto now = steady_clock::now().time_since_epoch();
+    hours timeOut(loggerConfig.flushPeriod);
+    auto expireTime = duration_cast<microseconds>(now) +
+                      duration_cast<microseconds>(timeOut);
+
+    //Set the time
+    int rc = sd_event_source_set_time(event, expireTime.count());
+    if (DBUS_RC_TO_ERR(rc))
+        fprintf(stderr, "Unable to set timer handler: %i %s\n", rc, strerror(rc));
+
+    return rc;
+}
+
+
+void DbusWatcher::hostStateHandler(sdbusplus::message::message& msg)
+{
+    std::map<std::string, sdbusplus::message::variant<std::string>> properties;
+    std::string interface;
+
+    msg.read(interface, properties);
+
+    bool needFlush = false;
+    const auto itc = conds_.find(interface);
+    if (itc != conds_.end()) {
+        const auto itp = properties.find(itc->second.property);
+        if (itp != properties.end()) {
+            const auto& propVal = itp->second.get<std::string>();
+            needFlush = itc->second.values.find(propVal) != itc->second.values.end();
+        }
+    }
+
+    if (needFlush)
+        logManager_.flush();
+}
+
+
+int DbusWatcher::ioCallback(sd_event_source* /*event*/, int /*fd*/, uint32_t /*revents*/, void* data)
+{
+    DbusWatcher* instance = static_cast<DbusWatcher*>(data);
+    instance->logManager_.handleHostLog();
+    return 0;
+}
+
+
+int DbusWatcher::timerCallback(sd_event_source* event, uint64_t /*usec*/, void* data)
+{
+    DbusWatcher* instance = static_cast<DbusWatcher*>(data);
+    instance->logManager_.flush();
+    return instance->setupTimer(event);
+}