#pragma once
-
#include <string>
#include <memory>
#include <map>
#include <vector>
+#include <osquery/notification.h>
+
namespace osquery {
using Row = std::map<std::string, std::string>;
using Rows = std::vector<Row>;
+using Callback = NotifyCallback;
+
+/// TBD: Consider error handling.
class OsqueryManager final {
public:
- OsqueryManager(const OsqueryManager&) = delete;
- OsqueryManager& operator=(const OsqueryManager&) = delete;
-
- /// TBD: Consider error handling.
+ /// Query Execution method
static Rows execute(const std::string& query);
+
+ /// Event Subscription method
+ static void subscribe(const std::string& table, const Callback& callback);
+
+ /// Table information
static std::vector<std::string> tables(void) noexcept;
static std::vector<std::string> columns(const std::string& table) noexcept;
+public:
+ OsqueryManager(const OsqueryManager&) = delete;
+ OsqueryManager& operator=(const OsqueryManager&) = delete;
+
private:
OsqueryManager();
~OsqueryManager() noexcept;
/// TODO(Sangwan): Apply pimpl idiom.
Rows executeInternal(const std::string& query) const;
+ void subscribeInternal(const std::string& table, const Callback& callback);
+
std::vector<std::string> tablesInternal(void) const noexcept;
std::vector<std::string> columnsInternal(const std::string& table) const noexcept;
};
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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
+ */
+
+
+/**
+ * @file notification.h
+ * @brief Notify to registered stuffs when event-callback called
+ */
+
+
+#pragma once
+
+#include <map>
+#include <vector>
+#include <functional>
+
+#include <osquery/database.h>
+#include <osquery/status.h>
+#include <osquery/registry.h>
+
+namespace osquery {
+
+using NotifyCallback = std::function<void(const Row&)>;
+
+class Notification final {
+public:
+ static Notification& instance();
+
+ Status add(const std::string& table, const NotifyCallback& callback);
+ Status emit(const std::string& table, const Row& result) const;
+
+public:
+ Notification(const Notification&) = delete;
+ Notification& operator=(const Notification&) = delete;
+
+private:
+ Notification() = default;
+ ~Notification() = default;
+
+ std::multimap<std::string, NotifyCallback> callbacks;
+};
+
+} // namespace osquery
# tizen feature
ADD_SUBDIRECTORY(manager)
+ADD_SUBDIRECTORY(notification)
## Table generation #############################################################
FILE(GLOB TABLE_FILES "tables/specs/*.table")
return results;
}
+void OsqueryManager::subscribe(const std::string& table, const Callback& callback)
+{
+ LOG(INFO) << "Subscribe event: " << table;
+
+ return instance().subscribeInternal(table, callback);
+}
+
+void OsqueryManager::subscribeInternal(const std::string& table, const Callback& callback)
+{
+ auto status = Notification::instance().add(table, callback);
+ if (!status.ok())
+ LOG(ERROR) << "Subscribing event failed: " << status.getCode();
+}
+
std::vector<std::string> OsqueryManager::tables(void) noexcept
{
return instance().tablesInternal();
#include <gtest/gtest.h>
+#include <osquery/notification.h>
#include <osquery/manager.h>
#include <osquery/logger.h>
VLOG(1) << "\t seconds: " << rows[0]["seconds"];
}
+TEST_F(ManagerTests, test_manager_subscribe) {
+ int called = 0;
+ auto callback = [&](const Row& row) {
+ VLOG(1) << "NotifyCallback called:";
+ for (const auto& r : row)
+ VLOG(1) << "\t" << r.first << " : " << r.second;
+ called++;
+ };
+
+ OsqueryManager::subscribe("manager_test", callback);
+
+ Row row;
+ row["foo"] = "bar";
+ row["foo2"] = "bar2";
+ row["foo3"] = "bar3";
+
+ /// Notification trigger
+ auto s = Notification::instance().emit("manager_test", row);
+
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(called, 1);
+}
+
TEST_F(ManagerTests, test_manager_tables) {
auto tables = OsqueryManager::tables();
EXPECT_TRUE(tables.size() > 0);
--- /dev/null
+# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# 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
+
+ADD_OSQUERY_LIBRARY(TRUE osquery_notification notification.cpp)
+
+ADD_OSQUERY_TEST(TRUE osquery_notification_tests notification_tests.cpp)
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <mutex>
+
+#include <osquery/notification.h>
+#include <osquery/logger.h>
+
+namespace {
+ std::mutex mutex;
+} // anonymous namespace
+
+namespace osquery {
+
+Notification& Notification::instance()
+{
+ static Notification notifier;
+ return notifier;
+}
+
+Status Notification::add(const std::string& table, const NotifyCallback& callback)
+{
+ if (table.empty())
+ return Status(1, "Wrong table name");
+
+ LOG(INFO) << "Add NotifyCallback to:" << table;
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ this->callbacks.insert(std::make_pair(table, callback));
+ }
+
+ return Status(0, "OK");
+}
+
+Status Notification::emit(const std::string& table, const Row& result) const
+{
+ if (table.empty())
+ return Status(1, "Wrong table name");
+
+ auto iter = this->callbacks.find(table);
+ if (iter == this->callbacks.end())
+ return Status(1, "Registered callback not found");
+
+ LOG(INFO) << "Emit notification about:" << table;
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ while (iter != this->callbacks.end()) {
+ const auto& callback = iter->second;
+ callback(result);
+ iter++;
+ }
+ }
+
+ return Status(0, "OK");
+}
+
+} // namespace osquery
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <gtest/gtest.h>
+
+#include <osquery/notification.h>
+#include <osquery/logger.h>
+
+using namespace osquery;
+
+class NotificationTests : public testing::Test {};
+
+TEST_F(NotificationTests, test_add_positive) {
+ auto& notifier = Notification::instance();
+
+ auto callback = [](const Row& row) {
+ VLOG(1) << "NotifyCallback called:";
+ for (const auto& r : row)
+ VLOG(1) << "\t" << r.first << " : " << r.second;
+ };
+
+ auto s = notifier.add("test", std::move(callback));
+ EXPECT_TRUE(s.ok());
+}
+
+TEST_F(NotificationTests, test_add_negative) {
+ auto& notifier = Notification::instance();
+
+ auto callback = [](const Row& row) {
+ VLOG(1) << "NotifyCallback called:";
+ for (const auto& r : row)
+ VLOG(1) << "\t" << r.first << " : " << r.second;
+ };
+
+ auto s = notifier.add("", std::move(callback));
+ EXPECT_FALSE(s.ok());
+}
+
+TEST_F(NotificationTests, test_emit_positive) {
+ auto& notifier = Notification::instance();
+
+ int called = 0;
+ auto callback = [&](const Row& row) {
+ VLOG(1) << "NotifyCallback called:";
+ for (const auto& r : row)
+ VLOG(1) << "\t" << r.first << " : " << r.second;
+ called++;
+ };
+
+ auto s = notifier.add("test2", std::move(callback));
+ EXPECT_TRUE(s.ok());
+
+ Row row;
+ row["foo"] = "bar";
+ s = notifier.emit("test2", row);
+
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(called, 1);
+}
+
+int main(int argc, char* argv[]) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}